multithreadingdelphiwinapitstringlist

Passing a TStrings Object to a Secondary Thread in Delphi


I'd like to know how to pass the local object address of a TStrings object (allocated on the heap, IIRC) from the calling function to a thread I create with CreateThread(). The thread has an infinite wait, so the object should still be available at the caller level, waiting to be filled with information.

I'd like to keep this Win32 related and not use the VCL TThread class for such stuff.

Does anyone have an example of how to do this? IsMutliThread is already set to True before the CreateThread() API call. I just would like to utilize passing the address of the TStrings variable directly to the worker thread.


Solution

  • First off, IsMutliThread has no effect on CreateThread().

    Second, CreateThread() has an lpParameter parameter for this exact kind of situation. It is an untyped Pointer, so you can pass whatever you want to your thread function. In this case, you can simply pass the value of the TStrings local variable, you don't need to pass the address of the local variable, eg:

    function MyThreadProc(lpParameter: Pointer): DWORD; stdcall;
    var
      List: TStrings;
    begin
      List := TStrings(lpParameter);
      // populate List as needed...
      Result := 0;
    end;
    
    ...
    
    var
      List: TStrings;
      H: THandle;
      TID: DWORD;
    begin
      List := TStringList.Create;
      try
        H := CreateThread(nil, 0, @MyThreadProc, List, 0, TID);
        if H = 0 then RaiseLastOSError;
        WaitForSingleObject(H, INFINITE);
        CloseHandle(H);
        // use List as needed...
      finally
        List.Free;
      end;
    end;
    

    That being said, creating a worker thread just to immediately wait for it to terminate is a waste of a worker thread. In which case, you may as well just remove the worker thread altogether and call the thread function directly and wait for it to return, the end result will be exactly the same - the caller waits until the TStrings is populated - eg:

    procedure MyProc(List: TStrings);
    begin
      // populate List as needed...
    end;
    
    ...
    
    var
      List: TStrings;
    begin
      List := TStringList.Create;
      try
        MyProc(List);
        // use List as needed...
      finally
        List.Free;
      end;
    end;