首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

VB 6.0 在主窗口嵌入外部程序:SetParent API 實現「窗口內窗口」

     編輯:程式設計疑難解答

核心 API:SetParent

Windows API SetParent(hWndChild, hWndNewParent) 可將指定窗口設置為另一窗口的子窗口,實現**在 VB 6.0 表單中嵌入計算器、記事本、甚至其他 VB 程序**的效果,類似「輕量級虛擬機」視覺體驗。

完整代碼示例

1. 模塊中聲明 API

' Module1.bas
Public Declare Function SetParent Lib "user32" (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Public Declare Function MoveWindow Lib "user32" (ByVal hWnd As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Long) As Long
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Const GWL_STYLE = -16
Public Const WS_VISIBLE = &H10000000
Public Const WS_CHILD = &H40000000

2. 窗體代碼嵌入計算器

Private Sub Form_Load()
    ' 1. 啟動外部程序 (這裡以計算器為例)
    Dim pid As Long
    pid = Shell("calc.exe", vbNormalFocus)
    
    ' 2. 等待窗口創建 (簡易輪詢,實際建議用 WaitForInputIdle 或定時器)
    Dim hWndCalc As Long
    Do
        hWndCalc = FindWindow(vbNullString, "計算器") ' 視系統語言調整標題
        DoEvents
        Sleep 100
    Loop Until hWndCalc <> 0
    
    ' 3. 設置為 Picture1 (或 Form 本身) 的子窗口
    ' 注意:PictureBox 無 hWnd,需用 Form.hWnd 或 UserControl.hWnd
    SetParent hWndCalc, Me.hWnd ' 或 Picture1.hWnd (需 Picture1 有句柄)
    
    ' 4. 調整樣式:去掉標題欄、邊框,變為純客戶區
    Dim style As Long
    style = GetWindowLong(hWndCalc, GWL_STYLE)
    style = style Or WS_CHILD
    style = style And Not WS_VISIBLE ' 先隱藏再顯示以刷新
    SetWindowLong hWndCalc, GWL_STYLE, style
    
    ' 5. 移動縮放至容器客戶區
    MoveWindow hWndCalc, 0, 0, Me.ScaleWidth, Me.ScaleHeight, 1
    
    ' 6. 重新顯示
    style = style Or WS_VISIBLE
    SetWindowLong hWndCalc, GWL_STYLE, style
End Sub

Private Sub Form_Resize()
    ' 窗體大小改變時同步調整嵌入窗口
    If hWndCalc <> 0 Then
        MoveWindow hWndCalc, 0, 0, Me.ScaleWidth, Me.ScaleHeight, 1
    End If
End Sub

Private Sub Form_Unload(Cancel As Integer)
    ' 程序結束時恢復外部程序獨立狀態 (可選)
    If hWndCalc <> 0 Then SetParent hWndCalc, 0
End Sub

關鍵技術點解析

步驟API/屬性作用
獲取目標句柄FindWindow / EnumWindows根據類名/標題查找外部程序主窗口句柄
建立父子關係SetParent(hChild, hParent)核心:將外部窗口掛載到 VB 窗體/容器下
修改窗口樣式GetWindowLong/SetWindowLong (GWL_STYLE)添加 WS_CHILD,移除 WS_CAPTION/WS_BORDER/WS_SYSMENU 等
尺寸定位MoveWindow / SetWindowPos填滿容器客戶區,響應 Resize 事件
容器選擇Form.hWnd / UserControl.hWndPictureBox 無窗口句柄不可直接作父窗口,需用繼承自 ContainerControl 的控件

進階:嵌入另一個 VB 6.0 程序並交互

  • 子程序編譯為 EXE,主程序 Shell 啟動並 SetParent。
  • 進程間通信 (IPC) 方式:WM_COPYDATA (SendMessage)、**命名管道**、**本地 TCP/UDP**、**共享內存 (CreateFileMapping)**、COM 暴露對象 (最符合 VB 6 風格)。
  • 子程序關閉時,主程序捕獲 WM_DESTROY 或輪詢 IsWindow(hWnd) 清理狀態。

常見問題與避坑

  • 嵌入後外部程序無法獲得焦點/鍵盤輸入無效:確保樣式包含 WS_CHILD 且父窗口可聚焦,嘗試 SetFocus API。
  • 外部程序標題欄/邊框殘留:樣式修改需完整:style = (style Or WS_CHILD) And Not (WS_CAPTION Or WS_THICKFRAME Or WS_SYSMENU Or WS_MINIMIZEBOX Or WS_MAXIMIZEBOX)。
  • VB 6.0 IDE 運行時正常,編譯 EXE 後失效:IDE 中 Me.hWnd 與編譯後不同,確保在 Form_Load 而非 Form_Initialize 獲取句柄。
  • 高 DPI 模糊/尺寸錯位:VB 6 無原生 DPI 感知,需清單文件聲明 dpiAware 或用 API SetProcessDPIAware。

總結

SetParent 是 VB 6.0 實現「窗口嵌入」的核心鑰匙。配合窗口樣式修改、尺寸同步、IPC 通信,可構建出類似 MDI 或插件宿主的複雜界面。但需注意:這僅是**視覺層面的父子關係**,進程仍獨立運行,崩潰隔離性好,但交互複雜度高。現代開發建議遷移至 .NET (WPF/WinForms) 使用 HwndHost 或 Process.Start + SetParent 封裝庫。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved