2014-02-11 39 views
0

環境是Delphi XE2 Enterprise。排除COM錯誤「參數不正確」

有關use dispInterface in Delphi with no classid。重新發布作爲一個不同的問題,因爲我已經超越了以前的問題(感謝@EricBrown),現在有一個更具體的問題。

我有一個.NET的DLL,我已經註冊在計算機上的COM接口,並已作爲類型庫導入到Delphi中。我正在使用Delphi創建的tlb.pas文件。

使用我在IDispatch接口和TAutoIntf後代類中實現的一對dispInterfaces,我已經成功地初始化了我需要調用.NET庫的COM接口中的方法的類和接口。下面是一些代碼來說明申報/實施:

// 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; 

這裏是我嘗試使用該接口:

FRespList := TFXResponseListener.Create; 
    try 
    FSess.subscribeResponse(FRespList.ListenerDispIntf); 
    except 
    // errors out here with 'The parameter is incorrect' 
    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,0 ))',InvKind是'1',DispParams是'($ 2152FE8,零,1,0)',Resul t是'$ 12FE24',@ExcepInfo是'$ 12FDE0'。

在System.pas,行30133中,TInterfacedObject.QueryInterface被調用兩次。在第二次運行中,它返回結果'E_NOINTERFACE',並顯示可怕的'The parameter is incorrect'信息。

我真的不確定該從哪裏出發,但我希望COM專家和/或Delphi專家可以檢查這一點,並看到一些不妥之處。

我也想知道是否有一個.NET框架版本或其他問題。我正在使用框架版本4.5.1;不確定如何確定.NET程序集是否與此版本的框架兼容,或者它確實需要更早的版本。

任何相關的.NET/COM調試技術將不勝感激。

另請注意,我可以用不同的調度接口/ IDispatch/TAutoIntfObj後代類和類似的調用複製此問題,與'T'相同。

謝謝。

+0

什麼是FRespList聲明爲? 'FSess.subscribeResponse()'? QueryInterface()在返回E_NOINTERFACE時被詢問是什麼?這個guid是一個標準的guid還是定義在類型庫中?另外,'TFXResponseListener.GetResponseListIntf()'的實現看起來對我來說是非常可疑的,你創建了那個還是讓Delphi自動生成它? –

+0

FRespList被聲明爲TFXResponseListener。 FSess是來自類型庫的ISession接口。 Session subscribeResponse過程接受一個參數,一個被定義爲dispInterface的IResponseListener。 TFXResponseListener.GetResponseListIntf是我定義的東西,就像所有的TFXResponseListener類和IFXResponseListener接口一樣。 QueryInterface正在測試:(3288121758,43376,4562,(139,90,0,160,201,183,201,196))',我不知道如何將它轉換爲GUID。 – DeCoder

+0

奇怪的是它碰到了兩次TInterfacedObject.QueryInterface。第一次被稱爲IID是'(0,0,0,(192,0,0,0,0,0,0,70))。第二個電話是上面列出的接口。在追蹤中,它是對subscribeResponse(IResponseListener)的調用,導致對QueryInterface的2次調用。在第一次調用時返回-0-(成功?)的結果 – DeCoder

回答

0

看起來像這個在袋子裏。感謝@EricBrown和@RemyLebeau,我能夠得到這個工作。

雷米的更改FRespList的實例化的建議:

var 
    FRespList: TFXResponseListener; 

到:

var 
    FRespList: IFXResponseListener; 

...做的伎倆。所以,當我使用實例

FRespList := TFXResponseListener.Create; 

...我得到正確的結果,一切都是脂肪,啞和快樂。

另外我需要指出的是,分配給調度接口的GUID必須用於我創建的IDispatch接口後代,否則,我們又回到'The parameter is incorrect。'。不知道這是否記錄在某處...

也有點奇怪,當我完成我的IDispatch後裔我零。這將TAutoIntfObject後裔的計數減少到。這會導致內存泄漏。我測試和嘗試不同的東西,得到這個引用計數至十二月,最後不得不做了一些怪事:

**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; 

...,然後調用MyClassInstance.Destroy;在沒有AV或mem泄漏的情況下讓課程免費。

如果有人知道爲什麼我有3個引用我的類,爲什麼FreeAndNil(MyClassInstance)和IMyClass:=無;爲什麼我必須首先銷燬繼承的,爲什麼我必須將類作爲IUnknown進行類型化並手動釋放實例,請說出來。

在另一個接口/類對,我仍然從TServerEventDispatch得到一個mem泄漏。這是Delphi在tlb.pas文件中自動創建的類之一。如果有人有一個建議... ...

COM ...亞'一定要喜歡它!

我想給埃裏克布朗和雷米Lebeau任何點,但我不知道如何。

所以......謝謝你!

相關問題