Recent

Author Topic: Add a unique id within exe  (Read 21056 times)

timcs

  • Full Member
  • ***
  • Posts: 213
Re: Add a unique id within exe
« Reply #15 on: February 25, 2015, 03:27:07 pm »
Since we are on windows.
Code: [Select]
uses JwaTlHelp32, Windows;

function IsProcessRunning(PID: DWORD): Boolean;
var
  pProc: TProcessEntry32;
  pSnap: THandle;
  pBool: BOOL;
begin
  Result := False;
  pProc.dwSize := SizeOf(pProc);
  pSnap := CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
  pBool := Process32First(pSnap, pProc);
  while Integer(pBool) <> 0 do
  begin   
    {ShowMessage('PName: ' + pProc.szExeFile + sLineBreak +
                'PID: ' + IntToStr(pProc.th32ParentProcessID) + sLineBreak +
                'PARENTID: ' + IntToStr(pProc.th32ParentProcessID));}
    if pProc.th32ProcessID = PID then
    begin
       Result := True;
       Break;
    end;
    pBool := Process32Next(pSnap, pProc);
   end;
   CloseHandle(pSnap);
end;

Just make a PID list with your  processes, you can check which one is running from time to time.

Thanks GetMem, one question how would I identify a specific process with specific parameters as this will just list all of My process no matter what.

Thanks

TimCS

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Add a unique id within exe
« Reply #16 on: February 25, 2015, 03:34:30 pm »
Hi Taazz

  The program starts with parameters as it is called from an internal web page those parameters provide it with the details to be used with mstsc so how do I then use these parameters to identify that process ?


web page? really? up until now you are talking about using tprocess to execute external applications and now you are talking about web page? You can not distinguish between web page instances none of them are applications in the memory of the computer they are the result of the web server processing html files. The processID is always not to be used or rely upon for anything. If the server is multithreaded (windows based technology mostly) then the processID will always be the same for all your instances if it is fork based (linux mostly) then the moment you have the page that specific process might have already died out. In any case make sure that the web page passes to your process all the information required and never ever pull info from the server /web page your self, its not designed to allow this, actually I would think that it was designed to disallow that kind of use for security reasons.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

balazsszekely

  • Guest
Re: Add a unique id within exe
« Reply #17 on: February 25, 2015, 03:39:06 pm »
Does your process has a window? If yes, then you can send message between the processes with SendMessage or even better PostMessage which is asynchronous.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms644950%28v=vs.85%29.aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/ms644944%28v=vs.85%29.aspx

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Add a unique id within exe
« Reply #18 on: February 25, 2015, 03:40:18 pm »
my question on your suggestion is how do I know that the ID I find is the right one if there are multiple processes open ?

You can use, beside your program ProcessID, the thread ID as well: GetThreadID. In this case both ProcessID and ThreadID should identify your program uniquely.

balazsszekely

  • Guest
Re: Add a unique id within exe
« Reply #19 on: February 25, 2015, 04:12:32 pm »
Quote
engkin
You can use, beside your program ProcessID, the thread ID as well: GetThreadID. In this case both ProcessID and ThreadID should identify your program uniquely.

The ProcessID alone identify his program uniquely. He needs more info about that specific process/program(the ID is just a number). That's why I suggested to keep a list with all started processID + some additional info(he can save the list to file, mapped memory, etc), or if the process has a window(this can be also done without a window, see my previous post) he can request "live" that specific  info.


timcs

  • Full Member
  • ***
  • Posts: 213
Re: Add a unique id within exe
« Reply #20 on: February 25, 2015, 04:23:38 pm »
Hi Taazz

  The program starts with parameters as it is called from an internal web page those parameters provide it with the details to be used with mstsc so how do I then use these parameters to identify that process ?


web page? really? up until now you are talking about using tprocess to execute external applications and now you are talking about web page? You can not distinguish between web page instances none of them are applications in the memory of the computer they are the result of the web server processing html files. The processID is always not to be used or rely upon for anything. If the server is multithreaded (windows based technology mostly) then the processID will always be the same for all your instances if it is fork based (linux mostly) then the moment you have the page that specific process might have already died out. In any case make sure that the web page passes to your process all the information required and never ever pull info from the server /web page your self, its not designed to allow this, actually I would think that it was designed to disallow that kind of use for security reasons.

Okay I will clarify matters here sorry again for the confusion. My program is started from an internal web page, this then fires up a batch file which runs my program, my program then reads in the parameters from the link from the web page and with this information starts the mstsc via a TPRocess routine , then runs in the background (not threaded) waiting for the connection to finish, when finished, my program closes. The purpose of this all is that when my program starts, it creates a record in a database table with the date and time on and the users Windows log in name. The purpose of this is so that one user who is on , does not get kicked off the link when another user tries to connect as my program tells the second user who is on. When my program closes it writes a date time off for that record.

What is happening at the moment, is that on occasions my program is either stuck or mstsc crashes my program so that the date time off is then not written and then my program thinks someone is on when they are not. I can deal with the situation when my program is no longer running but I need to deal with closing my program down when it gets stuck .

Again I hope this clears matters up :)

Thanks
TimCS 

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Add a unique id within exe
« Reply #21 on: February 25, 2015, 05:24:27 pm »
You are using poWaitOnExit in the process options to write the log-off time. Instead of waiting forever, remove poWaitOnExit and wait for a small period:
Code: [Select]
  while true do
  begin
    //SomeTime = 4 minues
    if WaitForSingleObject(Process.Handle, SomeTime) <> Wait_Failed then  //<----
    begin
      //TProcess finished: Write log off time (Now)
      break;
    end
    else
    begin
      //TProcess not finished: Write a future log off time (Now + SomeTime + 1 minutes)
    end;
  end;

OR:
Initiate mstsc TProcess in a thread, this way the thread may get stuck but not your program process which can check that mstsc session exists periodically, and just in case it crashes your program should write a future log-off time record and update it periodically while waiting for the real log-off time to happen.

timcs

  • Full Member
  • ***
  • Posts: 213
Re: Add a unique id within exe
« Reply #22 on: February 25, 2015, 05:42:38 pm »
You are using poWaitOnExit in the process options to write the log-off time. Instead of waiting forever, remove poWaitOnExit and wait for a small period:
Code: [Select]
  while true do
  begin
    //SomeTime = 4 minues
    if WaitForSingleObject(Process.Handle, SomeTime) <> Wait_Failed then  //<----
    begin
      //TProcess finished: Write log off time (Now)
      break;
    end
    else
    begin
      //TProcess not finished: Write a future log off time (Now + SomeTime + 1 minutes)
    end;
  end;

OR:
Initiate mstsc TProcess in a thread, this way the thread may get stuck but not your program process which can check that mstsc session exists periodically, and just in case it crashes your program should write a future log-off time record and update it periodically while waiting for the real log-off time to happen.

Hi Engkin if I wait for a small period would this not mean that my program exits before the mstsc has finished ? I use wait on exit because I need to wait for the mstsc to finish before I update the table.

Thanks

TimCS

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Add a unique id within exe
« Reply #23 on: February 25, 2015, 06:05:41 pm »
Well, you are still in a waiting forever loop:
Code: [Select]
  while true do
but inside this loop your program can do other things, like waiting for a small period:
Code: [Select]
    if WaitForSingleObject(Process.Handle, SomeTime) <> Wait_Failed then
so your can update the future record (a record that writes some future time) just in case you program crashes while waiting for the TProcess to finish.
« Last Edit: February 25, 2015, 06:09:35 pm by engkin »

timcs

  • Full Member
  • ***
  • Posts: 213
Re: Add a unique id within exe
« Reply #24 on: February 25, 2015, 06:59:34 pm »
Well, you are still in a waiting forever loop:
Code: [Select]
  while true do
but inside this loop your program can do other things, like waiting for a small period:
Code: [Select]
    if WaitForSingleObject(Process.Handle, SomeTime) <> Wait_Failed then
so your can update the future record (a record that writes some future time) just in case you program crashes while waiting for the TProcess to finish.

Okay I will give this a go and report back.

***EDIT***
I have a question on your code regarding the part when the TProcess has not finished and your remark there is to write off a date and time + the Sometime value. My question is why would I write a time off if the process has not finished ?



Thanks

TimCS
« Last Edit: February 25, 2015, 07:21:24 pm by timcs »

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Add a unique id within exe
« Reply #25 on: February 25, 2015, 07:49:10 pm »
My question is why would I write a time off if the process has not finished ?

Let us assume that after a call to WaitForSingleObject the process did not finish, then you write/update the time record for some future time (5 minutes from now) and the loop calls WaitForSingleObject again, this time for some unknown reason your application crashed!

Later someone tries to establish a mstsc session, if this happens:
1-before the recorded future time, then (the second copy of) your program knows that a session is "possibly" on going and would refuse to establish another one or it could check if a session is really on going.
2-after the recorded future time (it is not future time anymore) then (the second copy of) your program would go ahead and establish a new session.

Check the attached project for an example to wait for a TProcess using both a thread or a simple while loop.

timcs

  • Full Member
  • ***
  • Posts: 213
Re: Add a unique id within exe
« Reply #26 on: February 26, 2015, 12:06:12 am »
My question is why would I write a time off if the process has not finished ?

Let us assume that after a call to WaitForSingleObject the process did not finish, then you write/update the time record for some future time (5 minutes from now) and the loop calls WaitForSingleObject again, this time for some unknown reason your application crashed!

Later someone tries to establish a mstsc session, if this happens:
1-before the recorded future time, then (the second copy of) your program knows that a session is "possibly" on going and would refuse to establish another one or it could check if a session is really on going.
2-after the recorded future time (it is not future time anymore) then (the second copy of) your program would go ahead and establish a new session.

Check the attached project for an example to wait for a TProcess using both a thread or a simple while loop.

Hi Engkin this may be a problem as I have been working to sort another issue out where the user sometimes double clicks on the line very quickly and in doing this no matter how I have checked for the second instance by the date on time I have never been able to catch it. Instead what I do is when these two processes end by the user cancelling one and finishing with the other, the two records are found with  a limit 1 search instead of trying to find the record by its ID which was the problem I had to start with.

I would pefer not to have to write a future date off as currently I leave the date off blank to find that there is a user on the site and this has worked. So can this method not work instead by just leaving the date off empty has it is now ?

Thanks

TimCS

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Add a unique id within exe
« Reply #27 on: February 26, 2015, 12:48:27 am »
I would pefer not to have to write a future date off as currently I leave the date off blank to find that there is a user on the site and this has worked. So can this method not work instead by just leaving the date off empty has it is now ?

Yes, sure! that was just a quick idea. Any alternative should work. For instance, since you leave the date empty you know that there is a "possible" user already engaged using the mstsc session. Now to make sure that the session is really there and the program did not crash you might want to consider writing the Process ID somewhere so that (the new copy of ) your programs can try to find it as shown previously by GetMem. If it does not exist then write the current program ProcessID and start a new session.

timcs

  • Full Member
  • ***
  • Posts: 213
Re: Add a unique id within exe
« Reply #28 on: February 26, 2015, 09:16:43 am »
I would pefer not to have to write a future date off as currently I leave the date off blank to find that there is a user on the site and this has worked. So can this method not work instead by just leaving the date off empty has it is now ?

Yes, sure! that was just a quick idea. Any alternative should work. For instance, since you leave the date empty you know that there is a "possible" user already engaged using the mstsc session. Now to make sure that the session is really there and the program did not crash you might want to consider writing the Process ID somewhere so that (the new copy of ) your programs can try to find it as shown previously by GetMem. If it does not exist then write the current program ProcessID and start a new session.

Hi again engkin , okay also I wondered if I could still look for an existing process by searching for its paramters as when the link is clicked the parameters are passed from the link to my program and when I view my program in Task Manager with the command line, I can see the parameters and these are unique per link / connection

Thanks

TimCS

balazsszekely

  • Guest
Re: Add a unique id within exe
« Reply #29 on: February 26, 2015, 10:55:27 am »
I commented the code as much as possible, you also have a small homework. Feel free to ask questions(if you have any).
Here you go:
Code: [Select]
program Project1;

{$mode objfpc}{$H+}

{$DEFINE UseCThreads}
uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,
  SysUtils,
  JwaTlHelp32,
  Windows,
  Process;

const
  UniqueString = 'ThisIsJustAUniqueString';


type
  PProcessData = ^TProcessData;
  TProcessData = packed record
    PID : DWORD;
    mstscPID: DWORD;
    Description: String[100];
    LastActive: DWORD;
    hFileMap: HANDLE;
    //you can add other data here
  end;


function ReadData(const FileMapName: string; var ProcessData: TProcessData): Boolean;
var
  hFileMap: HANDLE;
  pPProcessData: PProcessData;
begin
  Result := False;

  hFileMap := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, PChar(FileMapName));
  if (hFileMap = 0) then
    Exit;

  pPProcessData := MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  if (pPProcessData =  nil) then
    Exit;

  ProcessData.PID :=  pPProcessData^.PID;
  ProcessData.mstscPID := pPProcessData^.mstscPID;
  ProcessData.Description := pPProcessData^.Description;
  ProcessData.LastActive := pPProcessData^.LastActive;
  ProcessData.hFileMap :=  pPProcessData^.hFileMap;

  UnmapViewOfFile(pPProcessData);

  Result := True;
end;

function WriteData(const hFileMap: HANDLE; const ProcessData: TProcessData): Boolean;
var
  pPProcessData: PProcessData;
begin
  Result := False;

  if (hFileMap = 0) then
    Exit;

  pPProcessData := MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(TProcessData));
  if (pPProcessData =  nil) then
    Exit;

  pPProcessData^.PID := ProcessData.PID;
  pPProcessData^.mstscPID := ProcessData.mstscPID;
  pPProcessData^.Description := ProcessData.Description;
  pPProcessData^.LastActive := ProcessData.LastActive;
  pPProcessData^.hFileMap := ProcessData.hFileMap;

  UnmapViewOfFile(pPProcessData);

  Result := True;
end;

function CheckMstscStatus(PID: DWORD): Boolean;
var
  pProc: TProcessEntry32;
  pSnap: THandle;
  pBool: BOOL;
begin
  Result := False;
  pProc.dwSize := SizeOf(pProc);
  pSnap := CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
  pBool := Process32First(pSnap, pProc);
  while Integer(pBool) <> 0 do
  begin
    if pProc.th32ProcessID = PID then
    begin
       //HOMEWORK --> MSTSC is running, check if is alive...
       //Result := IsMstscAlive;
       Result := True;
       Break;
    end;
    pBool := Process32Next(pSnap, pProc);
   end;
   CloseHandle(pSnap);
end;


function KillProcess(PID: DWORD): Boolean;
var
  hProcess : HANDLE;
begin
  Result := False;

  hProcess := OpenProcess(PROCESS_TERMINATE, False, PID);
  if hProcess > 0 then
  try
    Result := Win32Check(Windows.TerminateProcess(hProcess, 0));
  finally
    CloseHandle(hProcess);
  end;
end;

function CheckIfProcessAlive(const FileMapName: string; const ProcessData: TProcessData): Boolean;
var
  New_ProcessData: TProcessData;
  IsMstscAlive: Boolean;
begin
  Result := False;

  Sleep(2000);//give a chance to the process to update itself

  if ReadData(FileMapName, New_ProcessData) then
  begin
    //MessageBox(0, PChar(IntToStr(ProcessData.LastActive) + sLineBreak + IntToStr(New_ProcessData.LastActive)), PChar('test'), 0);
    IsMstscAlive := CheckMstscStatus(ProcessData.mstscPID);
    Result := (ProcessData.LastActive <> New_ProcessData.LastActive) and (IsMstscAlive)
  end;
end;

procedure FindPreviouslyStartedProcesses(CurPID: DWord);
var
  pProc: TProcessEntry32;
  pSnap: THandle;
  pBool: BOOL;
  FileMapName: String;
  ProcessData: TProcessData;
begin
  pProc.dwSize := SizeOf(pProc);
  pSnap := CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
  pBool := Process32First(pSnap, pProc);
  while (Integer(pBool) <> 0) do
  begin
    FileMapName := UniqueString + IntToStr(pProc.th32ProcessID);
    if (pProc.th32ProcessID <> CurPID) then
    begin
      FileMapName := UniqueString + IntToStr(pProc.th32ProcessID);
      if ReadData(FileMapName, ProcessData) then //previously started process
      begin
        if not CheckIfProcessAlive(FileMapName, ProcessData) then  //dead is in the air
        begin
          KillProcess(ProcessData.PID);
          KillProcess(ProcessData.mstscPID);
          //do whatever you have to do in case of process freeze(write to db... you got ProcessData.Description)
          CloseHandle(ProcessData.hFileMap); //close handle of the memory mapp
        end;
      end;
    end;
    pBool := Process32Next(pSnap, pProc);
   end;
end;


var
  FileMapName: String;
  hFileMap: HANDLE;
  ProcessData: TProcessData;
  Proc: TProcess;
  CurPID: DWORD;
begin
  //Current process id
  CurPID := GetProcessID;
  //This will uniquely identify your process memory mapped file
  FileMapName := UniqueString + IntToStr(CurPID);

  //find previous processes, kill them if necessary
  FindPreviouslyStartedProcesses(CurPID);

  //create a file mapp for this process
  hFileMap := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, SizeOf(TProcessData), PChar(FileMapName));
  if hFileMap <> 0 then
  begin
    //init then execute your TProcess
    Proc := TProcess.Create(nil);
    Proc.CommandLine := 'notepad.exe'; //I just start notepad for testing purposes, change this line
    Proc.Execute;
    //fill our process data
    ProcessData.PID := CurPID;
    ProcessData.Description := 'add connection data here';
    ProcessData.mstscPID := Proc.ProcessID;
    ProcessData.hFileMap := hFileMap;
    while Proc.Active do
    begin
      Sleep(1000);
      ProcessData.LastActive := GetTickCount;
      WriteData(hFileMap, ProcessData);
    end;
    //cleanup
    Proc.Free;
    CloseHandle(hFileMap);
  end;
end.


PS: Some of the functions needs elevated privileges(run your program as admin, if possible).
« Last Edit: February 26, 2015, 12:10:56 pm by GetMem »

 

TinyPortal © 2005-2018