gpt4 book ai didi

delphi - 将 COM 对象接口(interface)从 C 转换为 Delphi

转载 作者:行者123 更新时间:2023-12-03 15:02:09 27 4
gpt4 key购买 nike

我正在尝试将以下两个接口(interface)从 C 头文件转换为 Delphi PAS 单元,但在使用我自己做的接口(interface)时遇到了奇怪的问题。我需要帮助了解如何在 Delphi 中实现这些。

来自 C 头文件的源接口(interface):

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 接口(interface)的示例代码:

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;

使用调试器,我可以看到示例代码将数据检索到 ParamName 和 Value 变量,但是,当我尝试包含代码以将它们存储到字符串列表 (SL) 时,对 EnumParams 的调用将始终返回 S_FALSE (1)而不是 S_OK (0)。如果我注释掉 SL.Add(...) 行并重新编译,它将再次工作。如果我再次包含它并重新编译它就不会了。这让我相信,由于我对这些接口(interface)的错误实现,某些东西在某些时候弄乱了内存,并且包含额外的代码使得这种情况发生。

我非常确定我分配给变量的类型在某种程度上是罪魁祸首,尤其是 EnumParams 的第二个参数,它应该返回 GUID* 数组。我也非常不确定 IParamConfig.EnumValidValues 调用也返回值数组。

我使用的是Delphi XE2。

非常感谢有关此问题的任何帮助。

最佳答案

为了明确地回答这个问题,需要有接口(interface)的文档。仅仅知道他们的签名是不够的。如果没有该文档,我们就必须做出有根据的猜测,所以就这样了。

让我们首先关注EnumParams

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

请注意,pNumParams 参数被标记为 [in][out]。另一个参数是 GUID 数组。最有可能的是,您应该通过 pNumParams 参数将数组的长度作为输入传递。这告诉函数可以安全地复制多少项。如果您传入的 pNumParams 值不足以容纳整个数组,则该函数将在返回值中指出这一点。当函数返回时,它将把pNumParams设置为数组的实际长度。您很可能可以调用它,为 pNumParams 传递 0,为 pParamIDs 传递 NULL 并使用它来确定实际需要的数组。这是一种非常常见的模式,但您需要阅读文档才能确定。

现在,由于您在调用 EnumParams 之前没有分配给 NumParams,因此您正在从堆栈传递一个随机值。事实上,对代码的进一步更改会影响对 EnumParams 的调用方式,这一事实有力地支持了这一假设。

根据您的实现,假设我的猜测是正确的,您应该在调用 EnumParams 之前将 NumParams 设置为 1025。但是,我可能会避免使用固定大小的数组并分配动态数组。您需要更改 EnumParams 的定义以获取指向第一项的指针。我会对界面中的所有数组执行此操作。

除此之外,我确实注意到您在 IParamConfig 中存在一些错误。 GetVisible 函数应如下所示:

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

而且你会发现这样写GetParamID更方便:

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

关于delphi - 将 COM 对象接口(interface)从 C 转换为 Delphi,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9757435/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com