疑难解答COM错误“参数不正确” [英] Troubleshooting COM error "The parameter is incorrect"

查看:371
本文介绍了疑难解答COM错误“参数不正确”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

环境是Delphi XE2 Enterprise。



关于在Delphi中使用dispInterface,没有classid 。重新发布为一个不同的问题,因为我已经超越了以前的问题(感谢@EricBrown),现在有一个更具体的问题。



我有一个.NET dll与COM接口,我已在计算机上注册,并作为类型库导入到Delphi。我使用Delphi创建的tlb.pas文件。



使用我在IDispatch接口和TAutoIntf后代类中实现的几个dispInterfaces,成功地初始化了我需要在COM接口中调用方法到.NET库的类和接口。下面是一些代码来说明声明/实现:

  // COM事件接收器GUID 
DIID_IResponseListener:TGUID = {ABC29F08-B628-4747-BA9E-469D408E57B9}';

// **************************************** ***************************** //
// DispIntf:IResponseListener
//标志:(4096 )可分派
// GUID:{ABC29F08-B628-4747-BA9E-469D408E57B9}
// *********************** ********************************************** //
IResponseListener = dispinterface
['{ABC29F08-B628-4747-BA9E-469D408E57B9}']
过程RequestCompleted(const requestID:WideString; const responseObj:IResponse); dispid 1610744833;
procedure RequestFailed(const requestID:WideString; const error:WideString); dispid 1610744834;
procedure TablesUpdates(const responseObj:IResponse); dispid 1610744835;
end;

...我的实现:
IFXResponseListener = interface(IDispatch)
['{3204D3F7-5DF2-4470-89D5-D34F4F6F0381}']
过程RequestCompleted const requestID:WideString; const responseObj:IResponse); dispid 1610744833;安全报
procedure RequestFailed(const requestID:WideString; const error:WideString); dispid 1610744834;安全报
procedure TablesUpdates(const responseObj:IResponse); dispid 1610744835;安全报
end;

TFXResponseListener = class(TAutoIntfObject,IFXResponseListener)
private
FDisp:IDispatch;
FResp:IResponse;
function GetResponseListIntf:IResponseListener;
public
constructor创建;
destructor Destroy;
published
procedure RequestCompleted(const requestID:WideString; const responseObj:IResponse);安全报
procedure RequestFailed(const requestID:WideString; const error:WideString);安全报
procedure TablesUpdates(const responseObj:IResponse);安全报
属性ResponseObj:IResponse read FResp;
属性ListenerDispIntf:IResponseListener read GetResponseListIntf;
end;

...

{TFXResponseListener}


构造函数TFXResponseListener.Create;
var
TypeLib:ITypeLib;
begin
OleCheck(LoadRegTypeLib(LIBID_fxcore2_com,fxcore2_comMajorVersion,fxcore2_comMinorVersion,0,TypeLib));
inherited Create(TypeLib,DIID_IResponseListener);
end;

destructor TFXResponseListener.Destroy;
begin
inherited;
end;

function TFXResponseListener.GetResponseListIntf:IResponseListener;
begin
FDisp:= Self as IFXResponseListener;
FDisp._AddRef;
结果:= IResponseListener(FDisp);
end;

procedure TFXResponseListener.RequestCompleted(const requestID:WideString; const responseObj:IResponse);
begin
showmessage('Completed:'+ requestID);
FResp:= responseObj;
end;

procedure TFXResponseListener.RequestFailed(const requestID:WideString; const error:WideString);
begin
showmessage('Failed:'+ requestID);
end;

procedure TFXResponseListener.TablesUpdates(const responseObj:IResponse);
begin
showmessage('TablesUpdates');
end;

这是我尝试使用界面的地方:

  FRespList:= TFXResponseListener.Create; 
try
FSess.subscribeResponse(FRespList.ListenerDispIntf);
except
//错误在这里与'参数不正确'
end;

跟踪到System.Win.ComObj的第1793行,它调用:

  Status:= Dispatch.Invoke(DispID,GUID_NULL,0,InvKind,DispParams,Result,@ExcepInfo,nil); 



此时,DispID参数有效(1610743816),GUID_NULL为'(0, 0,(0,0,0,0,0,0,0,0))',InvKind为'1',DispParams为'($ 2152FE8,nil,1,0)',结果为'$ 12FE24' @ExcepInfo是'$ 12FDE0'。



在System.pas第30133行中,TInterfacedObject.QueryInterface被调用两次。在第二次运行它返回结果'E_NOINTERFACE',并出现了可怕的'参数不正确'消息。



我真的不知道从哪里去,但我希望COM专家和/或Delphi专家可以审查这个和看到什么东西。



我也想知道是否有一个.NET框架版本或其他问题。我使用框架版本4.5.1;不知道如何确定.NET组件是否是这个版本的框架的犹太教,或者如果它真的需要一个早期版本。



任何相关的.NET / COM调试技术将非常感谢。



这个问题与一个不同的dispinterface / IDispatch / TAutoIntfObj后代类和类似的调用,相同的一个'T'。



谢谢。

解决方案

看起来这个是在包里。感谢@EricBrown和@RemyLebeau,我能够让这个工作。



Remy的建议改变FRespList的实例化:

  var 
FRespList:TFXResponseListener;

到:

 code> var 
FRespList:IFXResponseListener;

...所以当我实例化使用

  FRespList:= TFXResponseListener.Create; 

...我得到正确的结果,一切都很胖,



我还需要指出,分配给dispinterface的GUID必须用于我创建的IDispatch接口后代,否则我们回到'参数不正确。



也有点奇怪,当我完成了我的IDispatch后代我没有它。这会将TAutoIntfObject后代的引用计数减少为 2 。这会导致内存泄漏。我测试和尝试不同的事情,以获得这个引用计数,最终不得不做一些奇怪:

  **过程** TMyClass 。破坏; //<  - 从** destructor **改变TMyClass.Destroy; 
begin
inherited; //< - 不得不调用这个!
// then ...
while Self.RefCount> 0 do
IUnknown(Self)._ Release;
end;

...然后调用MyClassInstance.Destroy;



如果有人知道为什么我有3个引用我的类,为什么FreeAndNil(MyClassInstance)和IMyClass:= Nil;离开引用计数2与访问违反和/或内存泄漏,为什么我不得不摧毁继承的第一,为什么我必须类型转换类作为IUnknown和手动释放实例,请大声说。



在另一个接口/类对上,我仍然从TServerEventDispatch获取一个mem泄漏。这是Delphi在tlb.pas文件中自动创建的类之一。如果有人有建议...



我'



所以...谢谢你!


Environment is Delphi XE2 Enterprise.

Relates to use dispInterface in Delphi with no classid. Re-posting as a different question as I have moved well beyond the previous issues (thanks to @EricBrown) and now have a more specific problem.

I've got a .NET dll with a COM interface that I've registered on the computer and have imported as a type library into Delphi. I'm using the tlb.pas file that Delphi created.

Working with a couple of dispInterfaces that I've implemented in IDispatch interfaces and TAutoIntf descendant classes, I've successfully initialized the classes and interfaces that I need to call methods in the COM interface to the .NET library. Here is some code to illustrate the declaration/implementation:

// COM Event Sink GUID
DIID_IResponseListener: TGUID = '{ABC29F08-B628-4747-BA9E-469D408E57B9}';

// *********************************************************************//
// DispIntf:  IResponseListener
// Flags:     (4096) Dispatchable
// GUID:      {ABC29F08-B628-4747-BA9E-469D408E57B9}
// *********************************************************************//
  IResponseListener = dispinterface
    ['{ABC29F08-B628-4747-BA9E-469D408E57B9}']
    procedure RequestCompleted(const requestID: WideString; const responseObj: IResponse); dispid 1610744833;
    procedure RequestFailed(const requestID: WideString; const error: WideString); dispid 1610744834;
    procedure TablesUpdates(const responseObj: IResponse); dispid 1610744835;
 end;

...my implementation:
  IFXResponseListener = interface(IDispatch)
['{3204D3F7-5DF2-4470-89D5-D34F4F6F0381}']
    procedure RequestCompleted(const requestID: WideString; const responseObj: IResponse); dispid 1610744833; safecall;
    procedure RequestFailed(const requestID: WideString; const error: WideString); dispid 1610744834; safecall;
    procedure TablesUpdates(const responseObj: IResponse); dispid 1610744835; safecall;
  end;

  TFXResponseListener = class(TAutoIntfObject,IFXResponseListener)
  private
    FDisp: IDispatch;
    FResp: IResponse;
    function GetResponseListIntf: IResponseListener;
  public
    constructor Create;
    destructor Destroy;
  published
    procedure RequestCompleted(const requestID: WideString; const responseObj: IResponse); safecall;
    procedure RequestFailed(const requestID: WideString; const error: WideString); safecall;
    procedure TablesUpdates(const responseObj: IResponse); safecall;
    property ResponseObj: IResponse read FResp;
    property ListenerDispIntf: IResponseListener read GetResponseListIntf;
  end;

...

{ TFXResponseListener }


constructor TFXResponseListener.Create;
var
  TypeLib: ITypeLib;
begin
  OleCheck(LoadRegTypeLib(LIBID_fxcore2_com,fxcore2_comMajorVersion,fxcore2_comMinorVersion,0,TypeLib));
  inherited Create(TypeLib,DIID_IResponseListener);
end;

destructor TFXResponseListener.Destroy;
begin
  inherited;
end;

function TFXResponseListener.GetResponseListIntf: IResponseListener;
begin
  FDisp := Self as IFXResponseListener;
  FDisp._AddRef;
  Result := IResponseListener(FDisp);
end;

procedure TFXResponseListener.RequestCompleted(const requestID: WideString; const responseObj: IResponse);
begin
  showmessage('Completed: ' + requestID);
  FResp := responseObj;
end;

procedure TFXResponseListener.RequestFailed(const requestID: WideString; const error: WideString);
begin
  showmessage('Failed: ' + requestID);
end;

procedure TFXResponseListener.TablesUpdates(const responseObj: IResponse);
begin
  showmessage('TablesUpdates');
end;

Here is where I attempt to use the interface:

FRespList := TFXResponseListener.Create;
  try
    FSess.subscribeResponse(FRespList.ListenerDispIntf);
  except
    // errors out here with 'The parameter is incorrect'
  end;

Tracing this down into the bowels of System.Win.ComObj, at line 1793 it calls:

Status := Dispatch.Invoke(DispID, GUID_NULL, 0, InvKind, DispParams, Result, @ExcepInfo, nil);

At this point, the DispID parameter is valid (1610743816), GUID_NULL is '(0, 0, 0, (0, 0, 0, 0, 0, 0, 0, 0))', InvKind is '1', DispParams is '($2152FE8, nil, 1, 0)', Result is '$12FE24', @ExcepInfo is '$12FDE0'.

In System.pas, line 30133, TInterfacedObject.QueryInterface is called twice. On the second run it returns the result 'E_NOINTERFACE', and the dreaded 'The parameter is incorrect' message appears.

I'm really not sure where to go from here, but I'm hoping a COM expert and/or Delphi expert can review this and see something amiss.

I'm also wondering if there is a .NET framework version or other issue. I'm using framework version 4.5.1; not sure how to determine if the .NET assembly is kosher with this version of the framework or if it really needs an earlier version.

Any relevant .NET/COM debugging techniques would be greatly appreciated.

Also please note, I can duplicate this issue with a different dispinterface/IDispatch/TAutoIntfObj descendant class and similar call, identical to a 'T'.

Thanks.

解决方案

Looks like this one is in the bag. Thanks to @EricBrown and @RemyLebeau, I was able to get this to work.

Remy's suggestion of changing the instantiation of FRespList from:

var
  FRespList: TFXResponseListener;

to:

var 
  FRespList: IFXResponseListener;

...did the trick. So when I instantiate using

FRespList := TFXResponseListener.Create;

...I get the right result, and everything is fat, dumb and happy.

Also I need to point out that the GUID that is assigned to the dispinterface has to be used for the IDispatch interface descendant that I created, otherwise, we're back to 'The parameter is incorrect.'. Wonder if that's documented somewhere...

Also kind of weird, when I'm done with my IDispatch descendant I nil it. That reduces the refcount on the TAutoIntfObject descendant to 2. Which results in a memory leak. I tested and tried different things to get this refcount to dec, finally had to do some weirdness:

**procedure** TMyClass.Destroy; // <- changed from **destructor** TMyClass.Destroy;
begin
  inherited Destroy; // <- had to call this first!
  // then...
  while Self.RefCount > 0 do
    IUnknown(Self)._Release;
end;

...and then call MyClassInstance.Destroy; to get the class to free without AV's nor mem leaks.

If anyone knows why I had 3 references to my class, why FreeAndNil(MyClassInstance) and IMyClass := Nil; leaves a refcount of 2 with an Access Violation and/or a memory leak, why I had to destroy the inherited first, why I had to typecast the class as an IUnknown and manually release the instances, please speak up.

On another interface/class pair I still get a mem leak from TServerEventDispatch. This is one of the classes that Delphi auto-created in the tlb.pas file. If anyone has a suggestion...

COM... ya' gotta love it!

I'd like to give any points to both Eric Brown and Remy Lebeau, but I don't know how.

So... THANKS GUYS!

这篇关于疑难解答COM错误“参数不正确”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆