Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if an handle should be closed?

Tags:

delphi

handle

In case which ShellExecuteEx returns false, should the handle be closed?:

function EditAndWait(const AFileName : string) : boolean;
var
  Info: TShellExecuteInfo;
begin
  FillChar(Info, SizeOf(Info), 0);
  Info.cbSize := SizeOf(Info);
  Info.lpVerb := 'edit';
  Info.lpFile := PAnsiChar(AFileName);
  Info.nShow := SW_SHOW;
  Info.fMask := SEE_MASK_NOCLOSEPROCESS;
  Result := ShellExecuteEx(@Info);
  if(Result) then 
  begin
    WaitForSingleObject(Info.hProcess, Infinite);
    CloseHandle(Info.hProcess);
  end else
  begin
     //should I close the process handle?
  end;
end;

More generally, how can I check if an handle should be closed?

like image 221
Fabrizio Avatar asked Sep 08 '16 14:09

Fabrizio


People also ask

How do you close a process handle?

Assuming we find our handle, what do we do with it? Fortunately, there is a trick we can use that allows closing a handle in another process: call DuplicateHandle again, but add the DUPLICATE_CLOSE_SOURCE to close the source handle. Then close our own copy, and that's it!

What is a valid handle?

VALID-HANDLE ( handle ) handle. An expression that evaluates to a value of type HANDLE. If the handle represents an object that is currently valid, VALID-HANDLE returns TRUE. If the handle is no longer valid (if, for example, some procedure deleted the object), the function returns FALSE.

Is window handle valid?

Window handles are recycled so a window handle that was valid, and then invalid, could be valid again, but pointing to a completely different window.


1 Answers

You are only returned a process handle if:

  1. You included SEE_MASK_NOCLOSEPROCESS, and
  2. The function call succeeded, and
  3. The action was resolved by creating a new process.

In case the first two conditions hold, but not the third, then you will be handled back a process handle with value zero. So your code should be:

Result := ShellExecuteEx(@Info);
if Result and (Info.hProcess<>0) then 
begin
  WaitForSingleObject(Info.hProcess, Infinite);
  CloseHandle(Info.hProcess);
end;

If we were being very pedantic we might look for error checking on WaitForSingleObject and CloseHandle. Frankly though, I find it hard to get excited about that in this instance. What are the possible failure modes that could be recovered from?


You might well ask what I mean by:

The action was resolved by creating a new process.

Well, it's entirely possible for a shell action to be resolved by re-cycling an existing process. In which case you may not be returned a process handle. And that puts the kibosh on your code because you have nothing to wait on, never mind no handle to close. You'll just have to accept that such scenarios are beyond you.

The documentation has this to say:

SEE_MASK_NOCLOSEPROCESS

Use to indicate that the hProcess member receives the process handle. This handle is typically used to allow an application to find out when a process created with ShellExecuteEx terminates. In some cases, such as when execution is satisfied through a DDE conversation, no handle will be returned. The calling application is responsible for closing the handle when it is no longer needed.


Finally, may I congratulate you on taking seriously the issues of error checking and leak avoidance. So many developers seem to ignore this issue, no matter how many times they are told. It's nice that you have listened to comments at recent questions and made the effort to improve your code. Well done!

like image 75
David Heffernan Avatar answered Sep 23 '22 23:09

David Heffernan