SetWindowLong挂

时间:2012-04-18 19:20:04

标签: .net winapi vb6 interop pinvoke

为什么* SetWindowLong(myForm.hWnd,GWL_HWNDPARENT,parentHwnd)*挂起?

我可以持续地执行这三个步骤来重现这个问题。

  1. 创建.NET表单
  2. 初始化WaitWindow COM对象,在传递.NET Forms句柄时调用COM对象上的ShowWindow
  3. 在VB6中调用SetWindowLong方法
  4. C#Windows应用程序(挂起)

    private static void Main(string[] args)
    {
          Form form = new Form();
          form.Show();
    
          Interop.WaitWindow waitWindow = new Interop.WaitWindow();
          waitWindow.ShowWindow(form.Handle.ToInt32(), Language.RISEnglish);
    }
    

    C#控制台应用程序(不挂起)

    private static void Main(string[] args)
    {
          IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;     
    
          Interop.WaitWindow waitWindow = new Interop.WaitWindow();
          waitWindow.ShowWindow(handle.ToInt32(), Language.RISEnglish);
    }
    

    VB6代码段

    Public Sub ShowWindow(ByVal parentHwnd As Long, ByVal language As Language)
    
        SetWindowLong(myForm.hWnd, GWL_HWNDPARENT, parentHwnd)  'Hangs Here
        CenterWindow (parentHwnd)
    
        myForm.ShowRetrieving (language)
        myForm.Show (vbModal)
    End Sub
    

    非常感谢您的帮助:)

    修改

    我知道不应该调用SetWIndowLong来更改父级,但是我试图理解为什么它只在使用.NET表单句柄时挂起。

    EDIT2

    我现在认为这个问题与SetWindowLong无关,而是实际的句柄本身。我还在调查,但似乎当我从.NET调用VB6代码时,它会创建一个RPC线程。我还不确定,但我觉得它与跨线程问题有关。

3 个答案:

答案 0 :(得分:3)

我设法确切地知道发生了什么以及如何解决问题。我没有使用[STAThread]属性指定我的主入口点,因此它默认为MTA。这意味着当我调用VB6代码时,它创建了一个RPC回调线程,并没有编写对UI执行的主线程的调用。

Peter Mortensen写了一篇good explanation关于此事:

  

STA模型用于非线程安全的COM对象。那   意味着他们不处理自己的同步。常用的   这是一个UI组件。因此,如果另一个线程需要与之交互   对象(例如按下表单中的按钮)然后消息是   编组到STA线程上。窗户形成消息   系统就是一个例子。

答案 1 :(得分:2)

MSDN文档明确指出

  

您不能使用GWL_HWNDPARENT索引调用SetWindowLong来更改子窗口的父级。而是使用SetParent函数。

答案 2 :(得分:1)

你是在64位系统中运行吗?你的VB6应用程序是32位应用程序吗?如果您属于这种情况,它将解释为什么正在创建RPC调用,并且它将解释为什么您的非法黑客它无法正常工作。如果是这种情况,坏消息是现在有办法让它发挥作用。

您还应该知道.net控件may change during the lifetime of the control的底层窗口句柄。有关此问题的讨论,另请参阅SO中的this question