I have some problem with marshalling and PInvoke I have to develop some kind of driver for existing native application (Oracle Siebel CRM, call center integration interface). Sources of the application is black box from my point of view. Here is the signature of two structures (as defined in API description) and API function which is working with they:
struct ISC_KeyValue /* Key-Value element */
{
ISC_STRING paramName;
ISC_STRING paramValue;
};
struct ISC_KVParamList /* List of Key-Value parameter */
{
struct ISC_KeyValue* dataItems;
long len;
};
ISCAPI ISC_RESULT CreateISCDriverInstance
/* in */(const ISC_STRING mediaTypeStr,
/* in */ const ISC_STRING languageCode,
/* in */ const ISC_STRING connectString,
/* in */ const struct ISC_KVParamList* datasetParams,
/* out */ ISC_DRIVER_HANDLE* handle);
ISC_STRING here is wide character C++ string(2 bytes Unicode). ISC_RESULT is integer value similar to HRESULT type. I have a problem with marshaling of ISC_KVParamList* datasetParams in to CreateISCDriverInstance function and i need help with it.
Here is my vision on how I should marshal this:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct IscKeyValue
{
[MarshalAs(UnmanagedType.LPWStr)]
public string ParamName;
[MarshalAs(UnmanagedType.LPWStr)]
public string ParamValue;
}
[StructLayout(LayoutKind.Sequential)]
public struct IscKvParamList
{
public IntPtr DataItems;
[MarshalAs(UnmanagedType.I4)]
public int Len;
}
And the function itself:
[DllExport("CreateISCDriverInstance", CallingConvention = CallingConvention.StdCall)]
public static int CreateIscDriverInstance([MarshalAs(UnmanagedType.LPWStr)] string mediaTypeStr,
[In,MarshalAs(UnmanagedType.LPWStr)] string languageCode,
[In,MarshalAs(UnmanagedType.LPWStr)] string connectString,
[In, Out] ref IscKvParamList dataParams, [Out] IntPtr handle)
{
var datasetParams =(IscKvParamList)Marshal.PtrToStructure(dataParams,typeof(IscKvParamList));
// Some code here
}
When i'm trying to perform PtrToStructure conversion I get the exception which is saying that "The structure must not be a value class."
Question: How to improve marshalling of dataParams argument
p.s. Additional details : 1. I'm sure that charset is Unicode 2. I do not know the size of array and I cannot marshal it by value. 3. Also, i have example implementation of such driver which was written a long time ago in Delphi:
TNamedParam = record
Name: WideString;
Value: WideString;
end;
TNamedParamList = record
Params: packed array of TNamedParam;
Count: Cardinal;
end;
function CreateISCDriverInstance(const AMediaTypeStr, ALanguageCode, AConnectString: PWideChar; const AParams: TISCNamedParamList; out ADriverHandle: THandle):
HRESULT; begin try ADriverHandle := icISCCommunicationDriver.CreateInstance(AParams).Handle;
Result := SC_EC_OK;
except Result := SC_EC_DRIVER_CREATION_ERR;
end;
end;
And parsing of AParams:
procedure JoinISCNamedParamList(const AParamList: TNamedParamList; var LParamList: TISCNamedParamList);
var i:Integer;
begin
LParamList.Count := AParamList.Count;
SetLength(LParamList.Params, LParamList.Count);
for I := 0 to Pred(AParamList.Count) do
begin
LParamList.Params[i].Name := PWideChar(AParamList.Params[i].Name);
LParamList.Params[i].Value := PWideChar(AParamList.Params[i].Value);
end;
end;
It's possible to say that Layout of structs is Sequential here.