首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

Windows NT/2000/XP 下使用 VDMDBG API 管理 16 位應用程式

     編輯:關於VC++

背景知識

Windows NT 系列作業系統透過 Virtual DOS Machine (VDM) 執行 16 位 Windows 應用程式。`VDMDBG.dll` (Platform SDK 附贈) 提供一組 API 列舉、建立、終止 VDM 內的 16 位任務,適用於偵錯工具、工作管理員等系統級工具開發。

專案設定

  • 連結器輸入:加入 `VDMDBG.lib`
  • 標頭檔:`#include `
  • 執行階段:需 `VDMDBG.dll` 存在系統目錄

核心 API 概覽

函式用途
VDMEnumProcessWOW列舉所有執行 16 位 Windows 任務的 VDM (ntvdm.exe)
VDMEnumTaskWOW / Ex列舉指定 VDM 內的 16 位任務
VDMStartTaskInWOW在指定 VDM 中啟動 16 位應用程式
VDMTerminateTaskWOW終止指定 VDM 內的 16 位任務

列舉所有 16 位任務完整範例


#include 
#include 
#include 

// 回呼函式:處理每個 VDM
BOOL WINAPI ProcessEnumProc(DWORD dwProcessId, DWORD dwAttrib, LPARAM lParam)
{
    printf("\nVDM Process ID: %lu\n", dwProcessId);
    
    // 列舉該 VDM 內的任務
    VDMEnumTaskWOWEx(dwProcessId, TaskEnumProcEx, 0);
    return FALSE; // 繼續列舉
}

// 回呼函式:處理每個 16 位任務
BOOL WINAPI TaskEnumProcEx(DWORD dwThreadId, WORD hMod16, WORD hTask16,
                           PSZ pszModName, PSZ pszFileName, LPARAM lParam)
{
    printf("  Thread ID: %lu\n", dwThreadId);
    printf("  Module Handle: %u\n", hMod16);
    printf("  Task Handle: %u\n", hTask16);
    printf("  Module Name: %s\n", pszModName);
    printf("  File Name: %s\n", pszFileName);
    return FALSE; // 繼續列舉
}

int main()
{
    printf("Enumerating all 16-bit Windows tasks...\n");
    VDMEnumProcessWOW(ProcessEnumProc, 0);
    return 0;
}

啟動 16 位應用程式


// 在第一個找到的 VMD 中啟動計算機
VDMEnumProcessWOW([](DWORD pid, DWORD, LPARAM) -> BOOL {
    VDMStartTaskInWOW(pid, "calc.exe", SW_SHOW);
    return TRUE; // 只啟動第一個 VDM 即停止列舉
}, 0);

終止 16 位任務


// 先列舉取得 hTask16,再終止
VDMEnumTaskWOWEx(dwVdmPid, [](DWORD, WORD, WORD hTask, PSZ, PSZ, LPARAM) -> BOOL {
    if (strcmp(pszModName, "notepad") == 0) {
        VDMTerminateTaskWOW(dwVdmPid, hTask);
        return TRUE; // 找到即停止
    }
    return FALSE;
}, 0);

重要限制與注意事項

  • 僅支援 16 位 Windows 應用:DOS 程式 (如 `edit.com`) 不在 `VDMEnumProcessWOW` 列舉範圍內
  • 終止風險:`VDMTerminateTaskWOW` 類似 `TerminateProcess`,可能導致資料遺失、VDM 不穩定。優先嘗試傳送 `WM_CLOSE` 給視窗
  • DOS 程式處理:需自行列舉所有 `ntvdm.exe` 進程 (PSAPI),排除已知的 WOW VDM,剩餘即為 DOS VDM
  • 權限需求:需足夠權限存取目標進程

DOS VDM 偵測策略


// 1. 取得所有 WOW VDM PID
std::set wowPids;
VDMEnumProcessWOW([](DWORD pid, DWORD, LPARAM p) -> BOOL {
    static_cast*>(p)->insert(pid);
    return FALSE;
}, (LPARAM)&wowPids);

// 2. 列舉所有 ntvdm.exe (PSAPI)
DWORD pids[1024], cbNeeded;
EnumProcesses(pids, sizeof(pids), &cbNeeded);
for (int i = 0; i < cbNeeded/sizeof(DWORD); ++i) {
    HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, pids[i]);
    TCHAR name[MAX_PATH];
    GetModuleBaseName(h, NULL, name, MAX_PATH);
    if (_tcsicmp(name, _T("ntvdm.exe")) == 0 && !wowPids.count(pids[i])) {
        printf("DOS VDM found: PID=%lu\n", pids[i]);
    }
    CloseHandle(h);
}

現代替代方案

Windows 10/11 已移除 NTVDM (x64 版本),16 位應用無法原生執行。建議:

  • 使用 DOSBox、vDos 等模擬器
  • 應用程式移植至 32/64 位
  • Windows 10 32 位版本仍支援 NTVDM (需啟用「舊版元件」)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved