使用wchar16\u t参数调用函数的PInvoke 我有一个带有C++函数的.DLL,它采用了 const WCHAR16*T**/COD>参数。 我试图在c#中导入并使用它,其中包含字符串、字符数组和带有额外“\0”字符的字符数组,但没有得到任何结果。 当我在调试模式下在原始C++程序中检查它时,它的末尾有额外的“0”字符。我应该使用哪种类型
另外,我不能100%确定这些参数是否会导致问题。 我将非常感激,并给代表很多点,如果有人可以友好地研究小项目,我说明了问题。C++程序运行良好(我们获得登录响应),但是在C语言项目中OnLogNeRebug SaleBACK从不火。 我在C里做什么# 在C++中,它是工作(获取登录响应)。以下是api文档中的函数描述:使用wchar16\u t参数调用函数的PInvoke 我有一个带有C++函数的.DLL,它采用了 const WCHAR16*T**/COD>参数。 我试图在c#中导入并使用它,其中包含字符串、字符数组和带有额外“\0”字符的字符数组,但没有得到任何结果。 当我在调试模式下在原始C++程序中检查它时,它的末尾有额外的“0”字符。我应该使用哪种类型,c#,c++,pinvoke,C#,C++,Pinvoke,另外,我不能100%确定这些参数是否会导致问题。 我将非常感激,并给代表很多点,如果有人可以友好地研究小项目,我说明了问题。C++程序运行良好(我们获得登录响应),但是在C语言项目中OnLogNeRebug SaleBACK从不火。 我在C里做什么# 在C++中,它是工作(获取登录响应)。以下是api文档中的函数描述: ACTIVETICKSERVERAPI_API uint64_t ATCreateLoginRequest ( uint64_t session, cons
ACTIVETICKSERVERAPI_API uint64_t ATCreateLoginRequest ( uint64_t session,
const wchar16_t * userid,
const wchar16_t * password,
ATLoginResponseCallback pCallback
)
来自c的工作结构++
typedef struct _ATLOGIN_RESPONSE
{
ATLoginResponseType loginResponse;
uint8_t permissions[255];
ATTIME serverTime;
} ATLOGIN_RESPONSE, *LPATLOGIN_RESPONSE;
typedef struct _ATTIME
{
uint16_t year;
uint16_t month;
uint16_t dayOfWeek;
uint16_t day;
uint16_t hour;
uint16_t minute;
uint16_t second;
uint16_t milliseconds;
} ATTIME, *LPATTIME;
ATLOGINRESPONSE
的声明几乎肯定是错误的
public class ATLOGINRESPONSE
{
public byte loginResponse;
public byte[] permissions;
public ATTIME serverTime;
}
通过将其声明为类,可以确保它将通过引用进行封送。但你排除了它被价值编组的可能性。这可能很好。无论如何,我想我更喜欢声明为结构
此外,前两个参数在我看来是错误的。第一个可能是枚举,应该声明为枚举。第二个是字节数组,但需要指定如何封送它。像这样:
[StructLayout(LayoutKind.Sequential)]
public struct ATLOGINRESPONSE
{
public ATLoginResponseType loginResponse; // you need to define the ATLoginResponseType enum
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
public byte[] permissions;
public ATTIME serverTime;
}
我们不知道ATTIME
的声明是否正确
我在这里要求你的函数名:
C++函数具有此签名
unsigned __int64 __cdecl ATCreateLoginRequest(
unsigned __int64,
wchar_t const *,
wchar_t const *,
void (__cdecl*)(unsigned __int64,unsigned __int64,struct _ATLOGIN_RESPONSE *)
)
因此,您的委托使用错误的调用约定声明。应该是:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ATLoginResponseCallback(
ulong hSession,
ulong hRequest,
ref ATLOGINRESPONSE response
);
请注意,将ATLOGINRESPONSE
更改为结构后,我们必须将参数设置为ref
参数
函数ATLoginResponseCallback
在C#代码中正确声明
您的其他代理也需要使用[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
声明
除非只从ATCreateLoginRequest
调用回调,否则传递的委托将被垃圾收集。因此,如果ATCreateLoginRequest
获取该委托的副本,并稍后调用,则需要保持该委托的活动状态。将其分配给类型为ATLoginResponseCallback
的变量,该变量的生命周期超出对回调的最后调用
问题完全可能存在于其他地方。我下载了您的测试项目,并立即修复了委托声明,因为它们是错误的:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ATSessionStatusChangeCallback(ulong hSession, byte statusTyp);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ATLoginResponseCallback(ulong hSession, ulong hRequest, ref ATLOGINRESPONSE response);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ATRequestTimeoutCallback(ulong origRequest);
我第一次运行该程序时得到:
SessionStatus - Connected
request timeout
!THIS SHOULD FIRE
SessionStatus - Connected
!THIS SHOULD FIRE
第二次和随后的几次我得到:
SessionStatus - Connected
!THIS SHOULD FIRE
没有超时。很难猜测它为什么第一次这样做。您可能需要使用ATSendRequest()等待,直到确认正确登录为止,类似这样的情况
但是很明显,修复委托解决了问题,您现在在回调中获得了正确的hSession值。它还不是完美的,您需要确保它们不能被垃圾收集。将它们存储在静态变量中:
static ATSessionStatusChangeCallback statusCallback;
....
if (res == true) {
statusCallback = new ATSessionStatusChangeCallback(OnSessionStatusChangeCallback);
res = ATInitSession(sessionNumber, "activetick1.activetick.com",
"activetick2.activetick.com", 443, statusCallback, true);
}
对另外两个做同样的操作。也许会给你一个答案?不是我的情况,你关于out参数的链接。这可能是文章中的一个输入错误,但是空终止符是\0,不是/0是的,谢谢。请在问题中发布一个。这将是很容易回答,我肯定,但谁想下载一个外部项目?大卫感谢这些信息,我会深入了解你的答案。权限是enum,这就是为什么我将其设置为byte。关于类/结构-在同一个程序中,我已经遇到了将结构更改为类的问题。。这就是我最初上传项目的原因。它是简单的1页程序,其中C++代码工作正常,但C是不正确的。专业开发人员可以在5分钟内发现问题。谁在乎声誉?我想我已经够了。我是来帮助人们学习的。您对此感兴趣吗?将其声明为类是获得_ATLOGIN_RESPONSE*的一种变通方法,但需要[StructLayout]。只传递LoginResponseCallback是致命的语法,委托不会在任何地方被引用,并且将被垃圾收集。在从类切换到结构后需要ref。我很高兴您自己也在这样做并学习。干得好。谢谢汉斯,你真棒!我将在5小时内颁发赏金。虽然事情比我想象的要复杂。在这个回调的时间结构和logindied类型响应中得到了一些疯狂的值,这意味着用户ATGUID是错误的,尽管我只是复制了必需的值。一定是把结构翻译回来了。。我应该深入研究那个话题。
static ATSessionStatusChangeCallback statusCallback;
....
if (res == true) {
statusCallback = new ATSessionStatusChangeCallback(OnSessionStatusChangeCallback);
res = ATInitSession(sessionNumber, "activetick1.activetick.com",
"activetick2.activetick.com", 443, statusCallback, true);
}