2012-03-18 13 views
6

Tôi đang cố chuyển đổi hai giao diện sau từ một tệp tiêu đề C thành một đơn vị PAS Delphi nhưng đã gặp phải các vấn đề lạ khi sử dụng những cái tôi đã làm. Tôi cần giúp đỡ hiểu biết làm thế nào để thực hiện chúng trong Delphi.Chuyển đổi giao diện đối tượng COM từ C sang Delphi

giao diện Nguồn từ file c tiêu đề:

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); 
} 

Đây là của tôi "nỗ lực tối đa" cho đến nay:

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; 

Dưới đây là một số mẫu mã sử dụng các bộ lọc DirectShow và cố gắng sử dụng cả Các giao diện IModuleConfig và IParamConfig trên đối tượng đó:

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; 

Sử dụng trình gỡ rối I có thể thấy rằng mã mẫu lấy dữ liệu cả hai biến ParamName và Value, tuy nhiên, khi tôi thử bao gồm mã để lưu chúng vào danh sách chuỗi (SL), lệnh gọi EnumParams sẽ luôn trả về S_FALSE (1) chứ không phải S_OK (0). Nếu tôi nhận xét ra dòng SL.Add (...) và RECOMPILE nó sẽ hoạt động trở lại. Nếu tôi bao gồm nó một lần nữa và RECOMPILE nó sẽ không. Điều này khiến tôi tin rằng có điều gì đó đang làm rối loạn bộ nhớ tại một số thời điểm do việc triển khai không đúng các giao diện này và việc thêm mã bổ sung làm cho nó xảy ra.

Tôi khá chắc chắn rằng các loại tôi đã gán cho các biến là một cách nào đó thủ phạm của điều này, đặc biệt là tham số thứ hai cho EnumParams mà nghĩa vụ phải trả về một mảng GUID *. Tôi cũng rất không chắc chắn về cuộc gọi IParamConfig.EnumValidValues ​​mà cũng trả về mảng các giá trị.

Tôi đang sử dụng Delphi XE2.

Bất kỳ trợ giúp nào về vấn đề này được đánh giá rất cao.

Trả lời

2

Để trả lời câu hỏi này, chắc chắn bạn sẽ cần có tài liệu về giao diện. Chỉ cần biết chữ ký của họ là không bao giờ đủ thông tin. Nếu không có tài liệu đó, chúng tôi phải đưa ra những dự đoán được giáo dục, và vì vậy ở đây sẽ đi.

Hãy tập trung đầu tiên trên EnumParams

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

Lưu ý rằng tham số pNumParams được đánh dấu là đã [in][out]. Tham số khác là một mảng GUID. Rất có thể bạn muốn truyền độ dài mảng của mình làm đầu vào thông qua tham số pNumParams. Điều này cho biết hàm có bao nhiêu mục được an toàn để sao chép. Nếu bạn chuyển một giá trị cho pNumParams không đủ cho toàn bộ mảng thì hàm sẽ chỉ ra rằng trong giá trị trả lại. Khi hàm trả về nó sẽ đặt pNumParams là độ dài thực của mảng. Nhiều khả năng bạn có thể gọi nó là qua 0 cho pNumParams, NULL cho pParamIDs và sử dụng để xác định kích thước của mảng thực sự cần thiết. Đây là một mô hình rất phổ biến, nhưng bạn sẽ cần đọc tài liệu để chắc chắn.

Bây giờ, vì bạn không chỉ định cho NumParams trước khi gọi EnumParams, bạn đang chuyển một giá trị ngẫu nhiên từ ngăn xếp. Thực tế là những thay đổi đối với mã tiếp tục ảnh hưởng đến cách cuộc gọi đến EnumParams hoạt động mạnh mẽ hỗ trợ giả thuyết này.

Với việc triển khai của bạn và giả sử dự đoán của tôi là chính xác, bạn nên đặt NumParams thành 1025 trước khi gọi EnumParams. Tuy nhiên, tôi có lẽ sẽ tránh sử dụng mảng kích thước cố định và phân bổ mảng động. Bạn sẽ cần phải thay đổi định nghĩa của EnumParams để đưa con trỏ đến mục đầu tiên. Tôi sẽ làm điều này cho tất cả các mảng trong giao diện.

Khác với tôi đã nhận thấy rằng bạn có một vài lỗi trong IParamConfig. Chức năng GetVisible nên như thế này:

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

Và bạn sẽ tìm thấy GetParamID thuận tiện hơn bằng văn bản theo cách này:

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

Cảm ơn bạn David! Sử dụng thông tin từ bài đăng của bạn tôi đã quản lý để triển khai đúng giao diện. Tôi có tài liệu cho đối tượng này, nhưng tiếc là nó có bản quyền nên tôi không thể đăng nó ở đây. – TomRay74

+0

Vui vì tôi có thể giúp –

0

Đối với hồ sơ, đây là giao diện hoàn:

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; 

Các mã sau đây cho thấy làm thế nào để gọi và sử dụng giao diện và gọi 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; 

Nếu có ai phát hiện bất kỳ lỗi nào (Tôi chưa thử tất cả các chức năng), vui lòng nhận xét về bài đăng này.

+0

Điều này vẫn gặp phải lỗi cơ bản mà tôi đã mô tả trong câu trả lời của mình. Bạn cần phải khởi tạo NumParams trước khi bạn vượt qua nó. Và bạn đã không sửa GetVisible. Ngoài ra, tham số var là tốt hơn cho NumOfParams tham số hơn đi qua con trỏ. –

+0

Xin chào David, cảm ơn vì đã bình luận lần nữa. Tôi đã cập nhật bài đăng của mình để bao gồm nhận xét của bạn. Tôi hiểu tại sao sử dụng var thay vì truyền con trỏ là tốt hơn. Cảm ơn bạn! – TomRay74

+0

Điều đó trông giống như nó! –