以下是DLL中可用功能的文档:
extern EXTERNC __declspec( dllexport ) long initiate (
double conc1,
double conc2,
long temp,
const char* NT
);
extern EXTERNC __declspec( dllexport ) long DoWork (
long NumItems,
struct Structure* Items
);
在Delphi中,这些成功实现(包括自定义结构):
function CustomInitialize
(
Concentration1 : double;
Concentration2 : double;
Temperature : LongInt;
const Type : PAnsiChar
) : LongInt; cdecl; external 'CustomDLL.dll' name '_initiate';
procedure DoWork
(
NumItems : LongInt;
Items : PStructure
); cdecl; external 'CustomDLL.dll' name '_DoWork';
TStructure = record
ValueName : PAnsiChar;
Value : PAnsiChar;
Status : LongInt;
ReturnVal1 : Double;
ReturnVal2 : Double;
ReturnVal3 : Double;
Temp : Double;
end;
PStructure = ^TStructure;
请注意,虽然DoWork方法似乎接受了一个项目数组,但所有实现都将NumItems设置为1并在Delphi中循环该对象,而不是将其传递给C ++。
在C#中,我甚至不确定我应该发布哪个示例。我已经google了几天,尝试了我可以尝试的每个版本的代码,但都无济于事。这是最新版本:
namespace JunkProject
{
class Program
{
static void Main(string[] args)
{
int test = _initiate(.05, .05, 60, "1");
Console.WriteLine(test);
if (test != 1)
Console.ReadLine();
var structure = new FoldStructure() { ValueName = "Test1", Value = "TESTTESTTESTTESTTESTTESTTEST", Status = 0, ReturnVal1 = 0.0, ReturnVal2 = 0.0, ReturnVal3 = 0.0, Temp = 0.0 };
test = _DoWork(1, structure);
Console.WriteLine(structure.Value);
Console.ReadLine();
}
private const string DLL_LOCATION = "CustomDLL.dll";
[DllImport(DLL_LOCATION, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int _initiate(double Conc1, double Conc2, int Temp, [MarshalAs(UnmanagedType.LPStr, SizeConst = 5)] string Type);
[DllImport(DLL_LOCATION, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int _DoWork(int NumItems, [In, Out] Structure Struct);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class Structure
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string ValueName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 28)]
public string Value;
public int Status;
public double ReturnVal1;
public double ReturnVal2;
public double ReturnVal3;
public double Temp;
}
}
}
但是,这样做会提供访问冲突。我已经尝试将方法签名设为IntPtr,但这失败了。我已经尝试使方法签名成为结构的指针,这通常在我尝试的每一种方式都是非常错误的,尽管我不能确定我是否真的在'正确的方式'很长时间内,因为我不确定那是什么方式。我想如果我能弄清楚正确的方法签名是什么,那将有助于吨。
此外,对于稍微混淆源代码道歉。我正在使用的DLL是专有的等等。
先发制人,谢谢您的帮助!
答案 0 :(得分:1)
您不应该在SizeConst
MarshalAs
参数的Type
声明中使用_initiate()
属性。输入只是一个指向字符串的指针,所以让C#编组它。
_DoWork()
需要一个数组(即使你的实现只传递了1个元素),所以你应该编组一个实际的数组。
对于struct
类型,您应该使用class
而不是Structure
。 ValueName
和Value
字段的声明与您的Delphi代码不符。在你的Delphi代码中,它们只是原始指针,可能是分配的字符缓冲区。但是在您的C#代码中,您正在编组可变长度string
值,就像它们是固定长度的字符数组一样。
尝试更像这样的东西:
namespace JunkProject
{
class Program
{
static void Main(string[] args)
{
int test = initiate(.05, .05, 60, "1");
Console.WriteLine(test);
if (test != 1)
Console.ReadLine();
Structure[] structure = new Structure[1];
structure[0].ValueName = "Test1";
structure[0].Value = "TESTTESTTESTTESTTESTTESTTEST";
structure[0].Status = 0;
structure[0].ReturnVal1 = 0.0;
structure[0].ReturnVal2 = 0.0;
structure[0].ReturnVal3 = 0.0;
structure[0].Temp = 0.0;
test = DoWork(1, structure);
Console.WriteLine(structure[0].Value);
Console.ReadLine();
}
private const string DLL_LOCATION = "CustomDLL.dll";
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Structure
{
[MarshalAs(UnmanagedType.LPStr)]
public string ValueName;
[MarshalAs(UnmanagedType.LPStr)]
public string Value;
public int Status;
public double ReturnVal1;
public double ReturnVal2;
public double ReturnVal3;
public double Temp;
}
[DllImport(DLL_LOCATION, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "_initiate")]
private static extern int initiate(double Conc1, double Conc2, int Temp, [MarshalAs(UnmanagedType.LPStr)] string Type);
[DllImport(DLL_LOCATION, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "_DoWork")]
private static extern int DoWork(int NumItems, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] Structure[] Struct);
}
}
但是,您在Structure.Value
退出后正在阅读_DoWork()
字段,因此可能会将新数据写入该字段,因此您可能需要执行更类似的操作:
namespace JunkProject
{
class Program
{
static void Main(string[] args)
{
int test = initiate(.05, .05, 60, "1");
Console.WriteLine(test);
if (test != 1)
Console.ReadLine();
Structure[] structure = new Structure[1];
structure[0].ValueName = "Test1";
structure[0].Value = Marshal.AllocHGlobal(28);
// alternatively:
// structure[0].Value = (IntPtr) Marshal.StringToHGlobalAnsi("TESTTESTTESTTESTTESTTESTTEST");
structure[0].Status = 0;
structure[0].ReturnVal1 = 0.0;
structure[0].ReturnVal2 = 0.0;
structure[0].ReturnVal3 = 0.0;
structure[0].Temp = 0.0;
test = DoWork(1, structure);
String Value = Marshal.PtrToStringAnsi(structure[0].Value);
Console.WriteLine(Value);
Console.ReadLine();
Marshal.FreeHGlobal(structure[0].Value);
}
private const string DLL_LOCATION = "CustomDLL.dll";
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Structure
{
[MarshalAs(UnmanagedType.LPStr)]
public string ValueName;
public IntPtr Value;
public int Status;
public double ReturnVal1;
public double ReturnVal2;
public double ReturnVal3;
public double Temp;
}
[DllImport(DLL_LOCATION, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "_initiate")]
private static extern int initiate(double Conc1, double Conc2, int Temp, [MarshalAs(UnmanagedType.LPStr)] string Type);
[DllImport(DLL_LOCATION, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "_DoWork")]
private static extern int DoWork(int NumItems, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] Structure[] Struct);
}
}