none
WPF (.net4.0)下,调用C++的DLL 之后,出现异常:System.StackOverflowException RRS feed

  • 问题

  • 各位网友,版主好,请教一个问题

    我WPF (.net4.0)下,调用C++的DLL的方法 ,这个DLL的方法是:

            //蜂吟
            [DllImport("mi.dll", EntryPoint = "API_ControlBuzzer", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi)]
            public static extern int API_ControlBuzzer(int hComm, int DeviceAddress, int time, int count, byte[] buf);

    其作用是访问读卡器上的一个蜂吟器发声,我是把这段代码放到一个类AceReader里,

    调用方式:AceReader.API_ControlBuzzer(0,0,10,1,buf)

    现在的问题是调用完成时很正常,完成后,我在wpf点击其它任何按钮的动作或打开窗口等等commond动作时都报错:System.StackOverflowException

    为此,我请一朋友用C++写了一个测试 a.DLL,里面有一个方法:

            [DllImport("a.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
            public static extern void MyBox(int iNum);

    这个方法的作用是弹出一个提示信息,没有访问硬件,这样就没有问题

    其本上可以认为:访问硬件后,就会出现System.StackOverflowException

    关于上面提到的C++dll : "mi.dll"

    我在winForm (.net4.0) 下作同样的测试,都很正常。也就是winform上一切正常,没有问题

    我在WPF(.net4.0) 一旦访问了"mi.dll"里的访问硬件的相关方法,访问完成后,再做其它动作时就会出现System.StackOverflowException

     是什么原因?

    怎么解决?

     



    2011年4月19日 4:33

答案

  • 你好,

    我能够重现了,一个栈溢出异常发生在 WindowsBase 程序集里 WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame = {System.Windows.Threading.DispatcherFrame}) Line 1625 + 0x38 bytes。

    由于WPF和以前的Winform使用了不同的消息机制和线程机制,所以在你的dll中抛出的大量异常都被推到了Window的Frames中去了,导致溢出。对于这个问题,你只有尝试去从你的C++ Dll 入手去改了,在你的C++ dll中一定要把异常处理好,线程要做到和被PInvoke调用的代码独立。否则,Native代码被调用到了我们的主线程中,他甚至可以在主线程修改值,会导致我们的WPF 线程中Frame无法受到 WPF 的 Dispatcher 控制。


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 已标记为答案 YaoWenTao 2011年4月19日 9:47
    2011年4月19日 8:09
    版主
  • 有一个临时解决方法, 把你的调用代码放入 另外一个线程:

        private void button1_Click(object sender, RoutedEventArgs e)
        {
          Thread thread = new Thread(() => { AceReader.API_ControlBuzzer(10, 1); });
          thread.Start();
        }
    
    
        private void button2_Click(object sender, RoutedEventArgs e)
        {
          Window1 w1 = new Window1();
          w1.Show();
        }
    
    

    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 已标记为答案 YaoWenTao 2011年4月19日 9:47
    2011年4月19日 8:11
    版主

全部回复

  • 调用栈溢出?

    OK,先排除你的代码问题,我第一想到的是你是否让你的程序和你被调用的dll 的编译平台一致,即如果你的 C++ dll是32位的,那么你的WPF是否也是编译32位。(不推荐在要使用Native代码的时候使用 Any CPU 编译方案,请明确指定你要编译的平台属性, x86 or x64)

    还有,你要确定你的调用函数返回值是正常的,如果是这样,那么可以排除PInvoke上面的问题。所以问题可以归类为你的WPF 代码逻辑问题。能否把你的StackOverflowException异常的详细 Call Stack 调用堆栈贴上了,因为这个才是真正能够帮助我找到根源的信息。谢谢。

    还有,你的Command代码是怎么样,也可以分享一下,这样容易帮你调式找出问题。

    Sincerely,


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年4月19日 7:14
    版主
  • http://www.hjoy.net/wpf.rar

    这是我的测试demo,

    C++dll是32位下的,wpf(.net4.0)也是32位下的

    版主,因为你没有硬件,所以那个方法可能不能调用成功,

    主窗口两个按钮:

            private void button1_Click(object sender, RoutedEventArgs e)
            {
                AceReader.API_ControlBuzzer(10, 1);
            }


            private void button2_Click(object sender, RoutedEventArgs e)
            {
                Window1 w1 = new Window1();
                w1.Show();
            }

    点击了button1之后,再点击button2,就报System.StackOverflowException了

    2011年4月19日 7:33
  • 你可以用C#做一个中间层,然后调用,应该不会出问题。

    参考:

    http://msdn.microsoft.com/en-us/library/ms742522.aspx

     


    Stay hungry, stay foolish
    • 已建议为答案 Helper.WPF 2011年4月19日 8:11
    2011年4月19日 7:36
  • 你好,

    我能够重现了,一个栈溢出异常发生在 WindowsBase 程序集里 WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame = {System.Windows.Threading.DispatcherFrame}) Line 1625 + 0x38 bytes。

    由于WPF和以前的Winform使用了不同的消息机制和线程机制,所以在你的dll中抛出的大量异常都被推到了Window的Frames中去了,导致溢出。对于这个问题,你只有尝试去从你的C++ Dll 入手去改了,在你的C++ dll中一定要把异常处理好,线程要做到和被PInvoke调用的代码独立。否则,Native代码被调用到了我们的主线程中,他甚至可以在主线程修改值,会导致我们的WPF 线程中Frame无法受到 WPF 的 Dispatcher 控制。


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 已标记为答案 YaoWenTao 2011年4月19日 9:47
    2011年4月19日 8:09
    版主
  • 有一个临时解决方法, 把你的调用代码放入 另外一个线程:

        private void button1_Click(object sender, RoutedEventArgs e)
        {
          Thread thread = new Thread(() => { AceReader.API_ControlBuzzer(10, 1); });
          thread.Start();
        }
    
    
        private void button2_Click(object sender, RoutedEventArgs e)
        {
          Window1 w1 = new Window1();
          w1.Show();
        }
    
    

    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 已标记为答案 YaoWenTao 2011年4月19日 9:47
    2011年4月19日 8:11
    版主
  • C++ Dll 我没有源码,我是改不了的,



    非常感谢你的回复,我先用临时解决方案试用着,也没别的办法了
    2011年4月19日 8:52