I am trying to convert the following two interfaces from a C header file to a Delphi PAS block, but run into strange problems when using the ones I made myself. I need to help understand how to implement them in Delphi.
Source interfaces from header file c:
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); }
This is my "best effort" so far:
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;
Here is sample code using the DirectShow filter and trying to use the IModuleConfig and IParamConfig interfaces for this object:
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;
Using the debugger, I see that the sample code retrieves the data for both ParamName variables and Value, however, when I try to include the code for storing them in a string list (SL), calling EnumParams will always return S_FALSE (1) and not S_OK (0). If I comment on the line SL.Add (...) and RECOMPILE, it will work again. If I turn it on again, but RECOMPILE does not. This makes me think that at some point something messed up the memory due to the incorrect implementation of these interfaces, and the inclusion of additional code does this.
I am sure that the types that I assigned to the variables are somehow to blame for this, especially the second parameter EnumParams, which should return an array of GUID *. I also very much doubt calling IParamConfig.EnumValidValues, which also returns arrays of values.
I am using Delphi XE2.
Any help on this issue is greatly facilitated.