从非托管的win32程序集dll调用托管代码 - 崩溃

时间:2012-06-28 10:56:50

标签: .net dll assembly

我正在win32程序集中开发一个串口dll(MASM32)。它有自己的线程检查多个事件,并在指定的缓冲区阈值,它通过调用回调函数通知托管主应用程序。它只是一个没有参数/返回值的调用。

启动时,主应用程序通过调用dll中的函数来存储回调函数的地址:

pCallBackFunction dd 0

SetCallBackPointer proc pcb:DWORD

mov eax, pcb
mov pCallBackFunction, eax
call DWORD ptr pCallBackFunction ; verify it immediately
ret

SetCallBackPointer endp

upper函数立即回调托管应用程序回调例程以进行验证。它工作正常。 但是,当我将调用指令放到DLL中的其他函数时,它会崩溃应用程序。调用是在简单函数中还是在dll的threadproc中无关紧要。例如:

OpenPort proc pn:byte,br:dword, inputbuffersize: dword, outputbuffersize:dword, thresholdsize: dword
LOCAL dcb: DCB
LOCAL SerialTimeOuts: COMMTIMEOUTS
call DWORD ptr pCallBackFunction
xor eax, eax
mov al, pn
mov [com_port+3],al

etc. etc.

将始终在调用DWORD ptr pCallBackFunction时崩溃。由于我首先调用SetCallBackPointer在pCallBackFunction中存储有效地址,因此它应该有一个有效的地址。

我的托管应用程序是用C#编写的,相关部分是:

public partial class Form1 : Form
{
    public delegate void CallBackDelegate();
    public static CallBackDelegate mydelegate;

    [DllImport("serialport.dll")]
    private static extern void SetCallBackPointer(CallBackDelegate Delegate);

    [DllImport("serialport.dll")]
    public static extern int OpenPort(byte com, uint br, uint inbufsize, uint outbufsize, uint threshsize);



    public Form1() 
    {

        InitializeComponent();



        mydelegate =new CallBackDelegate(CallbackFunction);

        SetCallBackPointer(mydelegate);

        unsafe
        {
            int sysstat;
            int hResult;

            hResult = OpenPort(Convert.ToByte('5'), 9600, 306, 4, 4);
        }
        }

        public static void CallbackFunction()
        {
             MessageBox.Show( "CallBack Function Called by Windows DLL");
        }

VS调试器报告说dll试图从/向受保护的内存地址读/写。但是在调用SetCallBackPointer时没有这样的问题。我在这里做错了什么?

任何提示都会很棒!

1 个答案:

答案 0 :(得分:0)

SetCallBackDelegate必须使用IntPtr,而不是Delegate对象。

您必须使用Marshal.GetFunctionPointerForDelegate函数将System.Delegate转换为IntPtr32。否则,您将传递某些指针,该指针将某处指向托管堆。

所以改变

 mydelegate =new CallBackDelegate(CallbackFunction);
 SetCallBackPointer(mydelegate);

 mydelegate =new CallBackDelegate(CallbackFunction);

 SetCallBackPointer( Marshal.GetFunctionPointerForDelegate(delegate) );

并将SetCallBackPointer的C#声明修复为

[DllImport("serialport.dll")]
private static extern void SetCallBackPointer(IntPtr Delegate);