I am trying to convert the following two interfaces from a C header file to a Delphi PAS unit but have run into strange problems when using the ones I did myself. I need help understanding how to implement these in Delphi.
Source interfaces from c header file:
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 some sample code using the DirectShow filter and trying to use both the IModuleConfig and IParamConfig interfaces on that 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 can see that the sample code retrieves data both to the ParamName and Value variables, however, when I try include code to store them to the stringlist (SL) the call to EnumParams will always return S_FALSE (1) and not S_OK (0). If I comment out the line SL.Add(...) and RECOMPILE it will work again. If I include it again and RECOMPILE it won't. This leads me to believe that something is messing up the memory at some point due to my incorrect implementation of these interfaces, and the inclusion of the extra code makes it happen.
I am pretty sure that the types I have assigned to the variables are in some way the culprit of this, especially the second parameter to EnumParams which is supposed to return an array of GUID*. I am also very uncertain about the IParamConfig.EnumValidValues call which is also returning arrays of values.
I am using Delphi XE2.
Any help on this issue is greatly appreaciated.