3

The following code minimally demonstrates the problem. In a background thread, I create a valid handle array and pass it to WaitForMultipleObjects and this successfully waits on the objects.

When passing the exact same array to MsgWaitForMultipleObjects, however, the function call fails (WAIT_FAILED) with ERROR_INVALID_HANDLE.

What am I doing wrong?

program Project1;
{$APPTYPE CONSOLE}
uses
  SysUtils, Windows, SyncObjs, Classes;

type
  TMyThread = class(TThread)
    protected
      procedure Execute; override;
  end;

procedure TMyThread.Execute;
var
  LEvent : TEvent;
  LWaitHandles : TWOHandleArray;
  LPWaitHandles : PWOHandleArray;
  LWaitResult : Cardinal;
begin
  LEvent := TEvent.Create;
  LWaitHandles[0] := LEvent.Handle;
  LPWaitHandles := @LWaitHandles;
  while not Terminated do begin
    {Works -> LWaitResult := WaitForMultipleObjects(1, LPWaitHandles, false, INFINITE);}
    {Fails ->} LWaitResult := MsgWaitForMultipleObjects(1, LPWaitHandles, false, INFINITE, QS_ALLINPUT);
    case LWaitResult of
      WAIT_OBJECT_0:      WriteLn('Event 1 Signaled');
      { etc... }
      WAIT_FAILED :       WriteLn(SysErrorMessage(GetLastError));
    end;
  end;
end;

var
  lt : TMyThread;
begin
  lt := TMyThread.Create(false);
  ReadLn;
end.
J...
  • 30,968
  • 6
  • 66
  • 143
  • Is the problem that the thread doesn't have a message queue? It only gets one when you call certain functions. Like PeekMessage, GetMessage, etc. Can't remember the full list. – David Heffernan Jan 23 '17 at 17:48
  • @DavidHeffernan No, I just figured it out - it's an RTL issue (erratic type consistency in the WinAPI wrappers). Even if there are no messages posted to the thread, `MsgWaitForMultipleObjects` should still not return `WAIT_FAILED`. – J... Jan 23 '17 at 17:51
  • Oh I remember that. The RTL wrapper is lame. Also, no point in you declaring an array with 64 elements like that. You never declare a TWOHandleArray. – David Heffernan Jan 23 '17 at 17:52
  • @DavidHeffernan Yeah, I didn't bother making a message queue simply because it was not important for demonstrating the problem. And yes, `TWOHandleArray` is wasteful - it does save a line of code for the MCVE, however. – J... Jan 23 '17 at 17:53
  • 1
    TWOHandleArray is good. If I paid attention to the RTL wrapper, I wouldn't have asked [this](http://stackoverflow.com/questions/39380131/why-does-waitformultipleobjects-fail-with-multiple-thread-handles) question. – Sertac Akyuz Jan 23 '17 at 19:13

1 Answers1

5

Although the WinAPI signature for the handles parameter is identical for these two calls :

 _In_ const HANDLE *pHandles,

the RTL nevertheless wraps these functions in different ways. WaitForMultipleObjects uses the pointer type:

lpHandles: PWOHandleArray;

while MsgWaitForMultipleObjects uses an untyped var parameter:

var pHandles;

The handle array must therefore be passed directly to MsgWaitForMultipleObjects.

ie:

LWaitResult := MsgWaitForMultipleObjects(1, LWaitHandles, false, INFINITE, QS_ALLINPUT);
J...
  • 30,968
  • 6
  • 66
  • 143