I'm new to multithreading, but not a complete novice. I need to perform a call to a webservice in a worker thread.
In the main thread I have a form (TForm) with a private data member (private string) that only the worker thread will write to (I pass the a pointer to it into the thread before it resumes). When the worker thread has finished its webservice call and written the resultant response xml to the private member on the form, the worker thread uses PostMessage to send a message to the form's handle (which I also passed into the thread before it resumed).
interface const WM_WEBSERVCALL_COMPLETE = WM_USER + 1; type TWebServiceResponseXML = string; PWebServiceResponseXML = ^TWebServiceResponseXML; TMyForm = class(TForm) ... private ... fWorkerThreadID: Cardinal; fWebServiceResponseXML: TWebServiceResponseXML; public ... procedure StartWorkerThread; procedure OnWebServiceCallComplete(var Message: TMessage); Message WM_WEBSERVCALL_COMPLETE; end; TMyThread = class(TThread) private protected procedure Execute; override; public SenderHandle: HWnd; RequestXML: string; ResponseXML: string; IMyService: IService; PResponseXML: PWebServiceResponseXML; end; implementation procedure TMyForm.StartWorkerThread; var MyWorkerThread: TMyThread; begin MyWorkerThread := TMyThread.Create(True); MyWorkerThread.FreeOnTerminate := True; MyWorkerThread.SenderHandle := self.Handle; MyWorkerThread.RequestXML := ComposeRequestXML; MyWorkerThread.PResponseXML := ^fWebServiceResponseXML; MyWorkerThread.Resume; end; procedure TMyForm.OnWebServiceCallComplete(var Message: TMessage); begin // Do what you want with the response xml string in fWebServiceResponseXML end; procedure TMyThread.Execute; begin inherited; CoInitialize(nil); try IMyService := IService.GetMyService(URI); ResponseXML := IMyService.Search(RequestXML); PResponseXML := ResponseXML; PostMessage(SenderHandle, WM_WEBSERVCALL_COMPLETE, 0, 0); finally CoUninitialize; end; end;
It works great, but now I want to do the same thing from a datamodule (which doesn't have a Handle)... so I would really appreciate some useful code to supplement the working model I have.
What I really want is the code (if possible) that would allow me to replace the line
MyWorkerThread.SenderHandle := self.Handle;
MyWorkerThread.SenderHandle := GetHandleForThisSOAPDataModule;
I have used this technique before with some success: Sending messages to non-windowed applications
Basically, use a second thread as a message pump on a handle obtained via AllocateHWND. This is admittedly irritating, and you would be better off using a library to handle all the details. I prefer OmniThreadLibrary but there are others - see How Do I Choose Between the Various Ways to do Threading in Delphi? and Delphi - Threading frameworks.