سؤال

أقوم بإنشاء موضوع يبحث عن نافذة. عندما يجد النافذة ، فإنه يتجاوز WindowProc ، ويتعامل مع WM_Command و WM_Close.

إليك الرمز الذي يبحث عن النافذة والفواصل الفرعية:

public void DetectFileDialogProc()
{
   Window fileDialog = null;
   // try to find the dialog twice, with a delay of 500 ms each time
   for (int attempts = 0; fileDialog == null && attempts < 2; attempts++)
   {
      // FindDialogs enumerates all windows of class #32770 via an EnumWindowProc
      foreach (Window wnd in FindDialogs(500))
      {            
         IntPtr parent = NativeMethods.User32.GetParent(wnd.Handle);
         if (parent != IntPtr.Zero)
         {
            // we're looking for a dialog whose parent is a dialog as well
            Window parentWindow = new Window(parent);
            if (parentWindow.ClassName == NativeMethods.SystemWindowClasses.Dialog)
            {
               fileDialog = wnd;
               break;
            }
         }
      }
   }
   // if we found the dialog
   if (fileDialog != null)
   {
      OldWinProc = NativeMethods.User32.GetWindowLong(fileDialog.Handle, NativeMethods.GWL_WNDPROC);
      NativeMethods.User32.SetWindowLong(fileDialog.Handle, NativeMethods.GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(new WindowProc(WndProc)).ToInt32());
   }
}

و WindowProc:

public IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
   lock (this)
   {
      if (!handled)
      {
         if (msg == NativeMethods.WM_COMMAND || msg == NativeMethods.WM_CLOSE)
         {       
            // adding to a list. i never access the window via the hwnd from this list, i just treat it as a number
            _addDescriptor(hWnd);
            handled = true;
         }
      }
   }
   return NativeMethods.User32.CallWindowProc(OldWinProc, hWnd, msg, wParam, lParam);
}        

كل هذا يعمل بشكل جيد في ظل الظروف العادية. لكني أرى حالتين من السلوك السيئ في ترتيب السوء:

  1. إذا لم أغلق مربع الحوار في غضون دقيقة أو نحو ذلك ، فإن التطبيق يتعطل. هل هذا لأن الموضوع يتم جمع القمامة؟ هذا من شأنه أن يكون نوعًا ما ، بقدر ما يمكن لـ GC معرفة أن الخيط يتم؟ إذا كان هذا هو الحال ، (وأنا لا أعرف أنه) ، كيف يمكنني أن أجعل الخيط يبقى طالما أن مربع الحوار موجود؟

  2. إذا قمت بإغلاق مربع الحوار على الفور باستخدام زر "X" (WM_Close) ، يتعطل التطبيق. أعتقد أن تحطمها في Windowproc ، لكن لا يمكنني الحصول على نقطة توقف هناك. أحصل على AccessViolationException ، يقول الاستثناء "حاول قراءة أو كتابة ذاكرة محمية. هذا غالبًا ما يكون مؤشراً على أن الذاكرة الأخرى فاسدة". إنها حالة سباق ، لكن ما لا أعرفه. لمعلوماتك ، كنت أعيد ضبط Windowproc القديم بمجرد معالجة الأوامر ، لكن ذلك كان يتحطم في كثير من الأحيان!

أي أفكار حول كيف يمكنني حل هذه القضايا؟

هل كانت مفيدة؟

المحلول 2

توصل أخيرًا إلى حل ، مهاجم المشكلة من زاوية مختلفة. لقد تمكنت من تعيين خطاف على مستوى النظام في التعليمات البرمجية المدارة باستخدام setwineventhook ، وخيار WINEVENT_OUTOFCONTEXT ، الذي يحتوي بشكل مثير للدهشة على خاصية: لا يتم تعيين وظيفة رد الاتصال في مساحة العنوان للعملية التي تولد الحدث. أنا فخ الحدث event_system_dialogstart لتلقي الإخطارات كلما تم إنشاء مربع حوار ، و event_system_dialogend عند تدميره.

نصائح أخرى

نقطتان من الملاحظة التي يمكنني صنعها ....

  • في الخاص بك DetectFileDialogProc, ، أنت تقارن wnd إلى NULL ، هذا هو IntPtr اكتب نعم؟ إذا كان الأمر كذلك ، فيجب أن يكون التحقق من المقارنة if (wnd > IntPtr.Zero){ .... }
  • في الخاص بك WndProc, ، أنت تستخدم this متغير ل lock وهو أمر سيء للقيام به ... يجب أن تفعل شيئًا كهذا private readonly object objLock = new object(); وداخل الخاص بك WndProc استخدم هذا lock (objLock){....}

ومعرفة ما إذا كان هذا يحل المشكلة ....

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top