8
votes

I'm working on a Delphi wrapper for the Googledocs api using Delphi XE2. I generated all the classes using the XML Data Binding Wizard. This is a lot easier to explain using code, so here is the function my test calls.

function TGoogleDocsApi.GetEntries : IXMLEntryTypeList;
var
  httpHelper : IHttpHelper;
  xml, url : string;
  xmlDoc : TXmlDocument;
  ss : TStringStream;
  feed : IXmlFeedType;
begin
  ss := TStringStream.Create;
  httpHelper := THttpHelper.Create;
  if(fToken.IsExpired) then
    fToken.Refresh(fClientId,fClientSecret);
  url := BaseUrl + 'feeds/default/private/full?showfolders=true&access_token='+fToken.AccessToken+'&v=3';
  xml := httpHelper.GetResponse(url);
  ss.WriteString(xml);
  ss.Position := 0;
  xmlDoc := TXmlDocument.Create(nil);
  xmlDoc.LoadFromStream(ss);
  feed := GoogleData2.Getfeed(xmlDoc);
  Result := feed.Entry;
end;

Now, at the point that 'end' is hit, Result.ChildNodes has an address in memory and it's count is 20. IXMLEntryTypeList is a child interface of IXMLNodeCollection.

Now here is my test:

procedure TestIGoogleDocsApi.TestGetEntries;
var
  ReturnValue: IXMLEntryTypeList;
begin
  ReturnValue := FIGoogleDocsApi.GetEntries;
  if(ReturnValue = nil) then
    fail('Return value cannot be nil');
  if(ReturnValue.ChildNodes.Count = 0) then
    fail('ChildNodes count cannot be 0');
end;

On the second if statement, I get an access violation saying "Access violation at address 0061A55C in module 'GoogleDocsApiTests.exe'. Read of address 00000049" and when I look at my watches for ReturnValue and ReturnValue.ChildNodes, I see that ReturnValue has the same address as Result did in the TGoogleDocsApi.GetEntries method, but it gives me the access violation on the watch for ReturnValue.ChildNodes and in the TGoogleDocsApi.GetEntires method, Result.ChildNodes has a valid address and its properties are filled out.

To me it looks like Delphi is releasing the ChildNodes property somewhere along the line, but that doesn't make sense to me since ReturnValue should still be referencing it which (I think) should keep it around.

Any ideas what might be going on?

1
Your function leaks ss, but perhaps you simplified the code for this question. Also, what is keeping feed alive when the function returns. Does having taken a reference to feed.Entry keep feed alive? The answer will be along these lines, i.e. In the vein of what @hvd says. You have to keep the necessary objects alive.David Heffernan

1 Answers

21
votes

You're calling TXMLDocument.Create with an Owner of nil. That means its lifetime is controlled via interface reference counting. In order for that to work, you need to actually use interfaces. Change xmlDoc's type to IXMLDocument to maintain a reference, or else something internal to the VCL will free it when you're not expecting it.