Recent

Author Topic: [Solved] QueryFullProcessImageName API Function - can it be used in Lazarus?  (Read 18955 times)

TyneBridges

  • Full Member
  • ***
  • Posts: 127
    • Personal blog
I've been unable to find a Windows API declaration in Lazarus (my search included Jedi) for QueryFullProcessImageName. Following a suggestion from another forum user, I've created the following code with my own header. I'm guessing I've got something wrong as the final parameter seems to be extremely problematic. This is a pointer to a DWord, which should be compatible with the type Cardinal. My problem is that I can't assign a value to it. It doesn't seem to make any difference whether I declare STR_SIZE as Cardinal or DWORD. The code below gives the compiler error "Can't assign values to an address" on the line
Code: [Select]
GotName:= QueryFullProcessImageName... If I omit the @ from @STR_SIZE, the compiler reports that the parameter type is wrong ("Got LongWord, expected LPDWORD").

Code: [Select]
function QueryFullProcessImageName(hProcess: HANDLE; dwFlags: DWORD; var lpExeName: LPTSTR;
var lpdwSize: LPDWORD): BOOL; stdcall; external 'KERNEL32.dll'; 

...

  function FindInProcesses(const PName: String): DWord;
  const ListSize = 1024;
  var
     PIDList: array[1..Listsize] of DWORD;
     cbNeeded, cbProcesses: DWORD;
     I: integer;
     hProcess: HWND;
     hMod: HMODULE;
     CurrentProcName: PChar;
     GotName: Boolean;
     STR_SIZE: DWORD;
  begin
       // Enumerate all processes on the system
       EnumProcesses(@PIDList, ListSize, cbNeeded);
       cbProcesses:= cbNeeded div SizeOf(DWORD);
       Writeln('cbProcesses is ' + IntToStr(cbProcesses));
       Result:= 0;
       for i:= 1 to cbProcesses do
       begin
            Write('Process ID ' + IntToStr(PIDList[i]) + ' is ');
            hProcess:= OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, FALSE, PIDList[i]);
            EnumProcessModules(hProcess, @hMod, SizeOf(hMod), cbNeeded);
            GetMem(CurrentProcName, 512);
            STR_SIZE:= 512;
            GotName:= QueryFullProcessImageName(hProcess, 0, CurrentProcName, @STR_SIZE);
            If CurrentProcName = '' then
               Writeln('Failed to get a process name')
            else
               Writeln(Trim(CurrentProcName) + '. ');
            CloseHandle(hProcess);
            If UpperCase(CurrentProcName) = UpperCase(PName) then
            { Found the name. Set Result to the PID of process found }
                 Result:= PIDList[i];
            FreeMem(CurrentProcName, 512);
       end; // For
  end; // FindInProcesses

Any ideas?
« Last Edit: March 29, 2013, 06:34:13 pm by JohnSaltwell »
John H, north east England
Lover of the old Delphi, still inexperienced with FPC/Lazarus and not an instinctive programmer
Tried .Net Core and was perpetually in knots, so am back here to try again with Windows clients

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8728
  • FPC developer.
Re: QueryFullProcessImageName API Function - can it be used in Lazarus?
« Reply #1 on: March 27, 2013, 08:24:07 pm »
It's either  "var dwsize:dword"  or "lpdwsize:lpdword"

In the second case you need to pass @<something of dword> in the first just <something of type dword>


Not all Vista and later calls have been added.

TyneBridges

  • Full Member
  • ***
  • Posts: 127
    • Personal blog
Re: QueryFullProcessImageName API Function - can it be used in Lazarus?
« Reply #2 on: March 27, 2013, 09:02:06 pm »
It's either  "var dwsize:dword"  or "lpdwsize:lpdword"

In the second case you need to pass @<something of dword> in the first just <something of type dword>

Sorry, I still don't follow. I thought I was already doing as you suggest in the second case - using the declaration "lpdwsize: lpdword" and passing @STR_SIZE, but I then got the error I describe.
« Last Edit: March 27, 2013, 09:11:51 pm by JohnSaltwell »
John H, north east England
Lover of the old Delphi, still inexperienced with FPC/Lazarus and not an instinctive programmer
Tried .Net Core and was perpetually in knots, so am back here to try again with Windows clients

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8728
  • FPC developer.
Re: QueryFullProcessImageName API Function - can it be used in Lazarus?
« Reply #3 on: March 27, 2013, 09:38:58 pm »
It's either  "var dwsize:dword"  or "lpdwsize:lpdword"

In the second case you need to pass @<something of dword> in the first just <something of type dword>

Sorry, I still don't follow. I thought I was already doing as you suggest in the second case - using the declaration "lpdwsize: lpdword" and passing @STR_SIZE, but I then got the error I describe.
[/quot

With this declaration:

Code: [Select]
function QueryFullProcessImageName(hProcess: HANDLE; dwFlags: DWORD; var lpExeName: LPTSTR;
lpdwSize: LPDWORD): BOOL; stdcall; external 'KERNEL32.dll'; 

?

TyneBridges

  • Full Member
  • ***
  • Posts: 127
    • Personal blog
Re: QueryFullProcessImageName API Function - can it be used in Lazarus?
« Reply #4 on: March 28, 2013, 12:09:24 pm »
My mistake - I missed the fact that I'd included "var" when I shouldn't have. Tried again and, this time, the program compiled, but then gave an error on the function call - so I guess there is still something wrong with my header.

Code: [Select]
The procedure entry point QueryFullProcessImageName could not be located in the dynamic link library KERNEL32.dll.
« Last Edit: March 28, 2013, 10:10:15 pm by JohnSaltwell »
John H, north east England
Lover of the old Delphi, still inexperienced with FPC/Lazarus and not an instinctive programmer
Tried .Net Core and was perpetually in knots, so am back here to try again with Windows clients

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8728
  • FPC developer.
Re: QueryFullProcessImageName API Function - can it be used in Lazarus?
« Reply #5 on: March 28, 2013, 10:31:22 pm »
My mistake - I missed the fact that I'd included "var" when I shouldn't have. Tried again and, this time, the program compiled, but then gave an error on the function call - so I guess there is still something wrong with my header.

Code: [Select]
The procedure entry point QueryFullProcessImageName could not be located in the dynamic link library KERNEL32.dll.

You are using Vista or later? As said, it is is a Vista+ call.

TyneBridges

  • Full Member
  • ***
  • Posts: 127
    • Personal blog
Re: QueryFullProcessImageName API Function - can it be used in Lazarus?
« Reply #6 on: March 29, 2013, 08:30:25 am »
You are using Vista or later? As said, it is is a Vista+ call.

Yes, my OS is Windows 7 SP1 and the program is intended only to work on Windows 7.
John H, north east England
Lover of the old Delphi, still inexperienced with FPC/Lazarus and not an instinctive programmer
Tried .Net Core and was perpetually in knots, so am back here to try again with Windows clients

Leledumbo

  • Hero Member
  • *****
  • Posts: 8266
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: QueryFullProcessImageName API Function - can it be used in Lazarus?
« Reply #7 on: March 29, 2013, 09:23:19 am »
As usual, Windows has A and W variant of its API, including this function. You should map the name to one of the variant, because they are what really exists in the kernel32 library.

TyneBridges

  • Full Member
  • ***
  • Posts: 127
    • Personal blog
Re: QueryFullProcessImageName API Function - can it be used in Lazarus?
« Reply #8 on: March 29, 2013, 01:43:24 pm »
As usual, Windows has A and W variant of its API, including this function. You should map the name to one of the variant, because they are what really exists in the kernel32 library.

Thanks - I thought the problem might be something like this. Unfortunately I don't know how to do the mapping. I have already tried changing all occurrences of QueryFullProcessImageName to QueryFullProcessImageNameA, recompiling and running; same error. I also tried this with QueryFullProcessImageNameW but got the same error again. I assume this means that all of the names need to be mapped regardless of which version Windows goes on to use.

Another obvious thing to try is repeating the declaration twice with the name variations, but I've also tried that

Code: [Select]
function QueryFullProcessImageName(hProcess: HANDLE; dwFlags: DWORD; var lpExeName: LPTSTR;
 var dwsize: DWORD): BOOL; stdcall; external 'KERNEL32.dll';
{$EXTERNALSYM QueryFullProcessImageName}

function QueryFullProcessImageNameA(hProcess: HANDLE; dwFlags: DWORD; var lpExeName: LPTSTR;
 var dwsize: DWORD): BOOL; stdcall; external 'KERNEL32.dll';
{$EXTERNALSYM QueryFullProcessImageNameA}

function QueryFullProcessImageNameW(hProcess: HANDLE; dwFlags: DWORD; var lpExeName: LPTSTR;
 var dwsize: DWORD): BOOL; stdcall; external 'KERNEL32.dll';
{$EXTERNALSYM QueryFullProcessImageNameW}

...and got the same error ("The procedure entry point...could not be located") yet again.

I went on to try the following (slight adjustment of the lpExeName types in line with examples in Jedi) - same result, an error on the call.
Code: [Select]
function QueryFullProcessImageName(hProcess: HANDLE; dwFlags: DWORD; var lpExeName: LPTSTR;
 var dwsize: DWORD): BOOL; stdcall; external 'KERNEL32.dll';
{$EXTERNALSYM QueryFullProcessImageName}

function QueryFullProcessImageNameA(hProcess: HANDLE; dwFlags: DWORD; var lpExeName: LPSTR;
 var dwsize: DWORD): BOOL; stdcall; external 'KERNEL32.dll';
{$EXTERNALSYM QueryFullProcessImageNameA}

function QueryFullProcessImageNameW(hProcess: HANDLE; dwFlags: DWORD; var lpExeName: LPWSTR;
 var dwsize: DWORD): BOOL; stdcall; external 'KERNEL32.dll';
{$EXTERNALSYM QueryFullProcessImageNameW}
« Last Edit: March 29, 2013, 03:59:58 pm by JohnSaltwell »
John H, north east England
Lover of the old Delphi, still inexperienced with FPC/Lazarus and not an instinctive programmer
Tried .Net Core and was perpetually in knots, so am back here to try again with Windows clients

Leledumbo

  • Hero Member
  • *****
  • Posts: 8266
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: QueryFullProcessImageName API Function - can it be used in Lazarus?
« Reply #9 on: March 29, 2013, 05:19:46 pm »
Quote
Unfortunately I don't know how to do the mapping
Use:
Code: [Select]
external 'LibraryName' name 'FunctionName'Here are some examples taken from ascdef.inc (part of windows unit):
Code: [Select]
function GetBinaryType(lpApplicationName:LPCSTR; lpBinaryType:LPDWORD):WINBOOL; external 'kernel32' name 'GetBinaryTypeA';
function GetShortPathName(lpszLongPath:LPCSTR; lpszShortPath:LPSTR; cchBuffer:DWORD):DWORD; external 'kernel32' name 'GetShortPathNameA';
function GetEnvironmentStrings : LPSTR; external 'kernel32' name 'GetEnvironmentStringsA';
function FreeEnvironmentStrings(_para1:LPSTR):WINBOOL; external 'kernel32' name 'FreeEnvironmentStringsA';
function FormatMessage(dwFlags:DWORD; lpSource:LPCVOID; dwMessageId:DWORD; dwLanguageId:DWORD; lpBuffer:LPSTR;nSize:DWORD; Arguments:va_list):DWORD; external 'kernel32' name 'FormatMessageA';

TyneBridges

  • Full Member
  • ***
  • Posts: 127
    • Personal blog
Re: QueryFullProcessImageName API Function - can it be used in Lazarus?
« Reply #10 on: March 29, 2013, 06:33:54 pm »
Thanks to everyone for their help. In fact, I gave up on the function in the thread title. I did eventually manage to get it to run without errors but it still didn't work - all of the names it displayed consisted of the same 3 non-ASCII characters. Eventually I found that, for my use, CreateToolHelp32Snapshot and Process32First/Process32Next would give the names of all running processes, 32 and 64 bit. I'm posting the following in case it's useful to anyone else. In a console application, this will list all running processes and give as its result the process ID of the process name fed to it as a string (e.g. winlogon.exe).

It's messy programming in at least one sense, as a function shouldn't really list things that aren't part of its result - but it does work. If you need the process names and the paths, unfortunately that's much harder. It proved to be too difficult for me but (luckily) all I really needed were the process names.

Code: [Select]
  function FindInProcesses(const PName: String): DWord;
  var
     i: integer;
     CPID: DWORD;
     CProcName: Array[0..259] of Char;
     S: HANDLE;
     PE: TProcessEntry32;
  begin
       Result:= 0;
       CProcName:= '';
       // Create snapshot
       S:= CreateToolHelp32Snapshot(TH32CS_SNAPALL, 0);
       // Set size before use
       PE.DWSize:= SizeOf(PE);
       I:= 1;
       If Process32First(S, PE) then
       repeat
             CProcName:= PE.szExeFile;
             CPID:= PE.th32ProcessID;
             If CProcName = '' then
                Writeln(IntToStr(i) + ' - (' + IntToStr(CPID) + ') Failed to get a process name')
             else
                 Writeln(IntToStr(i) + ' - (' + IntToStr(CPID) + ') ' + Trim(CProcName) + '. ');
             Inc(i);
             If UpperCase(CProcName) = UpperCase(PName) then
                { Found the name. Set Result to the PID of process found }
                Result:= CPID;
       until not Process32Next(S, PE);
       CloseHandle(S);
  end; // FindInProcesses
     
« Last Edit: March 30, 2013, 07:59:10 am by JohnSaltwell »
John H, north east England
Lover of the old Delphi, still inexperienced with FPC/Lazarus and not an instinctive programmer
Tried .Net Core and was perpetually in knots, so am back here to try again with Windows clients

BigChimp

  • Hero Member
  • *****
  • Posts: 5740
  • Add to the wiki - it's free ;)
    • FPCUp, PaperTiger scanning and other open source projects
Want quicker answers to your questions? Read http://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

Open source including papertiger OCR/PDF scanning:
https://bitbucket.org/reiniero

Lazarus trunk+FPC trunk x86, Windows x64 unless otherwise specified

 

TinyPortal © 2005-2018