7d3f4e2411be742d4129aa0c5b800c63fcaafa5e
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: Virtual Device Drivers (VDD) Support
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
9 /* INCLUDES *******************************************************************/
19 typedef VOID (WINAPI
*VDD_PROC
)(VOID
);
21 typedef struct _VDD_MODULE
24 VDD_PROC DispatchRoutine
;
25 } VDD_MODULE
, *PVDD_MODULE
;
27 /* PRIVATE VARIABLES **********************************************************/
29 // TODO: Maybe use a linked list.
30 // But the number of elements must be <= MAXUSHORT (MAXWORD)
31 #define MAX_VDD_MODULES 0xFF + 1
32 static VDD_MODULE VDDList
[MAX_VDD_MODULES
] = {{NULL
}};
34 // Valid handles of VDD DLLs start at 1 and finish at MAX_VDD_MODULES
35 #define ENTRY_TO_HANDLE(Entry) ((Entry) + 1)
36 #define HANDLE_TO_ENTRY(Handle) ((Handle) - 1)
37 #define IS_VALID_HANDLE(Handle) ((Handle) > 0 && (Handle) <= MAX_VDD_MODULES)
39 /* PRIVATE FUNCTIONS **********************************************************/
41 static USHORT
GetNextFreeVDDEntry(VOID
)
43 USHORT Entry
= MAX_VDD_MODULES
;
44 for (Entry
= 0; Entry
< sizeof(VDDList
)/sizeof(VDDList
[0]); ++Entry
)
46 if (VDDList
[Entry
].hDll
== NULL
) break;
51 static VOID WINAPI
ThirdPartyVDDBop(LPWORD Stack
)
53 /* Get the Function Number and skip it */
54 BYTE FuncNum
= *(PBYTE
)SEG_OFF_TO_PTR(getCS(), getIP());
65 LPCSTR DllName
= NULL
,
66 InitRoutineName
= NULL
,
67 DispatchRoutineName
= NULL
;
69 VDD_PROC InitRoutine
= NULL
,
70 DispatchRoutine
= NULL
;
72 DPRINT("RegisterModule() called\n");
74 /* Clear the Carry Flag (no error happened so far) */
77 /* Retrieve the next free entry in the table (used later on) */
78 Entry
= GetNextFreeVDDEntry();
79 if (Entry
>= MAX_VDD_MODULES
)
81 DPRINT1("Failed to create a new VDD module entry\n");
87 /* Retrieve the VDD name in DS:SI */
88 DllName
= (LPCSTR
)SEG_OFF_TO_PTR(getDS(), getSI());
90 /* Retrieve the initialization routine API name in ES:DI (optional --> ES=DI=0) */
91 if (TO_LINEAR(getES(), getDI()) != 0)
92 InitRoutineName
= (LPCSTR
)SEG_OFF_TO_PTR(getES(), getDI());
94 /* Retrieve the dispatch routine API name in DS:BX */
95 DispatchRoutineName
= (LPCSTR
)SEG_OFF_TO_PTR(getDS(), getBX());
97 DPRINT1("DllName = '%s' - InitRoutineName = '%s' - DispatchRoutineName = '%s'\n",
98 (DllName
? DllName
: "n/a"),
99 (InitRoutineName
? InitRoutineName
: "n/a"),
100 (DispatchRoutineName
? DispatchRoutineName
: "n/a"));
102 /* Load the VDD DLL */
103 hDll
= LoadLibraryA(DllName
);
106 DWORD LastError
= GetLastError();
109 if (LastError
== ERROR_NOT_ENOUGH_MEMORY
)
111 DPRINT1("Not enough memory to load DLL '%s'\n", DllName
);
117 DPRINT1("Failed to load DLL '%s'; last error = %d\n", DllName
, LastError
);
123 /* Load the initialization routine if needed */
126 InitRoutine
= (VDD_PROC
)GetProcAddress(hDll
, InitRoutineName
);
127 if (InitRoutine
== NULL
)
129 DPRINT1("Failed to load the initialization routine '%s'\n", InitRoutineName
);
136 /* Load the dispatch routine */
137 DispatchRoutine
= (VDD_PROC
)GetProcAddress(hDll
, DispatchRoutineName
);
138 if (DispatchRoutine
== NULL
)
140 DPRINT1("Failed to load the dispatch routine '%s'\n", DispatchRoutineName
);
146 /* If we arrived there, that means everything is OK */
148 /* Register the VDD DLL */
149 VDDList
[Entry
].hDll
= hDll
;
150 VDDList
[Entry
].DispatchRoutine
= DispatchRoutine
;
152 /* Call the initialization routine if needed */
153 if (InitRoutine
) InitRoutine();
155 /* We succeeded. RetVal will contain a valid VDD DLL handle */
157 RetVal
= ENTRY_TO_HANDLE(Entry
); // Convert the entry to a valid handle
162 /* Unload the VDD DLL */
163 if (hDll
) FreeLibrary(hDll
);
165 /* Set the Carry Flag to indicate that an error happened */
170 // /* Clear the Carry Flag (success) */
177 /* UnRegisterModule */
180 WORD Handle
= getAX();
181 WORD Entry
= HANDLE_TO_ENTRY(Handle
); // Convert the handle to a valid entry
183 DPRINT("UnRegisterModule() called\n");
186 if (!IS_VALID_HANDLE(Handle
) || VDDList
[Entry
].hDll
== NULL
)
188 DPRINT1("Invalid VDD DLL Handle: %d\n", Entry
);
194 /* Unregister the VDD DLL */
195 FreeLibrary(VDDList
[Entry
].hDll
);
196 VDDList
[Entry
].hDll
= NULL
;
197 VDDList
[Entry
].DispatchRoutine
= NULL
;
204 WORD Handle
= getAX();
205 WORD Entry
= HANDLE_TO_ENTRY(Handle
); // Convert the handle to a valid entry
207 DPRINT("DispatchCall() called\n");
210 if (!IS_VALID_HANDLE(Handle
) ||
211 VDDList
[Entry
].hDll
== NULL
||
212 VDDList
[Entry
].DispatchRoutine
== NULL
)
214 DPRINT1("Invalid VDD DLL Handle: %d\n", Entry
);
220 /* Call the dispatch routine */
221 VDDList
[Entry
].DispatchRoutine();
227 DPRINT1("Unknown 3rd-party VDD BOP Function: 0x%02X\n", FuncNum
);
234 static BOOL
LoadInstallableVDD(VOID
)
236 #define ERROR_MEMORYVDD L"Insufficient memory to load installable Virtual Device Drivers."
237 #define ERROR_REGVDD L"Virtual Device Driver format in the registry is invalid."
238 #define ERROR_LOADVDD L"An installable Virtual Device Driver failed Dll initialization."
246 LPCWSTR VDDKeyName
= L
"SYSTEM\\CurrentControlSet\\Control\\VirtualDeviceDrivers";
247 LPWSTR VDDValueName
= L
"VDD";
248 LPWSTR VDDList
= NULL
;
252 /* Try to open the VDD registry key */
253 Error
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
258 if (Error
== ERROR_FILE_NOT_FOUND
)
260 /* If the key just doesn't exist, don't do anything else */
263 else if (Error
!= ERROR_SUCCESS
)
265 /* The key exists but there was an access error: display an error and quit */
266 DisplayMessage(ERROR_REGVDD
);
271 * Retrieve the size of the VDD registry value
272 * and check that it's of REG_MULTI_SZ type.
274 Error
= RegQueryValueExW(hVDDKey
,
280 if (Error
== ERROR_FILE_NOT_FOUND
)
282 /* If the value just doesn't exist, don't do anything else */
286 else if (Error
!= ERROR_SUCCESS
|| Type
!= REG_MULTI_SZ
)
289 * The value exists but there was an access error or
290 * is of the wrong type: display an error and quit.
292 DisplayMessage(ERROR_REGVDD
);
297 /* Allocate the buffer */
298 BufSize
= (BufSize
< 2*sizeof(WCHAR
) ? 2*sizeof(WCHAR
) : BufSize
);
299 VDDList
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, BufSize
);
302 DisplayMessage(ERROR_MEMORYVDD
);
307 /* Retrieve the list of VDDs to load */
308 if (RegQueryValueExW(hVDDKey
,
313 &BufSize
) != ERROR_SUCCESS
)
315 DisplayMessage(ERROR_REGVDD
);
321 VDDValueName
= VDDList
;
324 DPRINT1("Loading VDD '%S'...", VDDList
);
325 hVDD
= LoadLibraryW(VDDList
);
328 DbgPrint("Failed\n");
329 DisplayMessage(ERROR_LOADVDD
);
333 DbgPrint("Succeeded\n");
335 /* Go to next string */
336 VDDList
+= wcslen(VDDList
) + 1;
338 VDDList
= VDDValueName
;
341 if (VDDList
) HeapFree(GetProcessHeap(), 0, VDDList
);
342 RegCloseKey(hVDDKey
);
346 /* PUBLIC FUNCTIONS ***********************************************************/
348 VOID
VDDSupInitialize(VOID
)
350 /* Register the 3rd-party VDD BOP Handler */
351 RegisterBop(BOP_3RDPARTY
, ThirdPartyVDDBop
);
353 /* Load the installable VDDs from the registry */
354 LoadInstallableVDD();