Vc
ToolTip(всплывающей подсказки)
Первоначально необходимо создать окно класса TOOLTIPS_CLASS, потом заполнить структуру TOOLINFO:
typedef 
struct tagTOOLINFO{ UINT
cbSize; UINT
uFlags; HWND
hwnd; UINT_PTR
uId; RECT
rect; HINSTANCE
hinst; LPTSTR
lpszText; #if
(_WIN32_IE > = 0x0300)
LPARAM lParam;
#endif
} TOOLINFO, NEAR *PTOOLINFO, FAR *LPTOOLINFO;

Определяем два параметра в этой структуре, которые имеют для нас значение uFlags и lpszText. uFlags выбираем равным TTF_TRACK, что означает возможность использования посылки сообщений выбирающих позицию для ToolTip-a и видимость. lpszText - задание текста, который мы хотим выводить.

Теперь мы посылаем сообщение в систему, о желании создать всплывающую подсказку, куда передаём ссылку на нашу структуру SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti).

Затем посылаем сообщение TTM_TRACKPOSITION, которая задаёт координаты всплывающей подсказки SendMessage(hwndTT, TTM_TRACKPOSITION, 0, (LPARAM)(DWORD) MAKELONG(m_x, m_y)), где m_x и m_y координаты x и y на экране.

И в последнюю очередь посылаем сообщение о активизации всплывающей подсказки S endMessage(hwndTT, TTM_TRACKACTIVATE, true, (LPARAM)(LPTOOLINFO) &ti), где true параметр указывающий на отображение подсказки, при выборе false, подсказка будет скрыта.

Просмотр графических файлов(bmp,pcx,tiff,gif,jpeg)
Функции стандартного ввода/вывода (printf, scanf)
Работа с ADO
Установка ловушек
Создание драйверов
Драйвер с нуля

Ссылки:
Первое с чем сталкивается программист, решивший заняться драйверами это почти полное отсутствие русскоязычной литературы по данной теме. За год поисков мне удалось найти всего три книги на русском, в которых хотя бы немного говориться о драйверах:
-----------------------
1. Свен Шрайбер «Недокументированные возможности Windows 2000». Издательство «Питер» 2002 год.
Здесь очень хорошо описан механизм динамической загрузки драйвера.
------------------
2. П. И. Рудаков, К. Г. Финогенов «Язык ассемблера: уроки программирования»
Диалог МИФИ 2001 год. Очень полезная книга для того, что бы понять, как писать драйвера без всякий Wizard-ов.
-----------------------------
3. Светлана Сорокина, Андрей Тихонов, Андрей Щербаков «Программирование драйверов и систем безопасности». Издательство «БХВ-Петербург» 2002 год. Здесь хорошо описывается многоуровневая модель драйверов.


Для начала надо установить на компьютер Visul C++ 6.0, MSDN и NTDDK установку проводить желательно именно в этом порядке. Лично я пользуюсь редактором UltraEdit для работы с текстами драйверов, но в принципе исходный код драйвера можно набирать в любом текстовом редакторе, хоть в NotePad.
Создадим папку, в которой мы будем работать с драйвером (пусть это будет C:\myDriver).
В этой папке создадим 5 файлов:
1. myDrv.c
2. myDrv.h
3. myDrv.rc
4. MAKEFILE
5. SOURCES

Начнем с последнего файла:
В SOURCES скопируйте следующее:
TARGETNAME=myDrv
TARGETPATH=obj
TARGETTYPE=DRIVER

SOURCES=myDrv.c MyDrv.rc
В MAKEFILE скопируйте следующее:
!INCLUDE $(NTMAKEENV)\makefile.def

В myDrv.rc скопируйте следующее:
#include <windows.h>
#include <ntverp.h>
#define VER_FILETYPE VFT_DRV
#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
#define VER_FILEDESCRIPTION_STR "Generic Port I/O"
#define VER_INTERNALNAME_STR "myDrv.sys"
#include "common.ver"


А вот так должен выглядеть myDrv.h:

#define FIRST_IOCTL_INDEX 0x800
#define FILE_DEVICE_myDRV 0x00008000


#define TEST_SMTH CTL_CODE(FILE_DEVICE_myDRV, \
FIRST_IOCTL_INDEX + 101, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)



Теперь обратимся к тексту самого драйвера myDrv.c:
#include "ntddk.h"
#include "myDrv.h"
#include "parallel.h"

#define NT_DEVICE_NAME L"\\Device\\myDrv"
#define DOS_DEVICE_NAME L"\\DosDevices\\myDrv"

//структура расширения устройства
typedef struct _DEVICE_EXTENSION
{
PDRIVER_OBJECT DriverObject;
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
HANDLE Handle;

} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

//прототипы функций
NTSTATUS
DriverDeviceControl(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);

VOID
DriverUnload(IN PDRIVER_OBJECT DriverObject);

NTSTATUS
DriverOpen(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);

NTSTATUS
DriverClose(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////реализация функций

NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
PDEVICE_OBJECT deviceObject;
UNICODE_STRING deviceNameUnicodeString;
UNICODE_STRING deviceLinkUnicodeString;
PDEVICE_EXTENSION extension;
NTSTATUS ntStatus;

RtlInitUnicodeString(&deviceNameUnicodeString, NT_DEVICE_NAME);

ntStatus = IoCreateDevice(DriverObject,
sizeof (DEVICE_EXTENSION),
&deviceNameUnicodeString,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&deviceObject);

if (!NT_SUCCESS(ntStatus)) return ntStatus;

DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverDeviceControl;
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverOpen;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverClose;

extension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
extension->DeviceObject = deviceObject;
extension->DriverObject = DriverObject;

// Create counted string version of our Win32 device name.
RtlInitUnicodeString(&deviceLinkUnicodeString, DOS_DEVICE_NAME);

// Create a link from our device name to a name in the Win32 namespace.
ntStatus = IoCreateSymbolicLink(&deviceLinkUnicodeString, &deviceNameUnicodeString);
if (!NT_SUCCESS(ntStatus))
{
IoDeleteDevice(deviceObject);
return ntStatus;
}

return STATUS_SUCCESS;
}


//-------------------------------------------------------------------------------------------------------------------
VOID
DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING deviceLinkUnicodeString;
PDEVICE_EXTENSION extension;
PIRP pNewIrp = NULL;
ULONG m_size;
NTSTATUS ntStatus;
extension = DriverObject->DeviceObject->DeviceExtension;

// Create counted string version of our Win32 device name.
RtlInitUnicodeString(&deviceLinkUnicodeString, DOS_DEVICE_NAME);


// Delete the link from our device name to a name in the Win32 namespace.
IoDeleteSymbolicLink(&deviceLinkUnicodeString);


// Finally delete our device object
IoDeleteDevice(DriverObject->DeviceObject);
}

//-------------------------------------------------------------------------------------------------------------------
NTSTATUS
DriverOpen(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}

//-------------------------------------------------------------------------------------------------------------------
NTSTATUS
DriverClose(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}

//-------------------------------------------------------------------------------------------------------------------
NTSTATUS
DriverDeviceControl(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
NTSTATUS ntStatus;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION extension;
PULONG ioBuffer;
ULONG ioControlCode;
ULONG port = 0;

Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
irpStack = IoGetCurrentIrpStackLocation(Irp);
extension = DeviceObject->DeviceExtension;
ioBuffer = Irp->AssociatedIrp.SystemBuffer;
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
switch (ioControlCode)
{
case TEST_SMTH:
ioBuffer[0] =(ULONG)DriverEntry;//В буфер обмена адрес функции DriverEntry
Irp->IoStatus.Information = 4;
break;

default:
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
}

ntStatus = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return ntStatus;
}


Немного поясню содержимое файла myDrv.c. Итак, по порядку:
#define NT_DEVICE_NAME L"\\Device\\myDrv"
#define DOS_DEVICE_NAME L"\\DosDevices\\myDrv"- Эти строки служат для задания символических имен текстовыми строками с именами объекта устройства, который будет создан нашим драйвером.
Далее приведены прототипы используемых функций. Этим функциям можно дать произвольные имена, НО их сигнатура (состав параметров с типом возвращаемого значения) жестко заданы системой.
[2]:Программная часть драйвера начинается с обязательной функции с именем DriverEntry(), которая автоматически вызывается системой на этапе загрузки драйвера. Эта функция должна содержать все действия по его инициализации. В качестве первого параметра наша функция получает указатель на объект драйвера типа PDRIVER_OBJECT.
Небольшое лирическое отступление:
При загрузке драйвера системы создает объект драйвера (driver object), олицетворяющий образ драйвера в памяти. С другой стороны, объект драйвера представляет собой структуру, содержащую необходимые для функционирования драйвера данные и адреса функций. В процессе инициализации драйвера (в DriverEntry()) создаются один или несколько объектов устройств (device object), олицетворяющие те устройства с которыми будет работать драйвер. Этот самый device object, необходим для правильного функционирования драйвера и создается (как и в нашем случае) даже тогда, когда драйвер не имеет отношение к какому-либо реальному устройству.

Далее, в первых строках DriverEntry мы определяем используемые в ней данные, в т.ч. указатель на device object и две символьные строки UNICODE_STRING с именами устройств. Системные программы взаимодействуют с объектом устройства, созданным драйвером, посредством указателя на него. Однако для прикладных программ объект устройства представляется одним из файловых объектов и обращение к нему осуществляется по имени (в приложении мы будем использовать функцию CreateFikle()).
Надо иметь в виду, что объект устройства должен иметь два имени, одно-в пространстве имен NT, другое-в пространстве имен Win32. Эти имена должны представлять собой структуры UNICODE_STRING. Имена объектов устройств составляются по определенным правилам. NT-имя предваряется префиксом \Device\, а Win32-имя -префиксом \??\ ( или \DosDevice\). При указании имен в Си-программе знак обратной косой черты удваивается. Для того чтобы указанное в программе драйвера имя можно было использовать в приложении для открытия устройства, следует создать символическую связь между обоими заданными именами устройств. Для этого используем функцию IoCreateSymbolicLink(). Следующая обязательная операция-создание объекта устройства-осуществляется вызовом функции IoCreateDevice().
Первый параметр этой функции это указатель на объект драйвера, поступающий в DriverEntry(). Второй параметр определяет размер расширения устройства-структуры, которая служит для передачи данных между функциями драйвера (состав этой структуры произволен, и полностью определяется разработчиком). Третий параметр-созданное ранее NT-имя устройства. Далее идут: тип устройства (FILE_DEVICE_UNKNOWN), специальные характеристики (0), FALSE означает, что у нас однопоточное устройство. Наконец, последний параметр является выходным-через него функция возвращает указатель на созданный объект устройства.
Далее необходимо занести в объект драйвера адреса основных функций, включенных программистом в текст драйвера. Массив MajorFunction является одним из элементов структурной переменной. В этот массив мы и заносим адреса основных функций (т.е. функций которые вызываются системой автоматически в ответ на определенные действия приложения или устройства). Завершается функция оператором return с указанием кода успешного завершения.
Функция DriverUnload() вызывается при выгрузке драйвера. Здесь мы должны выполнить действия по удалению объекта устройства, созданного в DriverEntry().
Функции DriverOpen и DriverClose в нашем случае ничего не делают и возвращают просто STATUSS_SUCCESS. Кстати, все эти функции тоже могут иметь произвольные имена, но передаваемые им параметры строго фиксированы.

[2]:Вот мы и добрались до «самой содержательной» с точки зрения прикладного программирования функции DriverDeviceControl(). Эта функция вызывается каждый раз, когда драйверу приходит IRP-пакет с каким либо IOCTL_… кодом. Грубо говоря, IRP-пакет-это структура, передавая указатель на которую, приложение может «общаться» с драйвером (как впрочем, и драйвер может «общаться» с другим драйвером). Более подробное описание того, что такое IRP-пакет можно найти здесь http://www.lcard.ru/~gorinov/texts/irp99.html .
IRP-пакет содержит так называемый системный буфер, служащий для обмена информацией (переменная SystemBuffer). Таким образом, нам надо получить доступ к IRP-пакету, а через него к SystemBuffer. Для этого объявляем переменную irpStack типа указателя на стековую область ввода-вывода PIO_STACK_LOCATION, и, кроме того, переменная ioBuffer, в которую будет помещен адрес системного буфера обмена. В нашем случае тип этой переменной-PULONG, в действительности тип передаваемых данных может быть каким угодно. С помощью функции IoGetCurrentIrpStackLocation() в переменную irpStack помещается адрес стековой области ввода-вывода, а в переменную ioBuffer заноситься адрес системного буфера из структуры IRP. Системный буфер входит в объединение (union) с именем AssociatedIrp, поэтому мы используем конструкцию Irp->AssociatedIrp.SystemBuffer.
Конструкция switch-case анализирует содержимое ячейки IoControlCode и в зависимости от значения кода выполняет те или иные действия. В нашей программе только один код действия TEST_SMTH. Засылка в буфер обмена адреса функции DriverEntry() осуществляется через указатель на этот буфер. В переменную Irp->IoStatus.Information заносим количество (4) пересылаемых байт. Для завершения IRP-пакета вызываем IoCompleteRequest().
Итак, драйвер мы написали. Теперь надо его скомпилировать. Т.к. процесс компиляции идет из командной строки, то для этой цели гораздо удобнее пользоваться bat-файлом. Создадим небольшой bat-файл с именем, допустим, Crt.bat и со следующим содержанием:

%SystemRoot%\system32\cmd.exe /c "cd C:\NTDDK\bin&&setenv.bat C:\NTDDK&&cd c:\myDriver \&&build -ceZ"
pause

Замечание:
NTDDK у меня установлено в корень С:\, если у Вас по другому- то вместо C:\NTDDK\bin и C:\NTDDK пропишите полные пути к соответствующим папкам.

Итак, теперь запустим наш Crt.bat. После окончания компиляции в папке C:\myDriver\objfre\i386 находим готовый драйвер myDrv.sys. Наш драйвер пока умеет только, лишь загружаться/выгружаться и по специальному запросу-посылает приложению адрес одной из своих процедур.

Теперь займемся написанием приложения работающего с нашим драйвером. Еще раз напоминаю, что мы работаем под Win2000. Эта ОС позволяем реализовать динамическую загрузку/выгрузку драйвера.
Примечание:
Точнее динамическую загрузку/выгрузку служб (service), но т.к. в Win2000 в качестве службы можно рассматривать и драйвер, я буду использовать оба эти термина, подразумевая, в данной статье, наш драйвер.

Для загрузки и выгрузки драйверов используется диспетчер управления службами SC Manager (Service Control Manager). Прежде чем вы сможете работать с интерфейсом SC, вы должны получить дескриптор диспетчера служб. Для этого необходимо обратиться к функции OpenSCManager(). Дескриптор диспетчера служб необходимо использовать при обращении к функциям CreateServise() и OpenService(). Дескрипторы, возвращаемые этими функциями необходимо использовать при обращении к вызовам, имеющим отношение к конкретной службе. К подобным вызовам относятся функции ControlService(), DeleteService() и StartService(). Для освобождения дескрипторов обоих типов используется вызов CloseServiceHandle().
Загрузка и запуск службы подразумевает выполнение следующих действий:
1. Обращение к функции OpenSCManager() для получения дескриптора диспетчера
2. Обращение к CreateServise() для того, чтобы добавить службу в систему.
Если такой сервис уже существует, то CreateServise() выдаст ошибку с кодом 1073 (код ошибки можно прочитать GetLastError()) данная ошибка означает, что сервис уже существует и надо вместо CreateServise() использовать OpenService().
3. Обращение к StartService() для того, чтобы перевести службу в состояние функционирования.
4. Если служба запустилась успешно, то можно вызвать CreateFile(), для получения дескриптора, который мы будем использовать уже непосредственно при обращении к драйверу.
5. И по окончании работы не забудьте дважды обратиться к CloseServiceHandle() для того чтобы освободить дескрипторы диспетчера и службы.

Если на каком-то шаге этой последовательности возникла ошибка, нужно выполнить действия обратные тем, которые вы успели выполнить до ошибки.
Надо помнить о том, что при обращении к функциям подобным CreateServise() необходимо указывать полное имя исполняемого файла службы (в нашем случае полный путь и имя myDrv.sys).

Посмотрим на исходный текст простого консольного приложения, написанного на
Visual C++ 6.0:

#include <conio.h>
#include "LoadDRV.h"
#include <string.h>
#include <stdio.h>


void main()
{
LPTSTR m_name = new char[20];
strcpy(m_name, "myDrv.sys");

if (drvLoad(m_name)) TestSmth();

drvUnLoad(m_name);
delete m_name;
}

//-----------------------------------------------------------------------------
//создаем и посылаем драйверу IRP-запрос
int TestSmth(void)//0x800 + 101
{
int test = 0;
DWORD ReturetLength = 0;

DeviceIoControl(hDevice, IOCTL_TEST_SMTH, NULL, 0,
&test, 4, &ReturetLength, NULL);

printf("TestSmth= %i\n",test);
return test;
}


///**************Функции динамической загрузки************************
bool drvLoad(char* name)
{
printf (name);
hSCManager=NULL;
hService=NULL;
bool status;

status=FALSE;


if(OpenManager())
{
if(drvCreateService(name))
{
if(drvStartService(name))
{
status=TRUE;
printf("\n Driver is now load...\n");
}
}
}

hDevice = CreateFile ("//./myDrv", GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);

return status;
}

//---------------------------------------------------------------------

bool OpenManager()
{
bool status;
status=FALSE;

if(hSCManager!=NULL)
{
CloseServiceHandle (hSCManager);
hSCManager=NULL;
}

hSCManager=OpenSCManager (NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (hSCManager == NULL)
{
error(_OpenSCManager);
} else status=TRUE;

return status;
}

//---------------------------------------------------------------------
bool drvCreateService(PCHAR pDrvName)
{
LPTSTR lpBuffer;
lpBuffer = new char[256];
bool status = FALSE;
LPTSTR awPath; // путь к драйверу с именем pDrvName

// формируем путь к pDrvName, драйвер должен лежать рядом с exe-шником

GetCurrentDirectory(256, lpBuffer);
strcat(lpBuffer,"\\");
strcat(lpBuffer,pDrvName);
awPath = lpBuffer;

hService = CreateService(hSCManager,pDrvName,pDrvName,SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START,SERVICE_ERROR_NORMAL,awPath,NULL,NULL,NULL,NULL,NULL);

if(!hService)
{
error(_CreateService);
status = drvOpenService(pDrvName);//Пытаемся открыть службу
}
else status=TRUE;

delete lpBuffer;
return status;
}

//--------------------------------------------------------------------
bool drvOpenService(PCHAR name)
{

bool status;
status=FALSE;
if(hService!=NULL) CloseService();

hService=OpenService(hSCManager,name,SERVICE_ALL_ACCESS);
if (!hService) error(_OpenService);
else status=TRUE;
return status;
}

//---------------------------------------------------------------------
bool drvStartService(PCHAR name)
{
bool status;
status=FALSE;
if(!StartService(hService,0,NULL))
{
error(_StartService);
printf("Deleting service...");
drvDeleteService(name)
}
else status=TRUE;
return status;
}

//---------------------------------------------------------------------
bool drvDeleteService(PCHAR name)
{
bool status;
status=FALSE;
CloseService();
if(!DeleteService(hService)) error(_DeleteService);
else status=TRUE;
return status;
}

//-------------------------------------------------------------------
void CloseService()
{
CloseServiceHandle (hService);
hService=NULL;
}

//-------------------------------------------------------------------
int drvUnLoad(PCHAR name)
{
int status;
status=FALSE;

if (hDevice!=INVALID_HANDLE_VALUE)
{
if(!CloseHandle(hDevice)) error(_CloseHandle);
hDevice=INVALID_HANDLE_VALUE;
}

if (hService)
{
status = ControlService(hService,SERVICE_CONTROL_STOP,&ServiceStatus);
if(!status) error(_SERVICE_CONTROL_STOP);

status = DeleteService(hService);
if(!status) error(_DeleteService);

status = CloseServiceHandle(hService);
if(!status) error(_CloseServiceHandle);
}

if(!CloseServiceHandle(hSCManager)) error(_CloseServiceHandle);
if (status) printf("Driver Unload... SUCCESS\n");
return status;
}

//---------------------------------------------------------------------
void error(error_index erIndex)
{

DWORD err;
err=GetLastError();
switch(erIndex)
{
case _OpenSCManager:
printf("OpenSCManager failed with Error=%i\n",err);
break;

case _GetFullPathName:
printf("GetFullPathName failed with Error=%i\n",err);
break;

case _CreateService:
switch (err)
{
case 1073:
printf("The specified service already exists.\n");
printf("opening this service...");
break;
default:
printf("CreateService failed with Error=%i\n",err);
}
break;

case _OpenService:
printf("OpenService failed with Error=%i\n",err);
break;

case _StartService:
printf("StartService failed with Error=%i\n",err);
break;

case _DeleteService:
printf("DeleteService failed with Error=%i\n",err);
break;

case _SERVICE_CONTROL_STOP:
printf("SERVICE_CONTROL_STOP failed with Error=%i\n",err);
break;
case _CreateFile:
printf("CreateFile failed with Error=%i\n",err);
break;
case _CloseHandle:
printf("CloseHandle failed with Error=%i\n",err);
break;
case _CloseServiceHandle:
printf("CloseServiceHandle failed with Error=%i\n",err);
break;

}
}

И содержимое h-файла этого приложения:


#define FIRST_IOCTL_INDEX 0x800
#define FILE_DEVICE_myDrv 0x00008000

#define TEST_SMTH CTL_CODE(FILE_DEVICE_myDrv, \
0x800 + 101, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
Это приложение загружает драйвер, файл которого лежит в одной папке, что и exe-шник данного приложения.

Посмотрим на исходный текст:
В main(), мы создаем переменную с именем драйвера (myDrv.sys), и передаем это имя в функцию динамической загрузки драйвера drvLoad(), которая выполняет все необходимые действия по работе с менеджером служб, и в конце вызывает CreateFile(),которая возвращает дескриптор, нужный для работы с драйвером как файловым объектом.
Этот дескриптор, в частности, используется при вызове функции DeviceIoControl.
Если драйвер загружен успешно, то вызываем функцию TestSmth(), внутри которой мы создаем, и посылаем драйверу IRP-пакет (с помощью вызова DeviceIoControl()). Приняв этот пакет, наш драйвер возвращает адрес своей процедуры DriverEntry.
После этого выгружаем драйвер. Все.


ISAPI Filter
Введение в WinInet
Troubleshooting and Debugging
MS BackOffice Unleashed
Creating an ISAPI Filter
SAFEARRAY
// Описатель измерения
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = 0;

WCHAR * pw = pf;
while(*pw != 0)
{
	pw+= ::wcslen(pw)+1;
	rgsabound[0].cElements++;
}

 // Создаем массив с одним измерением
SAFEARRAY * psa =  SafeArrayCreate(VT_BSTR,1,rgsabound);
if( psa == NULL )
{
	::wcscpy( _ErrorMessage, _TEXT("Out of memory") );
	return E_OUTOFMEMORY;
}

pw = pf;
for( long i=0; i < rgsabound[0].cElements; i++ )
{
	BSTR ps = ::SysAllocString(pw);
	hr = SafeArrayPutElement(psa,&i,ps);
	if( FAILED(hr) ) 
		return Error(_ErrorMessage);
	pw+= ::wcslen(pw)+1;
}

VARIANT R;
::VariantInit(&R);
R.vt = VT_ARRAY|VT_BSTR;
R.parray = psa;
Hosted by uCoz