程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 如何在Windows NT、Windows 2000和Windows XP中使用VDMDBG函數

如何在Windows NT、Windows 2000和Windows XP中使用VDMDBG函數

編輯:關於VC++

摘要

即使是在 32位環境中編寫程序,也經常碰到處理 16位應用程序的情況。在 Windows NT 中,16位程序是運行在虛擬 DOS 機(VDM)中的。VDMDBG.dll 包含許多處理16位程序的有用函數,這個庫是 Platform SDK 的一部分。

VDMDBG 中的函數提供了很好的方式在 VDM 中枚舉、創建和終止 16位進程(任務)。本文將描述如何在Windows NT、Windows 2000 和 Windows XP 中使用這些函數。

如果需要使用 VDMDBG 函數,你的工程必須鏈接 VDMDBG.lib。

下面提及的 VDMDBG 函數僅僅是一個子集。未提及的函數只與調試器有關。

枚舉 VDMs

VDMEnumProcessWOW() 函數提供了一種簡單的方式來枚舉所有 運行 Windows 任務的 VDMs。這些 VDMs 包含 WowExec.exe 任務。DOS VDMs 不在枚舉之列。 該函數的聲明如下:INT WINAPI VDMEnumProcessWOW( PROCESSENUMPROC fp, LPARAM lparam );

該函數的返回值是當前運行的 VDMs 數,或者終止枚舉前的枚舉數目。fp 是一個回調函數指針。該函數針對被枚舉的 VDM 被調用一次。lParam 是用戶定義的值,這個值被傳遞給回調函數。

PROCESSENUMPROC 的聲明如下:

typedef BOOL ( WINAPI *PROCESSENUMPROC )(
DWORD dwProcessId,
DWORD dwAttributes,
LPARAM lpUserDefined
);

這個函數返回 TRUE 停止枚舉,返回 FALSE 繼續枚舉。dwProcessId 是 NTVDM.exe 進程ID。在調用其它VDM函數時(下面會提到這些函數),你會需要此 ID。

枚舉 16-位 Windows 任務

你可以用 VDMEnumTaskWOW() 和 VDMEnumTaskWOWEx() 在特定的 VDM 中枚舉任務。兩者的差別是 VDMEnumTaskWOWEx() 為回調函數提供更多的信息。你只能使用 VDMEnumProcessWOW() 返回的 VDMs 來調用這些任務枚舉函數。用 DOS VDMs 是沒有意義的,因為 DOS 應用程序運行在自己的 VDM 中。這兩個函數的惡聲明如下:

INT WINAPI VDMEnumTaskWOW( DWORD dwProcessId, TASKENUMPROC fp,LPARAM lparam );
INT WINAPI VDMEnumTaskWOWEx( DWORD dwProcessId, TASKENUMPROCEX fp,
LPARAM lparam );

這兩個函數的返回值是當前運行在指定 VDM 中的任務數,或者每局終止前的枚舉數。dwProcessId 是 VDM 的惡進程ID。fp 是指向回調函數的指針。每個被枚舉的任務都調用該函數。lparam 是傳給回調函數的用戶定義的值。

TASKENUMPROC 和 TASKENUMPROCEX 的定義如下:

typedef BOOL ( WINAPI *TASKENUMPROC )(
DWORD dwThreadId,
WORD hMod16,
WORD hTask16,
LPARAM lpUserDefined
);
typedef BOOL ( WINAPI *TASKENUMPROCEX )(
DWORD dwThreadId,
WORD hMod16,
WORD hTask16,
PSZ pszModName,
PSZ pszFileName,
LPARAM lpUserDefined
);

這些函數返回 TRUE 停止枚舉,返回 FALSE 繼續枚舉。你可以在某個調用中用 hTask16 終止任務。

枚舉例子

// Enumerate all 16-bit tasks on the system.
#include <windows.h>
#include <stdio.h>
#include <vdmdbg.h>
BOOL WINAPI ProcessEnumProc( DWORD, DWORD, LPARAM );
BOOL WINAPI TaskEnumProcEx( DWORD, WORD, WORD, PSZ, PSZ, LPARAM );
void main()
{
  // 枚舉 VDMs.
  VDMEnumProcessWOW( (PROCESSENUMPROC)ProcessEnumProc,(LPARAM)NULL );
}
BOOL WINAPI ProcessEnumProc( DWORD dwProcessId, DWORD dwAttrib,LPARAM t )
{
  printf("\nProcess ID: %d\n", dwProcessId);
  // 使用 VDM 進程 ID 枚舉其所有任務
  VDMEnumTaskWOWEx(
    dwProcessId,
    (TASKENUMPROCEX)TaskEnumProcEx,(LPARAM)NULL);
  // 繼續枚舉
  return FALSE;
}
BOOL WINAPI TaskEnumProcEx( DWORD dwThreadId, WORD hMod16, WORD hTask16,
PSZ pszModName, PSZ pszFileName, LPARAM lParam )
{
  // 顯示任務信息
  printf("Thread ID: %d\n", dwThreadId);
  printf("Module handle: %d\n", hMod16);
  printf("Task handle: %d\n", hTask16);
  printf("Module Name: %s\n", pszModName);
  printf("File Name: %s\n", pszFileName);
  // 繼續枚舉
  return FALSE;
}

創建 16-位 任務

VDMStartTaskInWOW() 函數在 VDM 中創建一個任務。其聲明如下:

BOOL WINAPI VDMStartTaskInWOW( DWORD dwProcessId, LPSTR lpCommandLine,WORD wShow );

如果任務成功啟動,則該函數返回 TRUE,否則返回 FALSE。dwProcessId VDM 進程ID。lpCommandLine 是一個字符串,表示16-位應用程序的文件名和所帶的命令行參數。wShow 表示如何顯示窗口。wShow 可以是 16-位 ShowWindow() 函數使用的任何有效值。

終止 16-位任務

調用 VDMTerminateTaskWOW() 可以終止 VDM 中的任務。其聲明如下:

BOOL WINAPI VDMTerminateTaskWOW( DWORD dwProcessId, WORD htask );

如果終止成功該函數返回 TRUE,否則返回 FALSE,dwProcessId 是 VDM 進程ID。hTask 是任務句柄。該任務句柄可以通過調用 VDMEnumTaskWOW() 或者 VDMEnumTaskWOWEx() 獲得。

這個方法大體上與 Win32 中的 TerminateProcess()相當。如果可能,應盡量避免使用。有時任務無法干淨地退出,所以有可能數據丟失。與 Win32 不同,在終止任務後無法保證清除 WowExec。從而造成 VDM 混亂和不可用。為了干淨地終止任務,需發送 WM_CLOSE 到其頂層窗口。

關於 16-位 DOS 程序

VDMDBG 的諸函數中沒有任何專門處理 16-位 DOS 程序的函數。為了枚舉 DOS VDMs,你得用另外一個方法。首先,你得用 VDMEnumProcessWOW() 獲得所有 Win16 VDMs 清單,然後想辦法(比如用 PSAPI)枚舉所有 NTVDM.exe 實例。枚舉列表中任何不在 Win16 之列的 NTVDM.exe 就是 DOS VDM。你可以用 CreateProcess() 以及 TerminateProcess() 創建和終止 16-位 DOS 程序。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved