digitalmars.D - Windows API: Strange behaviour after calling GetModuleFileNameExA
- Tobias Wassermann (67/67) Nov 26 2007 Hi all,
- Regan Heath (2/2) Nov 26 2007 How have you declared processFileName? Perhaps "char[]
- Tobias Wassermann (3/5) Nov 26 2007 Yes, it is declared just before the for-loop as:
- Regan Heath (6/14) Nov 27 2007 The thought I had was that perhaps GetModuleFileNameExA was overwriting
- Tobias Wassermann (43/51) Nov 27 2007 Hi,
- Regan Heath (81/81) Nov 27 2007 This is totally whacky... using the code posted below I get the
- Tobias Wassermann (38/64) Nov 27 2007 Could be an implib problem - I ported the code to C and compiled with DM...
- Joel Lucsy (8/14) Nov 27 2007 Ah, I would tend to think that EnumProcesses and GetModuleFileNameExA
- Regan Heath (21/32) Nov 27 2007 I thought the same thing but couldn't get it to link with
- Joel Lucsy (8/24) Nov 27 2007 Actually, the WINAPI is what sets STDCALL. I believe the extern "C" is
- Tobias Wassermann (6/32) Nov 27 2007 The problem is:
- Carlos Santander (4/17) Nov 28 2007 You could use a .def file to alias _EnumProcesses@12 to EnumProcesses.
- Tobias Wassermann (1/17) Nov 28 2007
- Carlos Santander (4/24) Nov 29 2007 Check http://www.digitalmars.com/ctg/ctgDefFiles.html#exports
Hi all,
I have the following code, including some functions out of the psapi.dll
(generated a lib with implib /noi /system psapi.lib
C:\windows\system32\psapi.lib):
extern (Windows)
{
HANDLE OpenProcess(uint dwDesiredAccess, BOOL bInheritHandle, uint
dwProcessId);
BOOL CloseHandle(HANDLE hHandle);
}
extern (C)
{
BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned);
uint GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, LPTSTR fileName,
uint size);
}
void main(char[][] args) {
...
uint[256] processIds;
int ret = EnumProcesses(&processIds[0], processIds.length * uint.sizeof,
&byteCount);
...
for(uint i=0; i<processIds.length && i<byteCount/uint.sizeof; i++) {
uint pid = processIds[i];
HANDLE hProcess = OpenProcess(0x410 /* QueryInformation | VMRead */, false,
pid);
if(cast(int)hProcess>0)
CloseHandle(hProcess);
}
}
Running this code works fine. I'll get a list like:
...
But now I'll change the for-loop:
for(uint i=0; i<processIds.length && i<byteCount/uint.sizeof; i++)
{
uint pid = processIds[i];
HANDLE hProcess = OpenProcess(0x410 /* QueryInformation | VMRead */, false,
pid);
if(cast(int)hProcess>0)
{
processFileName.length = 300;
uint namelength = 0;
namelength = GetModuleFileNameExA(hProcess, cast(HMODULE)null,
processFileName.ptr, processFileName.length);
CloseHandle(hProcess);
}
}
With the call of GetModuleFileNameExA() my process id list will be corrupted,
I'll get something like this:
id doesn't exist, the next real id is 1288.
I don't know why this happens, looking to the MSDN it gives me the following
function header:
DWORD GetModuleFileNameEx(
HANDLE hProcess,
HMODULE hModule,
LPTSTR lpFilename,
DWORD nSize
);
So I think, my declaration within D should be correct:
uint GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, LPTSTR fileName,
uint size);
Do anybody have any suggestions?
Thanks,
Tobias
Nov 26 2007
How have you declared processFileName? Perhaps "char[] processFileName;"? Is it declared in main right next to processIds?
Nov 26 2007
Regan Heath Wrote:How have you declared processFileName? Perhaps "char[] processFileName;"? Is it declared in main right next to processIds?Yes, it is declared just before the for-loop as: char[] processFileName;
Nov 26 2007
Tobias Wassermann wrote:Regan Heath Wrote:The thought I had was that perhaps GetModuleFileNameExA was overwriting the wrong memory and corrupting the process list. Can you post a complete working piece of code which exhibits the bug, I'd like to help by debugging it locally. ReganHow have you declared processFileName? Perhaps "char[] processFileName;"? Is it declared in main right next to processIds?Yes, it is declared just before the for-loop as: char[] processFileName;
Nov 27 2007
Hi,
here is the code:
import std.stdio;
import std.c.windows.windows;
extern (Windows) HANDLE OpenProcess(uint dwDesiredAccess, BOOL bInheritHandle,
uint dwProcessId);
extern (C)
{
BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned);
DWORD GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, char* fileName,
uint size);
}
void main(char[][] args)
{
uint[256] processIds;
uint byteCount;
char[] processFileName;
int ret = EnumProcesses(processIds.ptr, processIds.length*uint.sizeof,
&byteCount);
if(ret!=0)
{
for(uint i=0; i<processIds.length && i<byteCount/uint.sizeof; i++)
{
if(processIds[i]==0)
continue;
uint pid = processIds[i];
HANDLE hProcess = OpenProcess(0x410 /* QueryInformation | VMRead */,
false, pid);
if(cast(int)hProcess>0)
{
processFileName.length = 300;
uint namelength = 0;
namelength = GetModuleFileNameExA(hProcess, cast(HMODULE)0,
processFileName.ptr, processFileName.length);
processFileName.length = namelength;
writefln("=> %s", processFileName);
CloseHandle(hProcess);
}
}
}
}
If you comment out the namelength = GetModuleFileNameExA(hProcess,
cast(HMODULE)0, processFileName.ptr, processFileName.length); line, all works
fine.
I also tried a char* allocated memory block with malloc() instead of the
processFileName.ptr - so I thought about a bug between the communication
between D and the Windows API, but the result is the same: a corrupted uint[]
process-id-array.
Bye
Tobias
Regan Heath Wrote:
The thought I had was that perhaps GetModuleFileNameExA was overwriting
the wrong memory and corrupting the process list.
Can you post a complete working piece of code which exhibits the bug,
I'd like to help by debugging it locally.
Regan
Nov 27 2007
This is totally whacky... using the code posted below I get the
following output:
a 4
b 2000
c
d
e 883C00 300
f 883C00 300
g 883C00 300
h 884FF0 4296896
The output for both g and h are written with:
writefln("h %p %d", processFileName.ptr, processFileName.length);
The line between the two which causes this behaviour is
processFileName = "Unknown".dup;
PID of 4 is of course "System".
Removing the call to GetModuleFileNameExA prevents the problem.
My guess is that GetModuleFileNameExA is corrupting the stack somehow,
perhaps the implib didn't correctly convert the dll to a lib. I used:
implib /noi /system psapi.lib C:\windows\system32\psapi.dll
The full code:
import std.stdio;
import std.c.windows.windows;
extern (Windows) HANDLE OpenProcess(uint dwDesiredAccess, BOOL
bInheritHandle, uint dwProcessId);
extern (C)
{
BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned);
DWORD GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, char*
fileName, uint size);
}
void main(char[][] args)
{
char[] processFileName;
uint[] processIds;
uint[] processIds2;
uint byteCount;
processIds.length = 256;
int ret = EnumProcesses(processIds.ptr,
processIds.length*uint.sizeof, &byteCount);
if(ret!=0)
{
processIds.length = byteCount/uint.sizeof;
processIds2 = processIds.dup;
foreach(i, pid; processIds)
{
if(pid==0) continue;
writefln("a %d", pid);
HANDLE hProcess = OpenProcess(0x410 /* QueryInformation | VMRead
*/, false, pid);
writefln("b %d", cast(int)hProcess);
if(cast(int)hProcess>0)
{
writefln("c");
processFileName.length = 300;
writefln("d");
uint namelength = 0;
writefln("e %p %d", processFileName.ptr,
processFileName.length);
namelength = GetModuleFileNameExA(hProcess, cast(HMODULE)0,
processFileName.ptr, processFileName.length);
writefln("f %p %d", processFileName.ptr,
processFileName.length);
if (namelength == 0)
{
writefln("g %p %d", processFileName.ptr, processFileName.length);
processFileName = "Unknown".dup;
writefln("h %p %d", processFileName.ptr, processFileName.length);
}
else
{
writefln("i");
processFileName.length = namelength;
writefln("j");
}
break;
writefln("%d. (%d) => %s", i, pid, processFileName);
CloseHandle(hProcess);
}
}
}
}
Nov 27 2007
Could be an implib problem - I ported the code to C and compiled with DMC, the
same thing.
Used C-Code:
#include <stdio.h>
#include <windows.h>
HANDLE OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD
dwProcessId);
CloseHandle(HANDLE hHandle);
BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned);
DWORD GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, char* fileName,
DWORD size);
void main()
{
unsigned long processIds[256];
unsigned long byteCount;
char processFileName[300];
int ret = EnumProcesses(&processIds[0], 256*sizeof(unsigned long),
&byteCount);
if(ret!=0)
{
for(DWORD i=0; i<256 && i<byteCount/sizeof(unsigned long); i++)
{
if(processIds[i]==0)
continue;
unsigned int pid = processIds[i];
HANDLE hProcess = OpenProcess(0x410, FALSE, pid);
if((int)hProcess>0)
{
unsigned int namelength = GetModuleFileNameExA(hProcess, NULL,
&processFileName[0], 300);
printf("=> %s\r\n", processFileName);
CloseHandle(hProcess);
}
}
}
}
Compiled with:
dmc -L/+psapi/noi ProcessFinderTest.c
Uncomment the GetModuleFileNameExA-Call and all works fine - otherthise the
array will be corrupted.
Regan Heath Wrote:
This is totally whacky... using the code posted below I get the
following output:
a 4
b 2000
c
d
e 883C00 300
f 883C00 300
g 883C00 300
h 884FF0 4296896
The output for both g and h are written with:
writefln("h %p %d", processFileName.ptr, processFileName.length);
The line between the two which causes this behaviour is
processFileName = "Unknown".dup;
PID of 4 is of course "System".
Removing the call to GetModuleFileNameExA prevents the problem.
My guess is that GetModuleFileNameExA is corrupting the stack somehow,
perhaps the implib didn't correctly convert the dll to a lib. I used:
implib /noi /system psapi.lib C:\windows\system32\psapi.dll
Nov 27 2007
Tobias Wassermann wrote:
extern (Windows) HANDLE OpenProcess(uint dwDesiredAccess, BOOL bInheritHandle,
uint dwProcessId);
extern (C)
{
BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned);
DWORD GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, char* fileName,
uint size);
}
Ah, I would tend to think that EnumProcesses and GetModuleFileNameExA
should be extern(Windows) as well. All Win32 api's use STDCALL, which is
what I believe extern(Windows) sets.
--
Joel Lucsy
"The dinosaurs became extinct because they didn't have a space program."
-- Larry Niven
Nov 27 2007
Joel Lucsy wrote:Tobias Wassermann wrote:I thought the same thing but couldn't get it to link with extern(Windows) on those two. I've just looked at the psapi.h header in my SDK I see: #ifdef __cplusplus extern "C" { #endif BOOL WINAPI EnumProcesses( DWORD * lpidProcess, DWORD cb, DWORD * cbNeeded ); note the extern "C" there. I believe that confirms it's C linkage and not Windows linkage. Thanks for the suggestion though :) It seems the same problem occurs when Tobias calls the routines from C which suggests a problem with the implib used to convert the dll into a library. Reganextern (Windows) HANDLE OpenProcess(uint dwDesiredAccess, BOOL bInheritHandle, uint dwProcessId); extern (C) { BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned); DWORD GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, char* fileName, uint size); }Ah, I would tend to think that EnumProcesses and GetModuleFileNameExA should be extern(Windows) as well. All Win32 api's use STDCALL, which is what I believe extern(Windows) sets.
Nov 27 2007
Regan Heath wrote:I've just looked at the psapi.h header in my SDK I see: #ifdef __cplusplus extern "C" { #endif BOOL WINAPI EnumProcesses( DWORD * lpidProcess, DWORD cb, DWORD * cbNeeded ); note the extern "C" there. I believe that confirms it's C linkage and not Windows linkage.Actually, the WINAPI is what sets STDCALL. I believe the extern "C" is for telling the compiler how to mangle, or not mangle in this case, the name of the function. -- Joel Lucsy "The dinosaurs became extinct because they didn't have a space program." -- Larry Niven
Nov 27 2007
The problem is: EnumProcesses() and GetModuleFileNameExA() both are marked as extern "C" within the psapi.h - the difference is: EnumProcesses works and GetModuleFileNameExA() in D and with DMC seems to corrupt the stack. If I move the C-ported code to the Microsoft Visual C++ and compile it, it works fine. On the other side: extern (C) within D is the only possibility to use for this two functions, if I use extern (Windows) I'll get linker errors (linker can not find symbols _EnumProcesses 12 and _GetModuleFileNameExA 16). With extern (Windows) it seems to be correct - remember: EnumProcesses() works fine, only GetModuleFileNameExA() causes the problem. Additional note: GetProcessImageFileNameA() (which could be an alternative to GetModuleFileNameExA()) causes the same problem. Joel Lucsy Wrote:Regan Heath wrote:I've just looked at the psapi.h header in my SDK I see: #ifdef __cplusplus extern "C" { #endif BOOL WINAPI EnumProcesses( DWORD * lpidProcess, DWORD cb, DWORD * cbNeeded ); note the extern "C" there. I believe that confirms it's C linkage and not Windows linkage.Actually, the WINAPI is what sets STDCALL. I believe the extern "C" is for telling the compiler how to mangle, or not mangle in this case, the name of the function. -- Joel Lucsy "The dinosaurs became extinct because they didn't have a space program." -- Larry Niven
Nov 27 2007
Tobias Wassermann escribió:The problem is: EnumProcesses() and GetModuleFileNameExA() both are marked as extern "C" within the psapi.h - the difference is: EnumProcesses works and GetModuleFileNameExA() in D and with DMC seems to corrupt the stack. If I move the C-ported code to the Microsoft Visual C++ and compile it, it works fine. On the other side: extern (C) within D is the only possibility to use for this two functions, if I use extern (Windows) I'll get linker errors (linker can not find symbols _EnumProcesses 12 and _GetModuleFileNameExA 16). With extern (Windows) it seems to be correct - remember: EnumProcesses() works fine, only GetModuleFileNameExA() causes the problem. Additional note: GetProcessImageFileNameA() (which could be an alternative to GetModuleFileNameExA()) causes the same problem.You could use a .def file to alias _EnumProcesses 12 to EnumProcesses. -- Carlos Santander Bernal
Nov 28 2007
How could this be done? I never made an alias via a def-file before ;)> On the other side: extern (C) within D is the only possibility to use for > this two functions, if I use extern (Windows) I'll get linker errors (linker > can not find symbols _EnumProcesses 12 and _GetModuleFileNameExA 16). > > With extern (Windows) it seems to be correct - remember: EnumProcesses() > works fine, only GetModuleFileNameExA() causes the problem. > > Additional note: GetProcessImageFileNameA() (which could be an alternative to > GetModuleFileNameExA()) causes the same problem. > You could use a .def file to alias _EnumProcesses 12 to EnumProcesses.
Nov 28 2007
Tobias Wassermann escribió:How could this be done? I never made an alias via a def-file before ;)Check http://www.digitalmars.com/ctg/ctgDefFiles.html#exports -- Carlos Santander Bernal> On the other side: extern (C) within D is the only possibility to use for > this two functions, if I use extern (Windows) I'll get linker errors (linker > can not find symbols _EnumProcesses 12 and _GetModuleFileNameExA 16). > > With extern (Windows) it seems to be correct - remember: EnumProcesses() > works fine, only GetModuleFileNameExA() causes the problem. > > Additional note: GetProcessImageFileNameA() (which could be an alternative to > GetModuleFileNameExA()) causes the same problem. > You could use a .def file to alias _EnumProcesses 12 to EnumProcesses.
Nov 29 2007









Regan Heath <regan netmail.co.nz> 