我一直在努力研究如何将这个VB6代码迁移到C#中。它涉及调用DLL中的函数,传递结构数组等等。
所以在VB6中," struct"声明是这样的:
'Define structure for RGETDAT_STR procedure call
Type rgetdat_str_data_str
type As Integer 'data type (set internally)
file As Integer 'file in database
rec As Integer 'record in file
word As Integer 'word offset in record
start_bit As Integer 'UNUSED
length As Integer 'length of string
flags As Integer 'flags
padding1 As Integer 'UNUSED
value As String 'database value
status As Integer 'return status
padding2 As Integer 'UNUSED
End Type
和一个使用此" struct"的函数有一个声明为此的方法:
Public Declare Function rgetdat_str Lib "hscnetapi.dll" _
Alias "rgetdat_str_vb" _
(ByVal Server As String, ByVal num_points As Integer, _
getdat_str_data() As rgetdat_str_data_str) As Integer
所以,我试图将这两段代码转换为C#。我尝试了很多变化,但我会在这里发布最新的变体。我们的想法是通过P/Invoke调用该函数。
C#struct(到目前为止):
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct rgetdat_str_data_str
{
public short type;
public short file;
public short rec;
public short word;
public short start_bit;
public short length;
public short flags;
public short padding1;
[MarshalAs(UnmanagedType.LPStr)]
public string value;
public short status;
public short padding2;
}
和函数import(到目前为止):
[DllImport("hscnetapi.dll", EntryPoint = "rgetdat_str_vb")]
public static extern short rgetdat_str(
[MarshalAs(UnmanagedType.LPTStr)]
string Server,
short num_points,
[In,Out, MarshalAs(UnmanagedType.LPArray)]
ref rgetdat_str_data_str[] getdat_str_data);
到目前为止,在我使用参数编组属性的各种实验中没有任何工作。
我设法找到了这个DLL的C头文件,声明如下:
EXTERN_C short __loadds CALLBACK rgetdat_str_vb_ansi
_DECLARE((char *szHostname, short cRequests, SAFEARRAY **ppsa));
和" struct"在C世界中声明如下:
/* define union used in rgetdat_value in RGETDAT procedure call */
typedef union rgetdat_value_str
{
n_short int2;
n_long int4;
n_float real4;
n_double real8;
n_char *str;
n_ushort bits;
} rgetdat_value;
/* define structure for RGETDAT procedure call */
typedef struct rgetdat_data_str
{
n_ushort type;
n_ushort file;
n_ushort rec;
n_ushort word;
n_ushort start_bit;
n_ushort length;
n_short flags;
rgetdat_value value;
n_short status;
} rgetdat_data;
令我沮丧的是,我尝试使用 ITypeLib Viewer 工具打开此DLL。我很惊讶DLL文件可以打开,即使我无法在我的项目中添加此DLL作为参考。无论如何,我在观众中观察到了一些事情。
该功能具有此签名:
[entry("rgetdat_str_vb"), helpstring("...")]
short _stdcall rGetdat_Str(
[in] LPSTR Server,
[in] short num_points,
[in, out] SAFEARRAY(rGetdat_Str_Data_Str)* getdat_str_data);
和" struct"看起来像这样:
typedef struct tagrGetdat_Str_Data_Str {
short type;
short file;
short rec;
short word;
short start_bit;
short length;
short flags;
short padding1;
BSTR value;
short status;
short padding2;
} rGetdat_Str_Data_Str;
基于这些观察,我使用了C#struct的编组属性,例如,
1。)将结构的值属性更改为 [MarshalAs(UnmanagedType.BStr)]
2.。)将功能的 getdat_str_data 参数属性更改为 MarshalAs(UnmanagedType.SafeArray,SafeArraySubType = VarEnum.VT_RECORD)
仍然无效。
这里有一篇关于类似主题的博客/文章:http://limbioliong.wordpress.com/2012/02/28/marshaling-a-safearray-of-managed-structures-by-pinvoke-part-1/但我无法绕过它。
与使用此DLL函数调用的C#(。Net)相比,VB6似乎可以非常简单地完成它。有关DLLImport如何在C#(。Net)中声明此函数的任何提示或想法?
答案 0 :(得分:1)
您需要将MarshalAs
与UnmanagedType.SafeArray
一起使用,告诉编组人员您希望将数组编组为SAFEARRAY
。
[DllImport("hscnetapi.dll", EntryPoint = "rgetdat_str_vb")]
public static extern short rgetdat_str(
[MarshalAs(UnmanagedType.LPStr)]
string Server,
short num_points,
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_USERDEFINED)]
ref rgetdat_str_data_str[] getdat_str_data
);
在您的C#结构中,您错误地处理了BSTR
成员。它应该是
[MarshalAs(UnmanagedType.BStr)]
public string value;