Сообщений 2    Оценка 122        Оценить  
Система Orphus

Как получить список 16-битных задач на Windows NT?

Автор: Александр Федотов
Опубликовано: 08.10.2001
Исправлено: 13.03.2005
Версия текста: 1.0

Тестовое приложение NTTASK16
Тестовое приложение Process Viewer

Несмотря на то, что Windows NT является целиком 32-разрядной системой, она способна выполнять большинство 16-битных приложений, как приложений MS-DOS, так и 16-битных приложений для Windows 3.1. В Windows NT 3.5 и более ранних версиях, каждая 16-битная программа выполнялась в своей собственной виртуальной машине. Каждая виртуальная машина выглядела как относительно полная Windows 3.1-система, из-за чего эта технология получила название Windows On Windows (WOW). Деятельность каждой 16-битной программы была полностью отделена от других 16-битных программ. В результате, сбои в одной 16-битной программе никак не влияли на остальные программы в системе.

Начиная с версии 3.51, Windows NT приобрела возможность запускать несколько 16-битных программ в одной виртуальной машине, разделяя одно и тоже адресное пространство и таблицу локальных дескрипторов (LDT) между программами. В результате, как только загружена одна 16-битная программа, последующие 16-битные программы стартуют быстрее и используют меньше памяти. Обратная сторона медали состоит в том, что если одна из 16-битных программ фатально завершается, то вся виртуальная машина целиком перестает существовать. К счастью, возможность запускать 16-битные программы в отдельной виртуальной машине сохранилась.

Виртуальная DOS-машина реализована в Windows NT в виде Win32-процесса под названием NTVDM.EXE. Ecли не брать во внимание тот факт, что NTVDM использует значительное количество недокументированных функций из NTDLL.DLL, то в остальном это такой же процесс, как и другие Win32-процессы. Каждой исполняющейся 16-битной программе соответствует один поток в процессе NTVDM.

Windows NT предоставляет интерфейс для управления виртуальными машинами в составе библиотеки VDMDBG.DLL. В частности, для перечисления 16-битных задач служит функция VDMEnumTaskWOWEx:

INT
WINAPI
VDMEnumTaskWOWEx(
    IN DWORD           dwProcessId,
    IN TASKENUMPROCEX  pfnEnumProc,
    IN LPARAM          lParam
    );

где

dwProcessId Идентификатор процесса NTVDM.EXE. Как было отмечено, в системе может быть запущено несколько виртуальных машин одновременно. С помошью этого параметра мы указываем, 16-битные задачи какой из виртуальных машин мы хотим получить.
pfnEnumProc Адрес пользовательской функции, которая будет вызвана для каждой 16-битной задачи в рамках указанной виртуальной машины.
lParam Дополнительный пользовательский параметр, который без изменений передается в функцию, указанную параметром pfnEnumProc.

Пользовательская функция, адрес которой передается в качестве параметра VDMEnumTaskWOWEx, должна соответствовать следующему прототипу:

typedef BOOL (CALLBACK * TASKENUMPROCEX)(
    IN DWORD  dwThreadId,
    IN WORD   hMod16,
    IN WORD   hTask16,
    IN LPSTR  pszModName,
    IN LPSTR  pszFileName,
    IN LPARAM lParam
    );

В отличие от принятой в Win32 практики, пользовательская функция должна вернуть FALSE, чтобы продолжать перечисление, и TRUE - чтобы прервать перечисление. Параметрами функции являются:

dwThreadId Указывает идентификатор Win32-потока в процессе NTVDM, который соответствует данной 16-битной задаче.
hMod16 Идентификатор 16-битного модуля, на основе которого была создана задача.
hTask16 Идентификатор 16-битной задачи.
pszModName Имя модуля, идентификатор которого был указан в параметре hMod16. Как правило, имя модуля совпадает с именем исполняемого файла без расширения, однако бывают и исключения.
pszFileName Полный путь к файлу, из которого был загружен исполняемый модуль задачи.
lParam Пользовательский параметр.

Чтобы перечислить все 16-битные задачи в системе, мы должны каким-либо образом найти все виртуальные машины. С одной стороны, это можно сделать просто перечислив все 32-битные процессы, как это описано в статье Как получить список запущенных процессов?, и выбрать из них процессы с именем NTVDM.EXE. Тестовое приложение Process Viewer использует этот подход.

С другой стороны, можно воспользоваться функцией VDMEnumProcessWOW, которая специально предназначена для перечисления виртуальных машин WOW:

INT
WINAPI
VDMEnumProcessWOW(
    IN PROCESSENUMPROC pfnEnumProc,
    IN LPARAM          lParam
);

typedef BOOL (CALLBACK * PROCESSENUMPROC)(
    IN DWORD	dwProcessId,
    IN DWORD	dwAttrib,
    IN LPARAM	lParam
    );

Здесь

pfnEnumProc Адрес пользовательской функции, которая будет вызвана для каждого экземпляра виртуальной машины.
lParam Произвольный пользовательский параметр.
dwProcessId Идентификатор процесса виртуальной машины.
dwAttrib Атрибуты виртуальной машины. В настоящее время определен только один атрибут с именем WOW_SYSTEM, который говорит о том, что эта виртуальная машина является системной виртуальной машиной. Новые 16-битные задачи будут создаваться в этой виртуальной машине, если явно не указано иначе.

В качестве иллюстрации использования функций VDMEnumTaskWOWEx и VDMEnumProcessWOW предлагается программа NTTASK16, полный текст которой приведен ниже.

#define STRICT
#include <windows.h>
#include <stdio.h>
#include <vdmdbg.h>

#pragma comment(lib, "vdmdbg.lib")

BOOL
CALLBACK
TaskEnumProcEx(
    IN DWORD dwThreadId,
    IN WORD hMod16,
    IN WORD hTask16,
    IN LPSTR pszModName,
    IN LPSTR pszFileName,
    IN LPARAM lParam
    )
{
    printf("\tThread ID:\t%u (0x%X)\n", dwThreadId, dwThreadId);
    printf("\tModule handle:\t0x%04X\n", hMod16);
    printf("\tTask handle:\t0x%04X\n", hTask16);
    printf("\tModule Name:\t%s\n", pszModName);
    printf("\tFile Name:\t%s\n\n", pszFileName);

    return FALSE;
} 

BOOL
CALLBACK
ProcessEnumProc(
    IN DWORD dwProcessId,
    IN DWORD dwAttrib,
    IN LPARAM lParam
    )
{
    printf("VDM Process ID: %u (0x%X)\n", dwProcessId, dwProcessId);
    printf("Attributes: 0x%08X\n", dwAttrib);

    VDMEnumTaskWOWEx(dwProcessId, TaskEnumProcEx, 0);
    
    return FALSE;
}

int
main(
    int argc,
    char * argv[]
    )
{
    VDMEnumProcessWOW(ProcessEnumProc, 0);

    return 0;
}

Cсылки

  1. Under the Hood by Matt Pietrek, Microsoft Systems Journal, August 1998.
  2. Q182559 HOWTO: Use VDMDBG Functions on Windows NT, Microsoft Knowledge Base.

Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав.
    Сообщений 2    Оценка 122        Оценить