2

in both python 3.4.3 and 2.7.9 when I try to call any function from kernel library.

from 32bit version of python on 64bit windows, an error message is printed:

from ctypes import *
path=create_string_buffer(256) 
rs=cdll.Kernel32.GetModuleFileNameA(0,path,256)
print (path)

the error is as following :

Traceback (most recent call last):
      File "test-ctypes.py", line 3, in <module>
      ValueError: Procedure called with not enough arguments (12 bytes missing) or wrong calling convention
Aladdin
  • 339
  • 1
  • 2
  • 15
  • possible duplicate of [Python ctypes and not enough arguments (4 bytes missing)](http://stackoverflow.com/questions/1458813/python-ctypes-and-not-enough-arguments-4-bytes-missing) – Kishor Pawar May 20 '15 at 07:36
  • even if I defined the function argtypes and restype the problem appears.. – Aladdin May 20 '15 at 07:49

1 Answers1

4

The exception message tells you the answer:

ValueError: Procedure called with not enough arguments (12 bytes missing) or wrong calling convention

The number of arguments is right, so it must be the other: You are using the wrong calling convention. The calling convention is the way the compiler maps the three arguments in C into a way to store the actual values in memory when calling the function (among a few other things). On the MSDN documentation for GetModuleFileA you find the following signature

DWORD WINAPI GetModuleFileName(
  _In_opt_ HMODULE hModule,
  _Out_    LPTSTR  lpFilename,
  _In_     DWORD   nSize
);

The WINAPI tells the compiler to use the stdcall calling convention. Your ctypes code uses cdll which on the other hand assumes cdecl calling convetion. The solution is simple: change cdll to windll:

from ctypes import *
path=create_string_buffer(256) 
rs=windll.Kernel32.GetModuleFileNameA(0,path,256)
print (path)

Compare with the ctypes documentation for accessing .dll's, where kernel32 is explicitely shown to use windll.

burnpanck
  • 1,955
  • 1
  • 12
  • 36
  • what I was really searching for is how to explicitly use specific callingcanvention – Aladdin May 20 '15 at 08:44
  • @user3406177, it's more idiomatic to use `None` when passing a `NULL` pointer value. Also, if you don't define its `restype` and `argtypes`, `GetModuleFileNameA` will not work properly on 64-bit Windows. Use the Windows types defined in `ctypes.wintypes`. Also, please use `kernel32 = WinDLL('kernel32')` if you're creating a library. – Eryk Sun May 20 '15 at 09:22