www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Access violation using Win32 function pointer

reply Lars Ivar Igesund <Lars_member pathlink.com> writes:
I'm making a Win32 process wrapper at work using D. As I need to know of all
child processes, I went for the functions

  HANDLE CreateToolhelp32Snapshot(
    DWORD dwFlags,
    DWORD th32ProcessId
  );

  BOOL Process32First(
    HANDLE hSnapshot,
    LPPROCESSENTRY32 lppe
  );

  BOOL Process32Next(
    HANDLE hSnapshot,
    LPPROCESSENTRY32 lppe
  );

As none of these were present in the lib files that comes with DMC, I used
std.loader to get a function pointer to these functions. The
CreateToolhelp32Snapshot function seems to work Ok, but the other two gives me
an access violation. AFAICS, there are several possibilities.

My definition of the function pointer could be off the mark. I've tried these
two versions for the Process32First:

BOOL function(HANDLE, LPPROCESSENTRY32) p32f;

and 

BOOL function(HANDLE, out PROCESSENTRY32) p32f;

I actually believe that both of these should work as long as the input is
correct, which brings me to the PROCESSENTRY32 struct. I'm not even close to
sure on how to translate it to D. MSDN reports it like this:

typedef struct tagPROCESSENTRY32 {
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID;
ULONG_PTR th32DefaultHeapID;
DWORD th32ModuleID;
DWORD cntThreads;
DWORD th32ParentProcessID;
LONG pcPriClassBase;
DWORD dwFlags;
TCHAR szExeFile[MAX_PATH];
} PROCESSENTRY32, 
*PPROCESSENTRY32;

Here are two possible culprits; The ULONG_PTR (which isn't defined in DMC's
win32 headers) and TCHAR (which is typedefed from WCHAR (What's the point?)).

The basetsd.h file (found by Google) has this line
typedef [public] unsigned __int3264 ULONG_PTR, *PULONG_PTR;

After these 'discoveries', my struct definition used ulong instead of ULONG_PTR
and wchar instead of TCHAR, without luck. After looking closer at DMC's
tlhelp32.h, I changed the ulong to DWORD and the wchar to char. No luck.

Any suggestions for where it's going wrong? Any ideas for what's the correct way
to translate the mentioned functions to function pointers and the PROCESSENTRY
struct? Must out/inout be used in conjunction with some obscure pointer form?
I'm running out of possible solutions, here.

Lars Ivar Igesund
Jan 11 2005
next sibling parent reply "Lionello Lunesu" <lionello.lunesu crystalinter.remove.com> writes:
Hi..

Not sure if this applies to the problem at hand, but for all functions that 
(even remotely) use strings, the Win32 API provides two versions: ANSI and 
UNICODE. The ansi (ascii) version of a specific function ends in A, the 
unicode version in W.

TCHAR is either defined as "char" or as "WORD" (or "unsigned short"). So if 
you plan on using simple ansi/ascii character set, you'll convert any 
"TCHAR" to D as "char" (*) and you'll call the function ending in A 
(Process32FirstA, don't know if it exists). If you use UNICODE, you'll port 
"TCHAR" to D as "wchar" (**) and call the W function (Process32FirstW).

As far as the PROCESSENTRY32 struct is concerned, I have a feeling Windows 
is using the first member, dwSize, to check whether it's dealing with char 
or WCHAR. In any case, if that size doesn't match, the function fails. You 
can create a small C program that dumps sizeof(PROCESSENTRY32) and check if 
it matches the sizeof in D.

L.

(*) "byte" would be better, since D will treat "char"-strings as UTF8, which 
they won't be coming from Win32.
(**) this one is OK (Win32 supports unicode surrogates) 
Jan 11 2005
parent Lars Ivar Igesund <Lars_member pathlink.com> writes:
Some good suggestions here (although I had no real success :); I'm able to get
pointers to the W versions, the A versions don't seem to exist. The minimal C
program found the same size for PROCESSENTRY32 as when I used byte (or char) in
D. Which means that at least on of my runs should have the correct size...

Lars Ivar Igesund

In article <cs02a4$fh6$1 digitaldaemon.com>, Lionello Lunesu says...
Hi..

Not sure if this applies to the problem at hand, but for all functions that 
(even remotely) use strings, the Win32 API provides two versions: ANSI and 
UNICODE. The ansi (ascii) version of a specific function ends in A, the 
unicode version in W.

TCHAR is either defined as "char" or as "WORD" (or "unsigned short"). So if 
you plan on using simple ansi/ascii character set, you'll convert any 
"TCHAR" to D as "char" (*) and you'll call the function ending in A 
(Process32FirstA, don't know if it exists). If you use UNICODE, you'll port 
"TCHAR" to D as "wchar" (**) and call the W function (Process32FirstW).

As far as the PROCESSENTRY32 struct is concerned, I have a feeling Windows 
is using the first member, dwSize, to check whether it's dealing with char 
or WCHAR. In any case, if that size doesn't match, the function fails. You 
can create a small C program that dumps sizeof(PROCESSENTRY32) and check if 
it matches the sizeof in D.

L.

(*) "byte" would be better, since D will treat "char"-strings as UTF8, which 
they won't be coming from Win32.
(**) this one is OK (Win32 supports unicode surrogates) 

Jan 11 2005
prev sibling parent reply John Reimer <brk_6502 yahoo.com> writes:
Hello Lars,

Have you tried prefixing your function pointer declarations with 
"extern(Windows)".  They probably need it to match the calling 
convention of the loaded winapi calls.

That might get rid of the access violation.

Later,

John

Lars Ivar Igesund wrote:
 I'm making a Win32 process wrapper at work using D. As I need to know of all
 child processes, I went for the functions
 
   HANDLE CreateToolhelp32Snapshot(
     DWORD dwFlags,
     DWORD th32ProcessId
   );
 
   BOOL Process32First(
     HANDLE hSnapshot,
     LPPROCESSENTRY32 lppe
   );
 
   BOOL Process32Next(
     HANDLE hSnapshot,
     LPPROCESSENTRY32 lppe
   );
 
 As none of these were present in the lib files that comes with DMC, I used
 std.loader to get a function pointer to these functions. The
 CreateToolhelp32Snapshot function seems to work Ok, but the other two gives me
 an access violation. AFAICS, there are several possibilities.
 
 My definition of the function pointer could be off the mark. I've tried these
 two versions for the Process32First:
 
 BOOL function(HANDLE, LPPROCESSENTRY32) p32f;
 
 and 
 
 BOOL function(HANDLE, out PROCESSENTRY32) p32f;
 
 I actually believe that both of these should work as long as the input is
 correct, which brings me to the PROCESSENTRY32 struct. I'm not even close to
 sure on how to translate it to D. MSDN reports it like this:
 
 typedef struct tagPROCESSENTRY32 {
 DWORD dwSize;
 DWORD cntUsage;
 DWORD th32ProcessID;
 ULONG_PTR th32DefaultHeapID;
 DWORD th32ModuleID;
 DWORD cntThreads;
 DWORD th32ParentProcessID;
 LONG pcPriClassBase;
 DWORD dwFlags;
 TCHAR szExeFile[MAX_PATH];
 } PROCESSENTRY32, 
 *PPROCESSENTRY32;
 
 Here are two possible culprits; The ULONG_PTR (which isn't defined in DMC's
 win32 headers) and TCHAR (which is typedefed from WCHAR (What's the point?)).
 
 The basetsd.h file (found by Google) has this line
 typedef [public] unsigned __int3264 ULONG_PTR, *PULONG_PTR;
 
 After these 'discoveries', my struct definition used ulong instead of ULONG_PTR
 and wchar instead of TCHAR, without luck. After looking closer at DMC's
 tlhelp32.h, I changed the ulong to DWORD and the wchar to char. No luck.
 
 Any suggestions for where it's going wrong? Any ideas for what's the correct
way
 to translate the mentioned functions to function pointers and the PROCESSENTRY
 struct? Must out/inout be used in conjunction with some obscure pointer form?
 I'm running out of possible solutions, here.
 
 Lars Ivar Igesund

Jan 11 2005
parent reply Lars Ivar Igesund <Lars_member pathlink.com> writes:
Is that possible? How would that look (to get it to compile)? Anyway, I don't
think that's the problem as CreateToolhelp works.

Lars Ivar Igesund

In article <cs04it$j5c$1 digitaldaemon.com>, John Reimer says...
Hello Lars,

Have you tried prefixing your function pointer declarations with 
"extern(Windows)".  They probably need it to match the calling 
convention of the loaded winapi calls.

That might get rid of the access violation.

Later,

John

Lars Ivar Igesund wrote:
 I'm making a Win32 process wrapper at work using D. As I need to know of all
 child processes, I went for the functions
 
   HANDLE CreateToolhelp32Snapshot(
     DWORD dwFlags,
     DWORD th32ProcessId
   );
 
   BOOL Process32First(
     HANDLE hSnapshot,
     LPPROCESSENTRY32 lppe
   );
 
   BOOL Process32Next(
     HANDLE hSnapshot,
     LPPROCESSENTRY32 lppe
   );
 
 As none of these were present in the lib files that comes with DMC, I used
 std.loader to get a function pointer to these functions. The
 CreateToolhelp32Snapshot function seems to work Ok, but the other two gives me
 an access violation. AFAICS, there are several possibilities.
 
 My definition of the function pointer could be off the mark. I've tried these
 two versions for the Process32First:
 
 BOOL function(HANDLE, LPPROCESSENTRY32) p32f;
 
 and 
 
 BOOL function(HANDLE, out PROCESSENTRY32) p32f;
 
 I actually believe that both of these should work as long as the input is
 correct, which brings me to the PROCESSENTRY32 struct. I'm not even close to
 sure on how to translate it to D. MSDN reports it like this:
 
 typedef struct tagPROCESSENTRY32 {
 DWORD dwSize;
 DWORD cntUsage;
 DWORD th32ProcessID;
 ULONG_PTR th32DefaultHeapID;
 DWORD th32ModuleID;
 DWORD cntThreads;
 DWORD th32ParentProcessID;
 LONG pcPriClassBase;
 DWORD dwFlags;
 TCHAR szExeFile[MAX_PATH];
 } PROCESSENTRY32, 
 *PPROCESSENTRY32;
 
 Here are two possible culprits; The ULONG_PTR (which isn't defined in DMC's
 win32 headers) and TCHAR (which is typedefed from WCHAR (What's the point?)).
 
 The basetsd.h file (found by Google) has this line
 typedef [public] unsigned __int3264 ULONG_PTR, *PULONG_PTR;
 
 After these 'discoveries', my struct definition used ulong instead of ULONG_PTR
 and wchar instead of TCHAR, without luck. After looking closer at DMC's
 tlhelp32.h, I changed the ulong to DWORD and the wchar to char. No luck.
 
 Any suggestions for where it's going wrong? Any ideas for what's the correct
way
 to translate the mentioned functions to function pointers and the PROCESSENTRY
 struct? Must out/inout be used in conjunction with some obscure pointer form?
 I'm running out of possible solutions, here.
 
 Lars Ivar Igesund


Jan 11 2005
parent reply John Reimer <brk_6502 yahoo.com> writes:
Lars Ivar Igesund wrote:
 Is that possible? How would that look (to get it to compile)? Anyway, I don't
 think that's the problem as CreateToolhelp works.
 
 Lars Ivar Igesund
 

Yes, it's possible. Just do: extern(Windows) BOOL function(HANDLE, LPPROCESSENTRY32) p32f; Then the function pointer will call the dll function with the proper winapi calling convention (when it's assigned). If you don't do that, p32f still can be assigned any type of function, but the calling conventions won't necessarily match leaving the possibility of an "access violation". Since it looks like your interfacing with the win32 API, I think you need to decorate your function pointers appropriatly. I'm just guessing that this is what is needed in this instance. Concerning CreateToolhelp working... sometimes even with incorrect calling conventions assigned /some/ functions will still be callable for various bizarre reasons. But then sudden death occurs with others. This may not be the problem here, but I was just wondering if perhaps it were. Mango ICU uses extern(C) decorated function pointers to set them up for appropriate DLL function assignment; they're not extern(Windows) in this case because they are not winapi calls, but it's the same idea. Anyway, this suggestion may be of no help, but I was just curious to know if it fixes the problem. Good luck, John
Jan 11 2005
parent reply Lars Ivar Igesund <Lars_member pathlink.com> writes:
Heh, you were right, thanks! Although it wasn't as simple as it sounds. It
doesn't seem like it's possible to cast a function pointer to the correct type
(including the extern (Windows) part). I got messages like this:

cannot implicitly convert expression ExeModule_GetSymbol(kernel,
"CreateToolhelp32Snapshot") of type void* to HANDLE(Windows *)(uint,uint)

As I wasn't able to find a cast statement that would compile, I looked at the
Mango code and ended up with something with far to many asterisks:

*(cast(void**)&p32n) = ExeModule_GetSymbol(kernel, "Process32Next");

If it is possible to simplify that, please tell me. I'm no fan of pointers
(hence D :).

Also, another but not surprising problem. I can't declare an extern (Windows)
function pointer from within main (or any other class, struct, function I
suppose). I understand the issue for normal functions (mangling and such), but
don't think this should apply for function pointers.

Lars Ivar Igesund

In article <cs076s$n6a$1 digitaldaemon.com>, John Reimer says...
Lars Ivar Igesund wrote:
 Is that possible? How would that look (to get it to compile)? Anyway, I don't
 think that's the problem as CreateToolhelp works.
 
 Lars Ivar Igesund
 

Yes, it's possible. Just do: extern(Windows) BOOL function(HANDLE, LPPROCESSENTRY32) p32f; Then the function pointer will call the dll function with the proper winapi calling convention (when it's assigned). If you don't do that, p32f still can be assigned any type of function, but the calling conventions won't necessarily match leaving the possibility of an "access violation". Since it looks like your interfacing with the win32 API, I think you need to decorate your function pointers appropriatly. I'm just guessing that this is what is needed in this instance. Concerning CreateToolhelp working... sometimes even with incorrect calling conventions assigned /some/ functions will still be callable for various bizarre reasons. But then sudden death occurs with others. This may not be the problem here, but I was just wondering if perhaps it were. Mango ICU uses extern(C) decorated function pointers to set them up for appropriate DLL function assignment; they're not extern(Windows) in this case because they are not winapi calls, but it's the same idea. Anyway, this suggestion may be of no help, but I was just curious to know if it fixes the problem. Good luck, John

Jan 11 2005
parent reply John Reimer <brk_6502 yahoo.com> writes:
On Tue, 11 Jan 2005 10:52:17 +0000, Lars Ivar Igesund wrote:

 Heh, you were right, thanks! Although it wasn't as simple as it sounds. It
 doesn't seem like it's possible to cast a function pointer to the correct type
 (including the extern (Windows) part). I got messages like this:
 
 cannot implicitly convert expression ExeModule_GetSymbol(kernel,
 "CreateToolhelp32Snapshot") of type void* to HANDLE(Windows *)(uint,uint)
 

Yes, I didn't mention that, I guess. There are a few more details to get it working properly. I just wasn't sure how far you had got in the process. D is quite strict with the type-checking, so as you found out, you can't just assign the return pointer type to the function pointer. You need to cast it.
 As I wasn't able to find a cast statement that would compile, I looked at the
 Mango code and ended up with something with far to many asterisks:
 
 *(cast(void**)&p32n) = ExeModule_GetSymbol(kernel, "Process32Next");
 

Mango ICU uses the double indirection because it has to in order to allow direct manipulation of a variable address submitted to the function call. This is not really necessary for the simple assignment needed in your example. In your example above, you should be able to simplify to something like this: cast(void*)p32n = ExeModule_GetSymbol(kernel, "Process32Next"); This is necessary because the winapi call knows nothing of the D function pointer type. You gotta love void* pointer for these moments!
 If it is possible to simplify that, please tell me. I'm no fan of pointers
 (hence D :).

Pointers can get confusing! I did a double-take myself when I first tried reading what Kris was doing in Mango ICU. Thankfully, in most situations, one doesn't need to fiddle with pointer types with D. That is, not until you start doing low level code or start interfacing with C and Windows API's.
 Also, another but not surprising problem. I can't declare an extern (Windows)
 function pointer from within main (or any other class, struct, function I
 suppose). I understand the issue for normal functions (mangling and such), but
 don't think this should apply for function pointers.

No... none of the extern's work inside a function. They seem to be strictly intended for global scope use. This was discussed in some detail in an earlier post. There is a way to "cheat", although the usefulness of this cheat is dubious. Use an alias in the global scope (that contains an extern) and then use the aliased type locally (within the function). I actually doubt this does anything so use at your own risk. extern(Windows) alias int function(int, int) FuncPointerType; void main() { FuncPointerType fp; } This was discussed in the bugs newsgroup under "Can't declare extern(C) in function body." Hope some of this helps a bit. Later, John
Jan 11 2005
parent reply Lars Ivar Igesund <larsivar igesund.net> writes:
John Reimer wrote:

 Hope some of this helps a bit.

I guess I figured out all this earlier today, just to discover that the problem I tried to solve with my program wasn't the problem (although I needed the program to find that out). Lars Ivar Igesund
Jan 11 2005
parent John Reimer <brk_6502 yahoo.com> writes:
On Tue, 11 Jan 2005 22:10:35 +0100, Lars Ivar Igesund wrote:

 John Reimer wrote:
 
 Hope some of this helps a bit.

I guess I figured out all this earlier today, just to discover that the problem I tried to solve with my program wasn't the problem (although I needed the program to find that out). Lars Ivar Igesund

Ouch! That's got to be frustrating. :-(
Jan 11 2005