views:

152

answers:

1

Newbie question: I have a forms application. It has a separate thread which makes a web services call, and then posts the results of the call to the main form.

In my thread, after X seconds have passed (using a TTimer), I call:

procedure TPollingThread.OnTimer(Sender: TObject);
var
SystemProbeValues : TCWProbeValues;  
begin
SystemProbeValues := Remote.Run.GetSystemProbeValues;
PostMessage( ParentHandle, WM_APIEVENT ,Integer(apiMultiCellStatus), Integer(SystemProbeValues) );
end;

The function Remote.Run.GetSystemProbeValues has the following prototype:

function GetSystemProbeValues : TCWProbeValues; stdcall;

And TCWProbeValues is a dynamic array of TCWProbeValue objects (which all descend from TRemotable).

In my main form, I receive the message just fine and cast the LParam back to TCWProbeValues:

procedure TFrmCWMain.OnAPIEvent(var msg: TMessage);
begin
ProbeValues := TCWProbeValues(msg.LParam);
end;

My question is, given that the dynamic array and its objects were created by the Delphi HTTORIO system, who is responsible for freeing them? Did Delphi consider that memory re-usable after my OnTimer function returned? (And in which case, its pure good luck that my main form message handler can actually read the memory referenced by the LParam of the message?) Or rather, is it my responsibility to free the object auto-instantiated by the HTTPRIO request?

Many thanks, please shout if the above needs more detail / code and I'll add to it!

Cheers, Duncan

+2  A: 

TRemotable provides lifetime management via its DataContext property, so the SOAP runtime will free the object itself. As long as the data-context object exists, everything it allocated will exist, too. If you want to claim ownership of and responsibility for an object, simply clear its DataContext property. (That's probably what you'll want to do in this case because your API-event message may get handled after the SOAP event has terminated.)


A problem in your code is that you're passing a dynamic array via a posted message. When your OnTimer procedure returns to its caller, the dynamic array referenced by SystemProbeValues will have its reference count decremented. If the other thread hasn't processed the message yet (and it probably hasn't), then the dynamic array might already be destroyed by the time it does get around to processing that message.

The easy way around that is to clear the reference in the timer's event handler without reducing the reference count, and then do the opposite in the message handler. After you post the message, clear the variable:

LParam(SystemProbeValues) := 0;

In your message handler, clear the old value of the global ProbeValues variable and assign the new value like this:

ProbeValues := nil;
LParam(ProbeValues) := Msg.LParam;

Another problem lurking in your code may be the use of TTimer in a non-VCL thread. That class creates a window handle to share among all instances of the class. Unless your timer thread is the only thread in the program that uses TTimer, you will probably have problems, either with functions running in the wrong thread, or functions not running at all. Instead of TTimer, you can use SetTimer to create an OS timer manually, or you could create a waitable timer, which may be more suitable for use in a thread that doesn't need to remain responsive to user actions.

Rob Kennedy