使用wchar16\u t参数调用函数的PInvoke 我有一个带有C++函数的.DLL,它采用了 const WCHAR16*T**/COD>参数。 我试图在c#中导入并使用它,其中包含字符串、字符数组和带有额外“\0”字符的字符数组,但没有得到任何结果。 当我在调试模式下在原始C++程序中检查它时,它的末尾有额外的“0”字符。我应该使用哪种类型

使用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

另外,我不能100%确定这些参数是否会导致问题。 我将非常感激,并给代表很多点,如果有人可以友好地研究小项目,我说明了问题。C++程序运行良好(我们获得登录响应),但是在C语言项目中OnLogNeRebug SaleBACK从不火。 我在C里做什么#

在C++中,它是工作(获取登录响应)。以下是api文档中的函数描述:

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);
    }