【问题标题】:SetWindowLong HangingSetWindowLong Hanging
【发布时间】:2012-04-18 19:20:04
【问题描述】:

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

我可以通过这三个步骤不断地重现这个问题。

  1. 创建 .NET 表单
  2. 初始化 WaitWindow COM 对象,在传递 .NET 窗体句柄时调用 COM 对象上的 ShowWindow
  3. 在 VB6 中调用 SetWindowLong 方法

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 线程。我还不确定,但我感觉这与跨线程问题有关。

【问题讨论】:

  • 注意:我无法更新代码的 VB6 部分,因为这是现有系统的一部分,并且在此特定条件之前一直“正常”工作。

标签: .net winapi vb6 interop pinvoke


【解决方案1】:

MSDN 文档清楚地说明了

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

【讨论】:

  • 我确实阅读了文档,虽然它没有说明为什么你不应该调用它。我忘了提到我无法修改 VB6 代码,因为它是许多模块引用的现有代码。我很好奇它为什么会起作用,除非我将它传递给 .NET 表单句柄。
  • 可能是因为这会导致发送消息。尝试使用 windbg 为每个线程获取堆栈转储。另见blogs.msdn.com/b/oldnewthing/archive/2007/12/28/6882760.aspx
  • MS不需要解释你不能这样做。他们告诉你不要这样做,所以不要这样做。
【解决方案2】:

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

Peter Mortensen 写了一封 good explanation 关于此:

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 我在 Windows XP SP3 32 位中运行一切,感谢上帝...他的项目已经让他头疼了 :p。不过感谢您的建议。
    猜你喜欢
    • 1970-01-01
    • 2021-11-05
    • 2022-12-27
    • 1970-01-01
    • 2012-03-06
    • 2010-09-22
    • 1970-01-01
    • 2011-12-22
    • 1970-01-01
    相关资源
    最近更新 更多