I have the following code which creates an instance of an RemObjects service and makes a call to a .net server
class function TLabelPrintingServiceProxy.GetInstance: ILabelPrintingManager;
var
LRoRemoteService: TRoRemoteService;
begin
LRoRemoteService := TRoRemoteService.Create(nil);
LRoRemoteService.Message := TROSOAPMessage.Create();
LRoRemoteService.Channel := TROIndyHTTPChannel.Create(nil);
LRoRemoteService.Channel.TargetUri := TROUri.Create(ILabelPrintingIntf.LabelPrintingManager_EndPointURI);
Result := (LRoRemoteService as ILabelPrintingManager);
end;
After the call is made the LLabelPrintingManager interface should be released automatically by RemObjects, but it isn’t and leaks the objects used.
I’ve tried on the ReleaseLabelPrintingServiceProxyInstance (code bellow) to release manually all the objects from the service instance, but it’s still leaking
class procedure TLabelPrintingServiceProxy.ReleaseLabelPrintingServiceProxyInstance(aILabelPrintingManagerIntf: ILabelPrintingManager);
var
lProxy: TRoProxy;
begin
lProxy := TROProxy(aILabelPrintingManagerIntf);
TROIndyHTTPChannel(lProxy.__TransportChannel).TargetUri.Free;
// TROIndyHTTPChannel(lProxy.__TransportChannel).Free; this is generating an AV
TRoMessage(lProxy.__Message).free;
TRoRemoteService(aILabelPrintingManagerIntf).Free; end;
I’ve tried to create the call using CoLabelPrintingManager.Create(const aMessage: IROMessage; aTransportChannel: IROTransportChannel) and passing message and channel as interfaced objects but it also leaks. Setting ILabelPrintingManager to nil has also no effect
Result := CoLabelPrintingManager.Create(ILabelPrintingIntf.LabelPrintingManager_EndPointURI);
and make the call to .net service I get the following error:
I want to free the TRoRemoteService instance, but when I’m trying to cast ILabelPrintingManager interface to TRoRemoteService the result is all the time nil.
How can I cast back the proxy interface to TRoRemoteService, so I can release all it’s members?
class function TLabelPrintingServiceProxy.GetInstance: ILabelPrintingManager;
var
lIRoMessage: IRoMessage;
lIRoChannel: IROTransportChannel;
begin
lIRoMessage := TROSOAPMessage.Create();
lIRoChannel := TROIndyHTTPChannel.Create(nil);
TROIndyHTTPChannel(lIRoChannel).TargetUrl := ILabelPrintingIntf.LabelPrintingManager_EndPointURI;
Result := CoLabelPrintingManager.Create(lIRoMessage,lIRoChannel);
end;
try to use this code. here you return TRoRemoteService in GetInstance so no memory leaks should be now
class function TLabelPrintingServiceProxy.GetInstance: TRoRemoteService;
var
LRoRemoteService: TRoRemoteService;
begin
LRoRemoteService := TRoRemoteService.Create(nil);
LRoRemoteService.Message := TROSOAPMessage.Create();
LRoRemoteService.Channel := TROIndyHTTPChannel.Create(nil);
LRoRemoteService.Channel.TargetURL := ILabelPrintingIntf.LabelPrintingManager_EndPointURI;
Result := LRoRemoteService;
end;
try
Result := BinaryArray.Create;
LLabelPrintingManager := TLabelPrintingServiceProxy.GetInstance();
Result.Add((LLabelPrintingManager as ILabelPrintingManager).GetVSSLabelImage(APrintJob));
finally
TLabelPrintingServiceProxy.ReleaseLabelPrintingServiceProxyInstance(LLabelPrintingManager);
end;
class procedure TLabelPrintingServiceProxy.ReleaseLabelPrintingServiceProxyInstance(aILabelPrintingManagerIntf: TRoRemoteService);
begin
aILabelPrintingManagerIntf.Channel.Free;
aILabelPrintingManagerIntf.Message.free;
aILabelPrintingManagerIntf.Free;
end;
destructor TROTransportChannel.Destroy;
begin
...
fTargetUri.Free;
...
end;
You shouldn’t destroy (i.e. TargetUri) internal object because it is destroyed in destructor.
FastMM should display callstack where is leaked TROUri was created.
use TargetURL instead of TargetUri because it does the same as you want:
procedure TROTransportChannel.SetTargetUrl(const aValue: string);
var
lUri: TROUri;
begin
lUri := TROUri.Create(aValue);
try
SetTargetUri(lUri);
finally
lUri.Free;
end;
end;