jeudi 23 juin 2016

P/Invoke to third party popup window

Current situation: At my current project I have to use an old C++ dll in a C# winforms application to write on a Hardlock licensing dongle. My application is a simple interface which allows the user to write license information to the dongle. If the dongle already contains data a yes/no dialog is shown to the user by the C++ dll. If the information is successfully written to the dongle the C++ dll shows a confirm dialog. When our logistics department uses this tool they are going to write a lot of dongles (200 to 800 at a day). So they don't want to confirm message boxes. While searching a solution to close popups/message boxes of third party libraries I found some examples using platform invoke. After playing around unsuccessfully with the solution in this post How to suppress a dialog box displayed by code that I can't change? I tried the following approach: Every 500 milliseconds I check if the popup window is shown and confirm it with 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); Problem: Sometimes I get an AccessViolationException. Unfortunately this error is not deterministic. After some dongle-writes it occures or not. The best chance to cause this error is if I click the button (execute the code above) fast, e.g. every 2 seconds. Doese anyone see an obvious mistake? Thanks! Windows EventLog: 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() EDIT: Thanks to Luc who has sent me the following solution (still not solving my problem but still a better solution than mine): 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); Following Hans Passant's approach I used Application Verifier to get the following error details. At the beginning of the stack trace I see some "USER32" and "SendMessage" lines. I use SendMessage to send a closing message to the MessageBox window. But why is it happening? I must say I have no idea what the rest of the stack trace means. <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>

Aucun commentaire:

Enregistrer un commentaire