2012-03-18 223 views
6

我想將以下兩個接口從C頭文件轉換爲Delphi PAS單元,但在使用我自己做的那些時遇到了奇怪的問題。我需要幫助瞭解如何在Delphi中實現這些。從C頭文件將COM對象接口從C轉換爲Delphi

來源接口:

interface IParamConfig: IUnknown 
{   
    HRESULT SetValue([in] const VARIANT* pValue, [in] BOOL bSetAndCommit); 
    HRESULT GetValue([out] VARIANT* pValue, [in] BOOL bGetCommitted); 
    HRESULT SetVisible(BOOL bVisible); 
    HRESULT GetVisible(BOOL* bVisible); 
    HRESULT GetParamID(GUID* pParamID); 
    HRESULT GetName([out] BSTR* pName); 
    HRESULT GetReadOnly(BOOL* bReadOnly); 
    HRESULT GetFullInfo([out] VARIANT* pValue, [out] BSTR* pMeaning, [out] BSTR* pName, [out] BOOL* bReadOnly, [out] BOOL* pVisible); 
    HRESULT GetDefValue([out] VARIANT* pValue); 
    HRESULT GetValidRange([out] VARIANT* pMinValue, [out] VARIANT* pMaxValue, [out] VARIANT* pDelta); 
    HRESULT EnumValidValues([in][out] long* pNumValidValues, [in][out] VARIANT* pValidValues,[in][out] BSTR* pValueNames); 
    HRESULT ValueToMeaning([in] const VARIANT* pValue, [out] BSTR* pMeaning); 
    HRESULT MeaningToValue([in] const BSTR pMeaning, [out] VARIANT* pValue); 
} 

interface IModuleConfig: IPersistStream 
{ 
    HRESULT SetValue([in] const GUID* pParamID, [in] const VARIANT* pValue); 
    HRESULT GetValue([in] const GUID* pParamID, [out] VARIANT* pValue); 
    HRESULT GetParamConfig([in] const GUID* pParamID, [out] IParamConfig** pValue); 
    HRESULT IsSupported([in] const GUID* pParamID); 
    HRESULT SetDefState(); 
    HRESULT EnumParams([in][out] long* pNumParams, [in][out] GUID* pParamIDs); 
    HRESULT CommitChanges([out] VARIANT* pReason); 
    HRESULT DeclineChanges(); 
    HRESULT SaveToRegistry([in] HKEY hKeyRoot, [in] const BSTR pszKeyName, [in] const BOOL bPreferReadable); 
    HRESULT LoadFromRegistry([in] HKEY hKeyRoot, [in] const BSTR pszKeyName, [in] const BOOL bPreferReadable); 
    HRESULT RegisterForNotifies([in] IModuleCallback* pModuleCallback); 
    HRESULT UnregisterFromNotifies([in] IModuleCallback* pModuleCallback); 
} 

這是我的「盡力而爲」到目前爲止:

type 
    TWideStringArray = array[0..1024] of WideString; 
    TOleVariantArray = array[0..1024] of OleVariant; 
    TGUIDArray = array[0..1024] of TGUID; 

    IParamConfig = interface(IUnknown) 
    ['{486F726E-5043-49B9-8A0C-C22A2B0524E8}'] 
    function SetValue(const pValue: OleVariant; bSetAndCommit: BOOL): HRESULT; stdcall; 
    function GetValue(out pValue: OleVariant; bGetCommitted: BOOL): HRESULT; stdcall; 
    function SetVisible(bVisible: BOOL): HRESULT; stdcall; 
    function GetVisible(bVisible: BOOL): HRESULT; stdcall; 
    function GetParamID(pParamID: PGUID): HRESULT; stdcall; 
    function GetName(out pName: WideString): HRESULT; stdcall; 
    function GetReadOnly(bReadOnly: BOOL): HRESULT; stdcall; 
    function GetFullInfo(out pValue: OleVariant; out pMeaning: WideString; out pName: WideString; out pReadOnly: BOOL; out pVisible: BOOL): HRESULT; stdcall; 
    function GetDefValue(out pValue: OleVariant): HRESULT; stdcall; 
    function GetValidRange(out pMinValue: OleVariant; out pMaxValue: OleVariant; out pDelta: OleVariant): HRESULT; stdcall; 
    function EnumValidValues(var pNumValidValues: Integer; var pValidValues: TOleVariantArray; var pValueNames: TWideStringArray): HRESULT; stdcall; 
    function ValueToMeading(const pValue: OleVariant; out pMeaning: WideString): HRESULT; stdcall; 
    function MeaningToValue(const pMeaning: WideString; out pValue: OleVariant): HRESULT; stdcall; 
    end; 

    IModuleConfig = interface(IPersistStream) 
    ['{486F726E-4D43-49B9-8A0C-C22A2B0524E8}'] 
    function SetValue(const pParamID: TGUID; const pValue: OleVariant): HRESULT; stdcall; 
    function GetValue(const pParamID: TGUID; out pValue: OleVariant): HRESULT; stdcall; 
    function GetParamConfig(const ParamID: TGUID; out pValue: IParamConfig): HRESULT; stdcall; 
    function IsSupported(const pParamID: TGUID): HRESULT; stdcall; 
    function SetDefState: HRESULT; stdcall; 
    function EnumParams(var pNumParams: Integer; var pParamIDs: TGUIDArray): HRESULT; stdcall; 
    function CommitChanges(out pReason: OleVariant): HRESULT; stdcall; 
    function DeclineChanges: HRESULT; stdcall; 
    function SaveToRegistry(hKeyRoot: HKEY; const pszKeyName: WideString; const bPreferReadable: BOOL): HRESULT; stdcall; 
    function LoadFromRegistry(hKeyRoot: HKEY; const pszKeyName: WideString; const bPreferReadable: BOOL): HRESULT; stdcall; 
    function RegisterForNotifies(pModuleCallback: IModuleCallback): HRESULT; stdcall; 
    function UnregisterFromNotifies(pModuleCallback: IModuleCallback): HRESULT; stdcall; 
    end; 

下面是使用DirectShow過濾器,並試圖同時使用一些示例代碼該對象上的IModuleConfig和IParamConfig接口:

procedure TForm10.Button1Click(Sender: TObject); 
const 
    CLSID_VideoDecoder: TGUID = '{C274FA78-1F05-4EBB-85A7-F89363B9B3EA}'; 
var 
    HR: HRESULT; 
    Intf: IUnknown; 
    NumParams: Long; 
    I: Integer; 
    ParamConfig: IParamConfig; 
    ParamName: WideString; 
    Value: OleVariant; 
    ValAsString: String; 
    Params: TGUIDArray; 
begin 
    CoInitializeEx(nil, COINIT_MULTITHREADED); 
    try 
    HR := CoCreateInstance(CLSID_VideoDecoder, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IUnknown, Intf); 
    if Succeeded(HR) then 
    begin 
     FVideoDecoder := Intf as IBaseFilter; 

     if Supports(FVideoDecoder, IID_IModuleConfig) then 
     begin 
     HR := (FVideoDecoder as IModuleConfig).EnumParams(NumParams, Params); 
     if HR = S_OK then 
     begin 
      for I := 0 to NumParams - 1 do 
      begin 
      HR := (FVideoDecoder as IModuleConfig).GetParamConfig(Params[I], ParamConfig); 
      if HR = S_OK then 
      begin 
       try 
       ParamConfig.GetName(ParamName); 
       ParamConfig.GetValue(Value, True); 
       try 
        ValAsString := VarToStrDef(Value, 'Error'); 
        SL.Add(String(ParamName) + '=' + String(ValAsString)); // <-- ADDING THIS LINE WILL ALWAYS MAKE EnumParams call return S_FALSE = 1 
       except 
       end; 
       finally 
       ParamConfig := nil; 
       end; 
      end; 
      end; 
     end; 
     end; 
    end; 
    finally 
    CoUninitialize; 
    end; 
end; 

使用調試器I可以看到示例代碼都檢索到ParamName和Value變量的數據,但是,當我嘗試將代碼存儲到字符串列表(SL)時,對EnumParams的調用將始終返回S_FALSE(1)而不是S_OK(0)。如果我註釋掉SL.Add(...)和RECOMPILE行,它將再次起作用。如果我再次包含它,並且RECOMPILE它不會。這讓我相信,由於我錯誤地實現了這些接口,某些事情正在搞亂內存,並且包含額外的代碼使得它發生。

我非常確定我分配給變量的類型在某種程度上是這個的罪魁禍首,尤其是EnumParams的第二個參數,它應該返回一個GUID *數組。我也很不確定IParamConfig.EnumValidValues調用是否也返回值的數組。

我正在使用Delphi XE2。

在這個問題上的任何幫助是非常appreaciated。

回答

2

爲了回答這個問題,肯定需要有接口的文檔。只知道他們的簽名是永遠不夠的信息。沒有這些文件,我們必須做出有根據的猜測,所以這裏就是了。

讓我們把重點先對EnumParams

HRESULT EnumParams([in][out] long* pNumParams, [in][out] GUID* pParamIDs); 

注意,pNumParams參數被標記爲已[in][out]。另一個參數是一個GUID數組。很可能你打算通過參數pNumParams來傳遞數組長度。這告訴功能有多少項目是它安全的複製。如果您傳遞的值不足pNumParams,那麼該函數將在返回值中指示該值。當函數返回時,它會將pNumParams設置爲數組的實際長度。很有可能你可以稱它爲pNumParams,NULLpParamIDs,通過0並用它來確定實際需要的數組大小。這是一種非常常見的模式,但您需要閱讀文檔以確保。

現在,由於您在調用EnumParams之前未分配給NumParams,所以您正在傳遞堆棧中的隨機值。對代碼的更改進一步影響了對EnumParams的調用行爲的行爲方式的強烈支持這一假設的事實。

隨着您的實施,並假設我的猜測是正確的,您應在撥打EnumParams之前將NumParams設置爲1025。但是,我可能會避免使用固定大小的數組並分配動態數組。您需要更改EnumParams的定義以獲取指向第一項的指針。我會爲界面中的所有數組執行此操作。

除此之外,我確實注意到你在IParamConfig有幾個錯誤。該GetVisible功能應該是這樣的:

function GetVisible(var bVisible: BOOL): HRESULT; stdcall; 

而且你會發現GetParamID更方便這樣寫的:

function GetParamID(var pParamID: TGUID): HRESULT; stdcall; 
+0

謝謝大衛!使用您發佈的信息,我確實設法正確地實現了界面。我有這個對象的文檔,但不幸的是它的版權,所以我不能在這裏發佈。 – TomRay74 2012-03-18 16:47:39

+0

很高興能幫助 – 2012-03-18 16:52:39

0

根據記錄,這是完整的接口:

IParamConfig = interface(IUnknown) 
    ['{486F726E-5043-49B9-8A0C-C22A2B0524E8}'] 
    function SetValue(const pValue: OleVariant; bSetAndCommit: BOOL): HRESULT; stdcall; 
    function GetValue(out pValue: OleVariant; bGetCommitted: BOOL): HRESULT; stdcall; 
    function SetVisible(bVisible: BOOL): HRESULT; stdcall; 
    function GetVisible(var bVisible: BOOL): HRESULT; stdcall; 
    function GetParamID(out pParamID: TGUID): HRESULT; stdcall; 
    function GetName(out pName: WideString): HRESULT; stdcall; 
    function GetReadOnly(bReadOnly: BOOL): HRESULT; stdcall; 
    function GetFullInfo(out pValue: OleVariant; out pMeaning: WideString; out pName: WideString; out pReadOnly: BOOL; out pVisible: BOOL): HRESULT; stdcall; 
    function GetDefValue(out pValue: OleVariant): HRESULT; stdcall; 
    function GetValidRange(out pMinValue: OleVariant; out pMaxValue: OleVariant; out pDelta: OleVariant): HRESULT; stdcall; 
    function EnumValidValues(pNumValidValues: PInteger; pValidValues: POleVariant; pValueNames: PWideString): HRESULT; stdcall; 
    function ValueToMeaning(const pValue: OleVariant; out pMeaning: WideString): HRESULT; stdcall; 
    function MeaningToValue(const pMeaning: WideString; out pValue: OleVariant): HRESULT; stdcall; 
    end; 

    IModuleConfig = interface(IPersistStream) 
    ['{486F726E-4D43-49B9-8A0C-C22A2B0524E8}'] 
    function SetValue(const pParamID: TGUID; const pValue: OleVariant): HRESULT; stdcall; 
    function GetValue(const pParamID: TGUID; out pValue: OleVariant): HRESULT; stdcall; 
    function GetParamConfig(const ParamID: TGUID; out pValue: IParamConfig): HRESULT; stdcall; 
    function IsSupported(const pParamID: TGUID): HRESULT; stdcall; 
    function SetDefState: HRESULT; stdcall; 
    function EnumParams(var pNumParams: Integer; pParamIDs: PGUID): HRESULT; stdcall; 
    function CommitChanges(out pReason: OleVariant): HRESULT; stdcall; 
    function DeclineChanges: HRESULT; stdcall; 
    function SaveToRegistry(hKeyRoot: HKEY; const pszKeyName: WideString; const bPreferReadable: BOOL): HRESULT; stdcall; 
    function LoadFromRegistry(hKeyRoot: HKEY; const pszKeyName: WideString; const bPreferReadable: BOOL): HRESULT; stdcall; 
    function RegisterForNotifies(pModuleCallback: IModuleCallback): HRESULT; stdcall; 
    function UnregisterFromNotifies(pModuleCallback: IModuleCallback): HRESULT; stdcall; 
    end; 

以下代碼顯示如何調用和使用該接口並調用EnumParams:

procedure TForm10.ListAllParameters(Sender: TObject); 
const 
    CLSID_VideoDecoder: TGUID = '{C274FA78-1F05-4EBB-85A7-F89363B9B3EA}'; 
var 
    HR: HRESULT; 
    Intf: IUnknown; 
    ModuleConfig: IModuleConfig; 
    ParamConfig: IParamConfig; 
    NumParams: Integer; 
    ParamGUIDS: array of TGUID; 
    GUID: TGUID; 
begin 
    HR := CoCreateInstance(CLSID_VideoDecoder, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IUnknown, Intf); 
    try 
    if not Succeeded(HR) then Exit; 

    if Supports(Intf, IID_IModuleConfig) then ModuleConfig := (Intf as IModuleConfig) else Exit; 

    // Get number of parameters 
    NumParams := 0; 
    HR := ModuleConfig.EnumParams(NumParams, nil); 
    if HR = S_FALSE then 
    begin 
     // Set the lenght of the array of TGUIDS to match the number of parameters 
     SetLength(ParamGUIDS, NumParams); 
     // Use a pointer to the first TGUID of the array as the parameter to EnumParams 
     HR := ModuleConfig.EnumParams(NumParams, @ParamGUIDS[0]); 
     if HR = S_OK then 
     begin 
     for GUID in ParamGUIDS do Memo1.Lines.Add(GUIDToString(GUID)); 
     end else Exit; 
    end else Exit; 
    finally 
    ModuleConfig := nil; 
    Intf := nil; 
    end; 
end; 

如果有人發現任何錯誤(我還沒有嘗試過所有的功能),請評論這篇文章。

+0

這仍然患有我在我的回答中描述的基本錯誤。在傳遞它之前,您需要初始化NumParams。並且您沒有糾正GetVisible。另外,對於NumOfParams參數,var參數比傳遞指針要好。 – 2012-03-18 19:21:41

+0

嗨大衛,再次感謝您的評論。我已更新我的帖子以包含您的評論。我現在明白爲什麼使用var而不是傳遞指針更好。謝謝! – TomRay74 2012-03-19 00:03:01

+0

看起來更像它! – 2012-03-19 07:25:13

相關問題