digitalmars.D - Access violation using Win32 function pointer
- Lars Ivar Igesund (51/51) Jan 11 2005 I'm making a Win32 process wrapper at work using D. As I need to know of...
- Lionello Lunesu (19/19) Jan 11 2005 Hi..
- Lars Ivar Igesund (6/25) Jan 11 2005 Some good suggestions here (although I had no real success :); I'm able ...
- John Reimer (8/74) Jan 11 2005 Hello Lars,
- Lars Ivar Igesund (4/78) Jan 11 2005 Is that possible? How would that look (to get it to compile)? Anyway, I ...
- John Reimer (21/26) Jan 11 2005 Yes, it's possible. Just do:
- Lars Ivar Igesund (16/42) Jan 11 2005 Heh, you were right, thanks! Although it wasn't as simple as it sounds. ...
- John Reimer (36/54) Jan 11 2005 Yes, I didn't mention that, I guess. There are a few more details to ge...
- Lars Ivar Igesund (5/6) Jan 11 2005 I guess I figured out all this earlier today, just to discover that the
- John Reimer (2/11) Jan 11 2005 Ouch! That's got to be frustrating. :-(
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
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
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
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
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
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 IgesundYes, 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
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 IgesundYes, 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
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
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
On Tue, 11 Jan 2005 22:10:35 +0100, Lars Ivar Igesund wrote:John Reimer wrote:Ouch! That's got to be frustrating. :-(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