-5

In the answer in this SO question, there were some suggestions made in the comments but never fully finalized. So the basis of this question is to get a complete, correct, good quality answer.

So here is the code that I have derived based on the answer and comments to the above SO question:

procedure RunFileAsAdminWait(hWnd: hWnd; aFile, aParameters: string);
var
  sei: TShellExecuteInfo;
  msg: tagmsg;
begin
  FillChar(sei, SizeOf(sei), 0);
  sei.cbSize := SizeOf(sei);
  sei.Wnd := hWnd;
  sei.fMask := SEE_MASK_FLAG_NO_UI or SEE_MASK_NOCLOSEPROCESS;
  sei.lpVerb := 'runas';
  sei.lpFile := PChar(aFile);
  sei.lpParameters := PChar(aParameters);
  sei.nShow := SW_SHOWNORMAL;

  if ShellExecuteEx(@sei) then
  begin
    while MsgWaitForMultipleObjects(1, sei.hProcess, False, INFINITE, QS_ALLINPUT) <> WAIT_OBJECT_0 do
      while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
        DispatchMessage(msg);

    CloseHandle(sei.hProcess);
  end;
end;

But there was a comment in the answers to the above way that MsgWaitForMultipleObjects is called: "You should be processing messages only when MsgWaitForMultipleObjects() specifically returns WAIT_OBJECT_0+1 only. Handle other return values accordingly." – Remy Lebeau

Please suggest the corrections as an answer in order to make it complete, good quality code.

Community
  • 1
  • 1
Steve F
  • 1,527
  • 1
  • 29
  • 55
  • You don't check for errors when you call ShellExecuteEx. You don't call TranslateMessage. You can deal with Remy's code by reading the documentation. It looks like you don't want to learn yourself and just want others to write your code for you. Did you read the docs for MsgWaitForMultipleObjects? Could you not understand a particular part of those docs? – David Heffernan Jan 24 '16 at 10:47
  • @DavidHeffernan I read the MSDN page but could not glean a clue about what to do in this particular case. I also did a Google search and read about 4 or 5 different forum posts with answers, but no particular answer stood out as 'correct' to the particular issue in this question. That is why I posted here. Sorry if i offended you. – Steve F Jan 24 '16 at 10:52
  • We're this me, I'd be very sceptical about running what amounts to Application.ProcessMessages. I hope you know of the dangers of that. We're it me I'd put the wait in a separate event and send a message to main thread when the wait completes. – David Heffernan Jan 24 '16 at 10:52
  • So, if you are struggling to understand the docs that you read, tell us which parts you understand, which you don't understand. Please make it obvious that you aren't being lazy and expecting us to write your code. For me, I like helping people learn. Nothing in it for me to just do the work and have you not learn. So make it obvious that you want to learn. But as I said above, your chosen solution is likely the wrong approach anyway. – David Heffernan Jan 24 '16 at 10:55
  • @DavidHeffernan Its the comment made by Remy about the return value of "WAIT_OBJECT_0+1". What should be done (code) after that? ie. What messages should be handled and how, using which call? That is what I don't know how to do. – Steve F Jan 24 '16 at 10:58
  • Actually, as I said, you made a number of other mistakes. But the answer can be found in the documentation. It's written very clearly. What do you not understand? And why are you choosing to do the equivalent of ProcessMessages? – David Heffernan Jan 24 '16 at 11:01
  • I corrected the part of checking the return value of ShellExecuteEx. I'm not sure about what is TranslateMessage. Finally the MSDN documentation page does not particularly state what needs to be done after the call to "MsgWaitForMultipleObjects".. – Steve F Jan 24 '16 at 11:04
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/101511/discussion-between-steve-f-and-david-heffernan). – Steve F Jan 24 '16 at 11:06
  • Do you understand why not to use ProcessMessages? If so why are you doing that? And why don't you find the answer in the docs? Let me try again. When you read the docs, what did you not understand. Please try to answer all my questions. – David Heffernan Jan 24 '16 at 11:15
  • @DavidHeffernan: Here goes: Actually, I don't understand why not to use ProcessMessages. I'm using the code from the answer on that page. When I read the MSDN docs, I'm not sure what to do after the call to MsgWaitForMultipleObjects, specifically, I don't understand how to "wait" for the process to end or terminate. – Steve F Jan 24 '16 at 11:24
  • Also, only call CloseHandle when SEE succeeds. Otherwise you might accidentally close a handle that should not be closed. – David Heffernan Jan 24 '16 at 12:05

1 Answers1

4

The documentation for MsgWaitForMultipleObjects tells you how to interpret the return value. Here are the possible return values for your specific call:

  • WAIT_OBJECT_0 + 0 means the wait returned because the process is signaled. Handle this by exiting the loop. Your child process has terminated.
  • WAIT_OBJECT_0 + 1 means the wait returned because messages have been added to the queue. Handle this by pumping the message queue and then continuing the loop.
  • WAIT_ABANDONED_0 + 0 is not possible since you are not waiting on a mutex object.
  • WAIT_TIMEOUT is not possible because you used an infinite timeout.
  • WAIT_FAILED is an unexpected error. This should not be possible to encounter. You should respond to this by calling RaiseLastOSError.

There are other mistakes in your code as discussed in the comments which I will not repeat.

Further, your approach can lead to problems with re-entrancy and is equivalent to calling Application.ProcessMessages. It might be better to wait in a thread and send a message when that wait returns.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490