【问题标题】:C#-PInvoke: What does UnmanagedFunctionPointer do?C#-PInvoke:UnmanagedFunctionPointer 做什么?
【发布时间】:2013-06-28 12:26:45
【问题描述】:

首先,我为什么要问这个问题? 因为我坚持的 Windows CE 平台不支持这个属性。所以我需要对我的委托(从 C++ 调用)做所有属性通常做的事情。

在普通的 Windows 中我有

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]        
public delegate UInt32 UnmanagedAuthenticationEvent(UInt32 authType, UInt32 numberToDisplay, IntPtr btAddress, ref UInt32 numberOfDigits)

而且效果很好。当从 C++ 调用时,return valueref 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 实现中可能出现的其他问题。

【问题讨论】:

  • 没有合理的方法来处理这个问题,当调用约定错误时堆栈会变得不平衡。您必须更改您的 C 代码并声明函数指针 __stdcall。
  • 我的理解是Windows CE只有一个调用约定,那就是Winapi,我猜它是CDECL。有没有一种方法可以在不使用 UnmanagedFunctionPointer 属性的情况下声明调用约定?
  • 也许 Windows CE 根本不需要这个声明,因为它只支持一种调用约定。
  • 我认为,至少在 Windows 桌面上,WINAPI 是 __stdcall。

标签: c# callback pinvoke windows-ce unmanaged


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-02-10
    • 2019-02-15
    • 2013-05-12
    • 2011-03-29
    • 1970-01-01
    • 1970-01-01
    • 2022-11-17
    • 2023-01-08
    相关资源
    最近更新 更多