gpt4 book ai didi

C# 使用带有指针等的 C 库

转载 作者:行者123 更新时间:2023-11-30 16:43:03 25 4
gpt4 key购买 nike

我有一个没有源代码的.dll。该库是用 C 编写的...我只有一个 .h该库的摘录如下:

typedef enum
{
SSHD_ERR_NONE = 0,
SSHD_ERR_INVALID_HANDLE,
SSHD_ERR_NULL_POINTER,
}sshdErr_t;

typedef struct
{
unsigned long Year; //
unsigned long Month; // 1...12
unsigned long Day; // 1...31

unsigned long Hour; // 0...23
unsigned long Min; // 0...59
unsigned long Sec; // 0...59
unsigned long MilliSec; // 0...999
} sshdDateTime_t;


DllExport HANDLE sshdCreate(void);
DllExport sshdErr_t sshdGetDllVersion(char *dllVersion, unsigned long dllVersionMaxLen);

DllExport sshdErr_t sshdOpen(HANDLE rh);

I have write this code:



private const String dllPath = @"D:\work\SSHD.dll";

[DllImport(dllPath,EntryPoint = "sshdOpen")]
internal static extern eSSHD_Err Extern_sshdOpen();


[DllImport(dllPath,EntryPoint = "sshdGetDllVersion")]
//internal static extern string sshdGetDllVersion();
internal static extern eSSHD_Err Extern_sshdGetDllVersion(string dllVer , Int32 maxLen );

[DllImport(dllPath, EntryPoint = "sshdCreate")]
internal static extern IntPtr Extern_sshdCreate();

public enum eSSHD_Err {
SSHD_ERR_NONE = 0,
SSHD_ERR_INVALID_HANDLE,
SSHD_ERR_NULL_POINTER,
}

public class SSHDDateTime {
public ulong Year { get; set; } //
public ulong Month { get; set; } // 1...12
public ulong Day { get; set; } // 1...31
public ulong Hour { get; set; } // 0...23
public ulong Min { get; set; } // 0...59
public ulong Sec { get; set; } // 0...59
public ulong MilliSec { get; set; } // 0...999

public SSHDDateTime() {
Year = 0;
Month = 0;
Day = 0;
Hour = 0;
Min = 0;
Sec = 0;
MilliSec = 0;
}
}

所以我使用 Dll 导入,在枚举(C#)中转换枚举并在类中转换结构......

当我尝试使用时出现错误...

现在是使用该库的代码:

  IntPtr handle;
handle = Extern_sshdCreate();

这可能有效...这意味着“处理”的值发生变化...但我真的不知道它是否有效!

当我尝试使用其他功能时,以这种方式:

int retProva = (int) (Extern_sshdOpen(handle));

eSSHD_Err retProva = Extern_sshdOpen(handle);

我遇到堆栈损坏的错误...

使用其他函数是相同的结果:

string dllVer="xxxxxxxxxxxxxxx";
Int32 maxLen = 10;
Extern_sshdGetDllVersion(dllVer,maxLen);

我尝试使用 string 或 String 作为 dllVer 或使用 = ""...我尝试存储返回的值而不是我尝试使用 Int32、string、ulong 作为 maxLen坚果所有尝试都没有结果...

返回的错误(意大利语)是这样的:

Managed Debugging Assistant 'PInvokeStackImbalance' : 'Una chiamata alla funzione PInvoke 'TestSTSWavetronix!TestSTSWavetronix.FormTestWavetronix::Extern_sshdGetDllVersion' ha sbilanciato lo stack. Questo problema può verificarsi quando la firma PInvoke gestita non corrisponde alla firma di destinazione non gestita. Verificare che la convenzione di chiamata e i parametri della firma PInvoke corrispondano alla firma di destinazione non gestita.'

所以我问:1.如何正确使用这个调用?2.我在enum C#中改造了enum C,但是对于返回值,如何适配?3. 与之前类似,如果在 C# 中我有类,如何将 struct C 传递给函数?4. 我有一个关于C参数函数调用的指针...如何管理他?我想 C 代码尝试修改我传递的字符串......

编辑:其他尝试:- 在编译属性和原型(prototype)之前使用不安全- 在枚举定义上使用“enum : int”

编辑2:********************** 工作解决方案 **************

  public enum eSSHD_Err {
SSHD_ERR_NONE = 0,
SSHD_ERR_INVALID_HANDLE,
SSHD_ERR_NULL_POINTER,
}
[DllImport(dllPath,EntryPoint = "sshdGetDllVersion",CallingConvention = CallingConvention.Cdecl)]
unsafe internal static extern eSSHD_Err Extern_sshdGetDllVersion(ref char dllVer,Int32 maxLen);
char[] dllVer = new char[250];
Int32 maxLen = 250;
retErrGetDllVer = Extern_sshdGetDllVersion(ref dllVer[0],maxLen);

感谢大家

马西米利亚诺

最佳答案

尝试将 StructLayoutAttribute 添加到托管结构声明中。允许 C# 编译器重新排序如果结构成员认为有益的话,它会提高效率,因此这将防止这种情况发生。由于 long 在 C 中通常是一个 32 位整数,因此我已将字段类型更改为 uint

[StructLayout(LayoutKind.Sequential)]
public class SSHDDateTime {
public uint Year { get; set; } //
public uint Month { get; set; } // 1...12
public uint Day { get; set; } // 1...31
public uint Hour { get; set; } // 0...23
public uint Min { get; set; } // 0...59
public uint Sec { get; set; } // 0...59
public uint MilliSec { get; set; } // 0...999

public SSHDDateTime() {
Year = 0;
Month = 0;
Day = 0;
Hour = 0;
Min = 0;
Sec = 0;
MilliSec = 0;
}
}

接下来,将 StringBuilder 传递给 Extern_sshdGetDllVersion 函数。该函数需要一个字符缓冲区,字符缓冲区的托管等效项是 StringBuilder。 PInvoke 编码(marshal)拆收器详细介绍了了解用于处理字符串互操作编码(marshal)的 StringBuilder 类。您可以添加 MarshalAsAttribute 作为对编码(marshal)拆收器的提示,表明您正在 native 库中处理 ANSI 字符串。此外,DllImportAttribute 的默认调用约定是 StdCall,这可能不是您想要的。此修订后的签名指定了 Cdecl 调用约定,这是 C 程序的标准约定。如果您的 C 库实际上被编译为使用 StdCall,那么您可以将该部分删除,但我认为这是堆栈损坏的根源。

    [DllImport(dllPath, EntryPoint = "sshdGetDllVersion", CallingConvention = CallingConvention.Cdecl)]
internal static extern eSSHD_Err Extern_sshdGetDllVersion([MarshlAs(UnmanagedType.LPStr)]StringBuilder dllVer , Int32 maxLen );

其他函数的 PInvoke 签名如下:

[DllImport(dllPath, EntryPoint = "sshdOpen", CallingConvention = CallingConvention.Cdecl))]
internal static extern eSSHD_Err Extern_sshdOpen();

[DllImport(dllPath, EntryPoint = "sshdCreate", CallingConvention = CallingConvention.Cdecl))]
internal static extern IntPtr Extern_sshdCreate();

关于C# 使用带有指针等的 C 库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45571905/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com