2013-06-28 38 views
0

首先,我为什么问这个问题? 因为我坚持使用的Windows CE平台不支持此属性。所以我需要对我的委托(即从C++调用)执行一切属性通常的操作。C#-PInvoke:UnmanagedFunctionPointer做什么?

在正常的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实现中的其他问题。

+2

没有合理的方法来处理这个问题,当调用约定错误时,堆栈会不平衡。你*必须*改变你的C代码并声明函数指针__stdcall。 –

+0

我的理解是,Windows CE只有一个调用约定,那就是Winapi,我猜它是CDECL。有没有一种方法可以在不使用UnmanagedFunctionPointer属性的情况下声明调用约定? –

+0

也许Windows CE不需要这个声明,因为它只支持一个调用约定。 –

回答

1

原来它指定的是函数调用约定。在WindowsCE上,只有一个调用约定,因此不需要此属性,因此不存在。因此,如果有人试图支持这两种平台,则需要使用该属性进行条件编译。