1. Generate a lib with implib: implib /noi /system psapi.lib C:\windows\system32\psapi.lib
2. Compile the following code with dmd ProcessFinder.d -L+psapi/noi
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);
DWORD GetProcessImageFileNameA(HANDLE hProcess, LPSTR lpImageFileName, DWORD nSize);
}
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];
writefln("Process #%d - PID: %d", i, pid);
HANDLE hProcess = OpenProcess(0x410 /* QueryInformation | VMRead */, false, pid);
if(cast(int)hProcess>0)
{
processFileName.length = 300;
uint namelength = 0;
//namelength = GetProcessImageFileNameA(hProcess, processFileName.ptr, processFileName.length);
namelength = GetModuleFileNameExA(hProcess, cast(HMODULE)0, processFileName.ptr, processFileName.length);
processFileName.length = namelength;
writefln("=> %s", processFileName);
CloseHandle(hProcess);
}
}
}
}
So what will happen? With commented out GetModuleFileNameExA()-call you will get a list of correct process id's:
Process #1 - PID: 4
Process #2 - PID: 780
Process #3 - PID: 836
If you use GetModuleFileNameExA() the list will be incorrect:
Process #1 - PID: 4
Process #2 - PID: 780
Process #3 - PID: 836
Process #4 - PID: 4298544
Process #6 - PID: 1244976
Process #7 - PID: 4202711
Process #8 - PID: 1040
Process #9 - PID: 1288
Process #10 - PID: 1332
Process #4 to Process #8: These are invalid process id's - processes with these id doesn't exist, the next real id is 1288.
3. After calling GetModuleFileNameExA() the stack will be corrupted, the processIds-Array will be incorrect, if you comment out this call, all works fine. The same behaviour if you call GetProcessImageFileNameA()
Strange thing: If you port the code to C and compile against DMC - same problem! If you compile it with Microsoft Visual C++, you can also use GetModuleFileNameExA() and GetProcessImageFileNameA() without any problems. Seems to be an implib-issue?
See also the "Windows API: Strange behaviour after calling GetModuleFileNameExA" entries within the digitalmars.D-newsgroup
Comment #1 by bugzilla — 2007-12-30T00:55:22Z
The problem is declaring Windows API functions as being extern(C). They should be extern(Windows). Stack corruption is the result of incorrectly declaring what function calling convention to use.
Comment #2 by verylonglogin.reg — 2012-10-21T03:58:05Z
(In reply to comment #1)
> The problem is declaring Windows API functions as being extern(C). They should
> be extern(Windows). Stack corruption is the result of incorrectly declaring
> what function calling convention to use.
Looks like Walter like spending people time. As "extern(Windows)" and "extern(C)" functions has different symbol names the fact that the program links, runs and corrupts the stack just shows that `implib` generates incorrect *.lib files.
Incorrect behavior example (DLL):
implib /noi /system psapi-from-dll.lib %windir%\system32\psapi.dll
---
pragma(lib, "psapi-from-dll.lib");
extern(C) nothrow extern void EnumProcesses(); // links fine
void main()
{
auto p = &EnumProcesses;
}
---
More than that 'implib' works incorrect with '.def' files too.
Incorrect behavior example (DEF):
psapi.def (from mingw except library name is "PSAPI" instead of "PSAPI.DLL" because 'implib' stops on dot with error):
---
LIBRARY PSAPI
EXPORTS
EnumProcesses@12
---
implib /noi /system psapi-from-def.lib psapi.def
---
pragma(lib, "psapi-from-def.lib");
// Error 42: Symbol Undefined _EnumProcesses
// or _EnumProcesses@12 for extern(Windows)
extern(C) nothrow extern void EnumProcesses(int, int, int);
void main()
{
auto p = &EnumProcesses;
}
---
The second issue is because 'implib' ignores '/system' switch for *.def files:
implib /noi psapi-from-def-no-system.lib psapi.def
produces exactly same *.lib file.
The second issue has trivial workaround: one should prefix all symbols in *.def file with '_' by hands. E.g. such *.def file finally forces 'implib' to produce a correct *.lib:
---
LIBRARY PSAPI
EXPORTS
_EnumProcesses@12
---
Comment #3 by verylonglogin.reg — 2012-10-21T04:03:45Z
Damn, sorry. This is the correct DEF file for 'implib':
---
LIBRARY PSAPI
EXPORTS
_EnumProcesses@12=EnumProcesses
---
(or the program will link but fail to run trying to search for '_EnumProcesses@12' symbol in psapi.dll)
Comment #4 by bugzilla — 2013-04-07T01:23:20Z
All /system does is prepend a _. See:
http://www.digitalmars.com/ctg/implib.html
The trouble is that the names in Windows systems DLLs use the extern (Windows) calling convention, but they don't use the extern (Windows) mangled names. The Windows mangled names have the @nn suffix.
The names happen to match up with the C names, but the stack treatment is different, hence the crash.
There is nothing implib can do about this situation. The only thing you, as a user, can do is create a correct module definition file in order to map the internal and external names. Implib can't do that, as it doesn't have the information to do it.