首先,我为什么要问这个问题?因为我坚持的 Windows CE 平台不支持这个属性。所以我需要对我的委托(从 C++ 调用)做所有属性通常做的事情。
在普通的 Windows 中,我有
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate UInt32 UnmanagedAuthenticationEvent(UInt32 authType, UInt32 numberToDisplay, IntPtr btAddress, ref UInt32 numberOfDigits)
它工作正常。当从 C++ 调用时,返回值和ref UInt32 numberOfDigits值都从 C# 层正确接收。现在我删除该属性并使用 Windows CE 所需的方法通过 PInvoke 将非托管函数指针传递给 C++:
_authenticationEvent = new UnmanagedAuthenticationEvent(OnReceiveUnmanagedAuthenticationEvent);
_unmanagedAuthenticationEvent = Marshal.GetFunctionPointerForDelegate(_authenticationEvent);
CallRegisterForAuthenticationEvent(_uBTTransportPtr, _unmanagedAuthenticationEvent);
其中 'CallRegisterForAuthenticationEvent(IntPtr, IntPtr)' 是 PInvoke 签名。
我已经声明了以下类“变量”
private IntPtr _unmanagedAuthenticationEvent;
private Delegate _authenticationEvent;
private UInt32 _numberOfDigits; // the ref UInt32 passed back to C++
private UInt32 _matchValue; // the return value
保护我的委托函数指针和传递回 C++ 的变量不被垃圾收集。起初我没有添加返回值和 ref UInt32 值,它们在 C++ 中都是垃圾。完成上述操作后,'_numberOfDigits' 值很好,但返回值是垃圾。
我现在从 C++ 调用的函数如下所示(至少开始时):
#region OnReceiveUnmanagedAuthenticationEvent
// This is the function called by the unmanaged code
private UInt32 OnReceiveUnmanagedAuthenticationEvent(UInt32 authType, UInt32 numberToDisplay, IntPtr btAddress, ref UInt32 numberOfDigits)
{
byte[] byteAddress = new byte[6];
Marshal.Copy(btAddress, byteAddress, 0, 6);
string btAddressString = Common.StaticHelper.BluetoothAddressFromByteArray(byteAddress);
switch (authType)
{
case 2: //Auth_BT_PIN:
if(OnPinRequestEvent != null)
{
string pin = "";
OnPinRequestEvent(ref pin, btAddressString);
try
{
_matchValue = UInt32.Parse(pin);
_numberOfDigits = (uint)pin.Length; // protect value from being GCed
numberOfDigits = _numberOfDigits;
return _matchValue; // The case I am viewing returns here
}
catch(ArgumentNullException e)
{
Console.WriteLine("Application entered a bad PIN value. Details " + e.Message);
}
catch(FormatException e)
{
Console.WriteLine("Application entered a bad PIN value. Details " + e.Message);
}
catch(OverflowException e)
{
Console.WriteLine("Application entered a bad PIN value. Details " + e.Message);
}
}
break;
我错过了什么返回值是垃圾?我想我可以将值作为参数中的 ref 值返回并解决我的问题,但我想知道 UnmanagedFunctionPointer 是如何做到的,以便我可以解决这个痛苦的 Windows CE 实现中可能出现的其他问题。