【问题标题】:P/Invoke to third party popup windowP/Invoke 到第三方弹出窗口
【发布时间】:2016-06-22 21:59:32
【问题描述】:

现状:
在我当前的项目中,我必须在 C# winforms 应用程序中使用旧的 C++ dll 来编写 Hardlock 许可加密狗。

我的应用程序是一个简单的界面,允许用户将许可证信息写入加密狗。如果加密狗已经包含数据,则 C++ dll 向用户显示是/否对话框。如果信息成功写入加密狗,C++ dll 会显示确认对话框。

当我们的物流部门使用这个工具时,他们会编写很多加密狗(一天 200 到 800 个)。所以他们不想确认消息框。

在搜索关闭第三方库的弹出窗口/消息框的解决方案时,我发现了一些使用平台调用的示例。在使用这篇帖子How to suppress a dialog box displayed by code that I can't change? 中的解决方案失败后,我尝试了以下方法:

每 500 毫秒检查一次弹出窗口是否显示并按 ENTER 确认。

private void initButton_Click(object sender, EventArgs e)
{
    messageBoxCloseTimer.Interval = 500;
    messageBoxCloseTimer.Start();
    WriteDongle();
}

private void WriteDongle()
{
    // This code shows a message box        
}

private void MessageBoxCloseTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    BeginInvoke(new MethodInvoker(delegate
    {
        var hwnd = FindWindow("#32770", "Information");
        if (hwnd.ToInt32() < 1)    // Window not found
            return;

        SendKeys.Send("{ENTER}");
        messageBoxCloseTimer.Stop();
    }));
}

[DllImport("user32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

// C++ dll which is used to write the dongle
[DllImport("License.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern Int16 peak_BurnDongle(
        Int16 iType,
        [MarshalAs(UnmanagedType.LPStr)] ref string pszSysID,
        int iProgPort,
        Int16 iSigPort);

问题:
有时我会收到 AccessViolationException。 不幸的是,这个错误不是确定性的。在一些加密狗写入之后,它会发生与否。导致此错误的最佳机会是如果我快速单击按钮(执行上面的代码),例如每 2 秒一次。

有没有人发现明显的错误?谢谢!

Windows 事件日志:

Anwendung: VizLicInitializer.exe
Frameworkversion: v4.0.30319
Beschreibung: Der Prozess wurde aufgrund eines Ausnahmefehlers beendet.
Ausnahmeinformationen: System.AccessViolationException
Stapel:
   bei System.Drawing.SafeNativeMethods+Gdip.GdipCreateBitmapFromStream(IStream, IntPtr ByRef)
   bei System.Drawing.Bitmap..ctor(System.Type, System.String)
   bei System.Windows.Forms.ThreadExceptionDialog..ctor(System.Exception)
   bei System.Windows.Forms.Application+ThreadContext.OnThreadException(System.Exception)
   bei System.Windows.Forms.Application+ThreadContext.PreTranslateMessage(MSG ByRef)
   bei System.Windows.Forms.Application+ThreadContext.System.Windows.Forms.UnsafeNativeMethods.IMsoComponent.FPreTranslateMessage(MSG ByRef)
   bei System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr, Int32, Int32)
   bei System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)
   bei System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)
   bei System.Windows.Forms.Application.Run(System.Windows.Forms.Form)
   bei VizLicInitializer.Program.Main()

编辑:
感谢 Luc,他向我发送了以下解决方案(仍然没有解决我的问题,但仍然比我的解决方案更好):

        internal static void RegisterWindowCreatedEvent()
        {
            var hHook = SetWindowsHookEx(HookType.WH_SHELL, winDelegate, IntPtr.Zero, AppDomain.GetCurrentThreadId());
        }

        private static int ShellHookProcDelegate(int code, IntPtr wParam, IntPtr lParam)
        {
            if (code != HSHELL_WINDOWCREATED)
            {
                return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
            }

            StringBuilder wCaption = new StringBuilder();
            GetWindowCaption(wParam, wCaption, wCaption.Capacity);
            if (wCaption.ToString() == "Information")
            {
                SendMessage(wParam, 0x0010, IntPtr.Zero, IntPtr.Zero);
            }
            return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
        }


        private delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
        private static readonly HookProc winDelegate = ShellHookProcDelegate;
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(HookType hook, HookProc callback, IntPtr hMod, int dwThreadId);

        [DllImport("user32.dll")]
        private static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
        const int HSHELL_WINDOWCREATED = 1;

        [DllImport("user32.dll", EntryPoint = "GetWindowText",CharSet = CharSet.Auto)]
        static extern IntPtr GetWindowCaption(IntPtr hwnd,StringBuilder lpString, int maxCount);

        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam);

按照 Hans Passant 的方法,我使用 Application Verifier 获取以下错误详细信息。

在堆栈跟踪的开头,我看到一些“USER32”和“SendMessage”行。我使用 SendMessage 将关闭消息发送到 MessageBox 窗口。但为什么会这样? 我必须说我不知道​​堆栈跟踪的其余部分是什么意思。

<avrf:logfile xmlns:avrf="Application Verifier">
    <avrf:logSession Version="2" PID="4024" TimeStarted="2016-06-22 : 15:38:26">
        <avrf:logEntry Severity="Error" StopCode="0x13" LayerName="Heaps" Time="2016-06-22 : 15:38:54">
            <avrf:message>First chance access violation for current stack trace.</avrf:message>
            <avrf:parameter1>0 - Invalid address causing the exception.</avrf:parameter1>
            <avrf:parameter2>94e5d8f - Code address executing the invalid access.</avrf:parameter2>
            <avrf:parameter3>2ad984 - Exception record.</avrf:parameter3>
            <avrf:parameter4>2ad9a0 - Context record.</avrf:parameter4>
            <avrf:stackTrace>
                <avrf:trace>vrfcore!VerifierDisableVerifier+73c ( @ 0)</avrf:trace>
                <avrf:trace>vfbasics!+6c7462f0 ( @ 0)</avrf:trace>
                <avrf:trace>vfbasics!+6c747982 ( @ 0)</avrf:trace>
                <avrf:trace>vfbasics!+6c74728a ( @ 0)</avrf:trace>
                <avrf:trace>ntdll!RtlReleasePrivilege+114 ( @ 0)</avrf:trace>
                <avrf:trace>ntdll!RtlGetGroupSecurityDescriptor+30c ( @ 0)</avrf:trace>
                <avrf:trace>ntdll!RtlGetGroupSecurityDescriptor+211 ( @ 0)</avrf:trace>
                <avrf:trace>ntdll!KiUserExceptionDispatcher+f ( @ 0)</avrf:trace>
                <avrf:trace>HLPROG!GetListOfParPorts+f86a ( @ 0)</avrf:trace>
                <avrf:trace>verifier!VerifierGetProviderHelper+ce0d ( @ 0)</avrf:trace>
                <avrf:trace>vrfcore!VerifierTlsSetValue+431 ( @ 0)</avrf:trace>
                <avrf:trace>vfbasics!+6c746ba5 ( @ 0)</avrf:trace>
                <avrf:trace>ntdll!wcsncmp+58 ( @ 0)</avrf:trace>
                <avrf:trace>ntdll!EtwEventRegister+135 ( @ 0)</avrf:trace>
                <avrf:trace>ntdll!RtlImageNtHeader+2b1 ( @ 0)</avrf:trace>
                <avrf:trace>ntdll!LdrLoadDll+66 ( @ 0)</avrf:trace>
                <avrf:trace>vfbasics!+6c746fd7 ( @ 0)</avrf:trace>
                <avrf:trace>KERNELBASE!GetDiskFreeSpaceExA+2bd0 ( @ 0)</avrf:trace>
                <avrf:trace>clr!StrongNameFreeBuffer+201d1 ( @ 0)</avrf:trace>
                <avrf:trace>clr!StrongNameFreeBuffer+20234 ( @ 0)</avrf:trace>
                <avrf:trace>clr!PreBindAssemblyEx+1747a ( @ 0)</avrf:trace>
                <avrf:trace>clr!PreBindAssemblyEx+17edb ( @ 0)</avrf:trace>
                <avrf:trace>clr!CreateAssemblyNameObject+2f57 ( @ 0)</avrf:trace>
                <avrf:trace>clr!CreateAssemblyNameObject+2ec2 ( @ 0)</avrf:trace>
                <avrf:trace>clr!CreateAssemblyNameObject+2dcb ( @ 0)</avrf:trace>
                <avrf:trace>clr!CreateAssemblyNameObject+2d64 ( @ 0)</avrf:trace>
                <avrf:trace>clr!DllCanUnloadNowInternal+173 ( @ 0)</avrf:trace>
                <avrf:trace>clr!+5ba12a0c ( @ 0)</avrf:trace>
                <avrf:trace>????????+07F73967</avrf:trace>
                <avrf:trace>????????+07F73645</avrf:trace>
                <avrf:trace>????????+07F73579</avrf:trace>
                <avrf:trace>System.Windows.Forms.ni!+57cb918a ( @ 0)</avrf:trace>
                <avrf:trace>System.Windows.Forms.ni!+57cbb71c ( @ 0)</avrf:trace>
                <avrf:trace>System.Windows.Forms.ni!+5827c720 ( @ 0)</avrf:trace>
                <avrf:trace>System.Windows.Forms.ni!+582590cc ( @ 0)</avrf:trace>
                <avrf:trace>System.Windows.Forms.ni!+585b8aae ( @ 0)</avrf:trace>
                <avrf:trace>System.Windows.Forms.ni!+585b7841 ( @ 0)</avrf:trace>
                <avrf:trace>System.Windows.Forms.ni!+57cc1d00 ( @ 0)</avrf:trace>
                <avrf:trace>System.Windows.Forms.ni!+57cc6bb1 ( @ 0)</avrf:trace>
                <avrf:trace>System.Windows.Forms.ni!+57cc6b99 ( @ 0)</avrf:trace>
                <avrf:trace>System.Windows.Forms.ni!+57cc6ae0 ( @ 0)</avrf:trace>
                <avrf:trace>????????+0035A093</avrf:trace>
                <avrf:trace>USER32!gapfnScSendMessage+1cf ( @ 0)</avrf:trace>
                <avrf:trace>USER32!gapfnScSendMessage+2cf ( @ 0)</avrf:trace>
                <avrf:trace>USER32!gapfnScSendMessage+908 ( @ 0)</avrf:trace>
                <avrf:trace>USER32!DispatchMessageW+f ( @ 0)</avrf:trace>
                <avrf:trace>System.Windows.Forms.ni!+57d1b6bc ( @ 0)</avrf:trace>
                <avrf:trace>System.Windows.Forms.ni!+57cd5701 ( @ 0)</avrf:trace>
                <avrf:trace>System.Windows.Forms.ni!+57cd5389 ( @ 0)</avrf:trace>
                <avrf:trace>System.Windows.Forms.ni!+57cd5202 ( @ 0)</avrf:trace>
                <avrf:trace>System.Windows.Forms.ni!+57cb15e1 ( @ 0)</avrf:trace>
            </avrf:stackTrace>
        </avrf:logEntry>
    </avrf:logSession>
</avrf:logfile>

【问题讨论】:

  • 堆栈跟踪没有用,它显示内置未处理异常报告器失败。有关原始异常的所有信息都是不可见的。但是可以很安全地假设即使报告错误也无法再工作时,该过程已彻底损坏。您将需要更大的武器来诊断此问题,从 UMHD.exe 和应用程序验证程序开始。

标签: c# c++ .net winforms messagebox


【解决方案1】:

我认为您的代码会在关闭弹出窗口之前尝试写入加密狗。

考虑一下: 1.您启动计时器并写入加密狗。 2. 定时器触发,但弹出窗口还没有出现,所以什么也没有发生。 3. 再次单击按钮时会显示弹出窗口。 4. 在计时器再次触发(并关闭弹出窗口)之前,您调用 WriteDongle。

尝试在启动计时器之前禁用按钮并在关闭弹出窗口时启用它。

或者,您可能会尝试挂钩某个窗口创建事件,过滤掉您需要的事件并在那里调用您的关闭弹出代码(我自己从未做过,所以这只是一个头脑风暴)。在显示弹出窗口时,您仍然需要注意禁用对加密狗的写入。 How can I be notified when a new window is created on Win32?

【讨论】:

  • 在生产应用程序中禁用表单上的所有按钮(在我的示例中,这部分缺失)。但无论如何禁用和启用按钮并不能解决它。我已经尝试过您建议的链接的解决方案。但是在那里我得到了与我的解决方案相同的错误。恐怕我必须调查 Hans Passant 在原帖评论中指出的错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-07
  • 2014-06-18
  • 1970-01-01
  • 2011-09-30
相关资源
最近更新 更多