summaryrefslogtreecommitdiffstats
path: root/private/os2/client/dllpmnt.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/os2/client/dllpmnt.c')
-rw-r--r--private/os2/client/dllpmnt.c1793
1 files changed, 1793 insertions, 0 deletions
diff --git a/private/os2/client/dllpmnt.c b/private/os2/client/dllpmnt.c
new file mode 100644
index 000000000..384e60ada
--- /dev/null
+++ b/private/os2/client/dllpmnt.c
@@ -0,0 +1,1793 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllpmnt.c
+
+Abstract:
+
+ This module contains various calls needed internally for PM/NT
+
+Author:
+
+ Patrick Questembert (PatrickQ) 20-July-1992
+
+Revision History:
+
+ Patrick Questembert (PatrickQ) 13-Oct-1993:
+ Add support for 2nd frame buffer selector.
+
+--*/
+
+#if PMNT /* If not for PMNT build, yield just an empty file */
+
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+#include "crt/stdio.h"
+#include "crt/stdlib.h"
+#include "os2sub.h"
+
+#define INCL_32BIT
+#include "pmnt.h"
+#include "os2win.h"
+#include "sesport.h"
+
+#include "os2crt.h"
+
+#include <ntexapi.h>
+
+extern APIRET DosSemRequest(HSEM hsem, LONG lTimeout);
+extern APIRET PMNTAllocLDTSelector(ULONG BaseAddress, ULONG cbSize, PSEL pSel);
+extern APIRET VioGetConfig(ULONG usConfigId,PVIOCONFIGINFO Config,ULONG hVio);
+extern APIRET VioGetCp(ULONG usReserved,PUSHORT pIdCodePage,ULONG hVio);
+extern APIRET PMNTIsSessionRoot(void);
+extern VOID PMNTRemoveCloseMenuItem(void); // os2ses\os2.c
+
+extern LONG ScreenX;
+extern LONG ScreenY;
+BOOLEAN PMNTRegisteredDisplayAdapter = FALSE;
+extern HANDLE Ow2ForegroundWindow;
+
+ULONG PMFlags = 0;
+ULONG PMSubprocSem32;
+
+HANDLE hPMNTDevice = NULL;
+
+BOOLEAN
+SetProcessShutdownParameters(
+ DWORD dwLevel,
+ DWORD dwFlags
+ );
+
+// Defined in public\sdk\inc\winuser.h
+#define SW_HIDE 0
+
+BOOLEAN
+ShowWindow(
+ HANDLE hWnd,
+ int nCmdShow);
+
+APIRET
+InitPMNTDevice()
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ STRING NameString;
+ UNICODE_STRING UnicodeString;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+
+ RtlInitString( &NameString, PMNTDD_DEVICE_NAME );
+
+ Status = RtlAnsiStringToUnicodeString(&UnicodeString,
+ &NameString,
+ TRUE );
+ ASSERT( NT_SUCCESS( Status ) );
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &UnicodeString,
+ 0,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile( &hPMNTDevice,
+ SYNCHRONIZE, // | FILE_READ_DATA | FILE_WRITE_DATA,
+// FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttributes,
+ &IoStatus,
+ 0,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+
+ RtlFreeUnicodeString( &UnicodeString );
+
+ if ( !NT_SUCCESS( Status ) )
+ {
+ KdPrint(("InitPMNTDevice: NtOpenFile failed, ret=%x\n", Status));
+ return (Status);
+ }
+
+ return( NO_ERROR );
+}
+
+APIRET
+PMNTRegisterDisplayAdapter(
+ PMNT_IOPM_DATA *pMemory,
+ PMNT_IOPM_DATA *pPorts,
+ ULONG col,
+ ULONG row)
+{
+ ULONG MemoryStructSize, PortsStructSize;
+ PVOID AdapterInfo;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+
+ ScreenX = (LONG)col;
+ ScreenY = (LONG)row;
+ PMNTRegisteredDisplayAdapter = TRUE;
+
+ MemoryStructSize = FIELD_OFFSET(PMNT_IOPM_DATA,Entry)
+ + sizeof(pMemory->Entry[0]) * pMemory->NumEntries;
+ PortsStructSize = FIELD_OFFSET(PMNT_IOPM_DATA,Entry)
+ + sizeof(pPorts->Entry[0]) * pPorts->NumEntries;
+
+ // Allocate room for both structures
+ AdapterInfo = (PVOID)RtlAllocateHeap(Od2Heap, 0,
+ MemoryStructSize + PortsStructSize);
+
+ if (AdapterInfo == NULL)
+ {
+#if DBG
+ DbgPrint("PMNTRegisterDisplayAdapter: failed to allocate memory for structure\n");
+ DbgPrint(" MemoryStructSize=%x, PortsStructSize=%x\n",
+ MemoryStructSize,
+ PortsStructSize);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //Copy memory structure
+ RtlMoveMemory(AdapterInfo,
+ pMemory,
+ MemoryStructSize);
+ //Copy ports structure
+ RtlMoveMemory((char *)AdapterInfo + MemoryStructSize,
+ pPorts,
+ PortsStructSize);
+
+ if (hPMNTDevice == NULL)
+ {
+ if (InitPMNTDevice() != NO_ERROR)
+ {
+#if DBG
+ DbgPrint("PMNTRegisterDisplayAdapter: failed to open PMNTDD.SYS\n");
+#endif
+
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ Status = NtDeviceIoControlFile( hPMNTDevice,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_PMNTDD_REGISTER_HARDWARE,
+ (void *)AdapterInfo, // input buffer
+ MemoryStructSize + PortsStructSize, // in buffer length
+ NULL, // out buffer
+ 0 // out buffer length
+ );
+
+ RtlFreeHeap(Od2Heap, 0, AdapterInfo);
+
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ DbgPrint("PMNTRegisterDisplayAdapter: failed to perform IOCTL, Status=%x\n",
+ Status);
+#endif
+ return ERROR_ACCESS_DENIED;
+ }
+
+ return NO_ERROR;
+}
+
+APIRET
+PMNTIOMap()
+{
+ ULONG DummyHandle = 0L;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+
+ if (hPMNTDevice == NULL)
+ {
+ if (InitPMNTDevice() != NO_ERROR)
+ {
+#if DBG
+ DbgPrint("PMNTRegisterDisplayAdapter: failed to open PMNTDD.SYS\n");
+#endif
+
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ Status = NtDeviceIoControlFile( hPMNTDevice,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_PMNTDD_IO_MAP,
+ (void *)&DummyHandle, // input buffer
+ sizeof(DummyHandle), // in buffer length
+ NULL, // out buffer
+ 0 // out buffer length
+ );
+
+ if (NT_SUCCESS(Status))
+ return NO_ERROR;
+ else
+ {
+#if DBG
+ DbgPrint("PMNTIOMap: NtDeviceIoControl failed, Status=%x\n",
+ Status);
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
+ }
+}
+
+// Remembers the screen selector returned by PMNTDD.SYS. If PMNTMemMap() is
+// called twice within the same process, the selector will be returned without
+// calling PMNTDD.SYS again
+SEL ScreenSelector = 0;
+
+APIRET
+PMNTMemMap(
+ PSEL pSel)
+{
+ ULONG RequestedVirtualAddresses[2];
+ PMNT_MEMMAP_RESULTS ResultVirtualAddresses[2];
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+
+ if (ScreenSelector != 0)
+ {
+ try
+ {
+ Od2ProbeForWrite(pSel, sizeof(SEL), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+#if DBG
+ DbgPrint("PMNTMemMap called 2nd time for process - returning saved selector %x\n",
+ ScreenSelector);
+#endif
+ *pSel = ScreenSelector;
+
+ return NO_ERROR;
+ }
+
+ // Specify 2 virtual addresses, in case the display adapter has 2 frame
+ // buffer sections instead of one. The resulting virtual addresses structure
+ // will indicate how many are actually needed (a 2nd virtual address of 0
+ // will indicate that only one is needed).
+ RequestedVirtualAddresses[0] = PMDISPLAY_BASE1;
+ RequestedVirtualAddresses[1] = PMDISPLAY_BASE2;
+
+ if (hPMNTDevice == NULL)
+ {
+ if (InitPMNTDevice() != NO_ERROR)
+ {
+#if DBG
+ DbgPrint("PMNT_IOCTL: failed to open PMNTDD\n");
+#endif
+
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ Status = NtDeviceIoControlFile( hPMNTDevice,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_PMNTDD_MEM_MAP,
+ (void *)&RequestedVirtualAddresses,// input buffer
+ sizeof(RequestedVirtualAddresses), // in buffer length
+ (void *)ResultVirtualAddresses, // out buffer
+ sizeof(ResultVirtualAddresses) // out buffer length
+ );
+
+ if NT_SUCCESS(Status)
+ {
+ APIRET rc;
+
+ try
+ {
+ Od2ProbeForWrite(pSel, sizeof(SEL), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ // Allocate a LDT selector for the first selector. It is expected that
+ // first VirtualAddress is PMDISPLAY_BASE1 (+ some offset if address
+ // wasn't 64K-aligned)
+
+ rc = PMNTAllocLDTSelector(
+ ResultVirtualAddresses[0].VirtualAddress,
+ ResultVirtualAddresses[0].Length,
+ pSel);
+ if (rc != NO_ERROR)
+ {
+#if DBG
+ DbgPrint("PMNTDDIoctl: Error, PMNTAllocLDTSelector#1 failed\n");
+#endif
+
+ return rc;
+ }
+ else
+ {
+ ScreenSelector = *pSel; // Remember for next time !
+ // Is there a 2nd selector to map ?
+ if (ResultVirtualAddresses[1].VirtualAddress != 0)
+ {
+ SEL DummySEL; // Just to keep PMNTAllocLDTSelector happy
+
+ // Allocate a LDT selector for the 2nd selector. It is expected
+ // that the 2nd VirtualAddress is PMDISPLAY_BASE2 (+ some
+ // offset if address wasn't 64K-aligned)
+
+ rc = PMNTAllocLDTSelector(
+ ResultVirtualAddresses[1].VirtualAddress,
+ ResultVirtualAddresses[1].Length,
+ &DummySEL);
+#if DBG
+ if (rc != NO_ERROR)
+ {
+ DbgPrint("PMNTDDIoctl: Error, PMNTAllocLDTSelector#2 failed\n");
+ }
+#endif
+
+ return rc;
+ }
+ else
+ return NO_ERROR;
+ }
+ }
+ else
+ {
+#if DBG
+ DbgPrint("PMNTMemMap: IOCTL to PMNTDD.SYS failed, Status=%x\n",
+ Status);
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
+ }
+}
+
+APIRET
+PMNTDDIoctl(
+ ULONG request,
+ PVOID input_buffer,
+ ULONG input_buffer_length,
+ PVOID output_buffer,
+ ULONG output_buffer_length
+ )
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+
+ if (hPMNTDevice == NULL)
+ {
+ if (InitPMNTDevice() != NO_ERROR)
+ {
+#if DBG
+ DbgPrint("PMNT_IOCTL: failed to open PMNTDD\n");
+#endif
+
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ Status = NtDeviceIoControlFile( hPMNTDevice,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ request,
+ input_buffer,
+ input_buffer_length,
+ output_buffer,
+ output_buffer_length
+ );
+
+ if NT_SUCCESS(Status)
+ {
+ return NO_ERROR;
+ }
+ else
+ {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
+ }
+}
+
+APIRET
+PMNTIoctl(
+ ULONG request,
+ PVOID input_pointer,
+ PVOID output_pointer
+ )
+{
+ PMNT_IOCTL_DD_IOCTL_PARAMS *ptr;
+
+ UNREFERENCED_PARAMETER(output_pointer);
+
+ switch (request)
+ {
+ //PatrickQ 12-29-95 Hook for the CBA to make WIN32 Console window invisible
+ case PMNT_IOCTL_HIDE_WIN32_WINDOW:
+ if (!ShowWindow(Ow2ForegroundWindow, SW_HIDE))
+ {
+#if DBG
+ DbgPrint("PMNTIoctl: ShowWindow(%x) failed\n", Ow2ForegroundWindow);
+#endif
+ }
+ break;
+ case PMNT_IOCTL_DD_IOCTL: /* PMNTDD IOCTL's */
+ ptr = (PMNT_IOCTL_DD_IOCTL_PARAMS *)input_pointer;
+ // BUGBUG - Check input & output pointers against advertised length
+ return (PMNTDDIoctl(
+ CTL_CODE((unsigned long)PMNTDD_DEVICE_TYPE, ptr->Request,, METHOD_BUFFERED, FILE_ANY_ACCESS), /* Request */
+ FARPTRTOFLAT(ptr->InputBuffer),
+ ptr->InputBufferLength,
+ FARPTRTOFLAT(ptr->OutputBuffer),
+ ptr->OutputBufferLength
+ ));
+
+#if DBG
+ case PMNT_IOCTL_DUMP_SEGMENT_TABLE:
+ {
+ OS2_API_MSG m;
+ P_LDRDUMPSEGMENTS_MSG a = &m.u.LdrDumpSegments;
+
+ Od2CallSubsystem( &m, NULL, Ol2LdrDumpSegments, sizeof( *a ) );
+ return NO_ERROR;
+ }
+#endif
+ default:
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //PatrickQ - so that break statements above don't return random return-code
+ return NO_ERROR;
+}
+
+VOID
+validate_user_str(
+ char **ptr)
+{
+ if (*ptr == NULL)
+ {
+ *ptr = "(null)";
+ return;
+ }
+
+ try
+ {
+ int tmp;
+ tmp = strlen(*ptr);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ DbgPrint("PMNTDbgPrint: warning - illegal string parameter - %x:%x\n",
+ FLATTOSEL(*ptr),
+ (ULONG)ptr & 0xFFFF);
+ *ptr = "(illegal string)";
+ return;
+ }
+}
+
+APIRET
+PMNTDbgPrompt(
+ PCHAR MessageStr,
+ PCHAR OutputStr,
+ ULONG Len
+ )
+{
+ try
+ {
+ if (MessageStr == NULL)
+ return (DbgPrompt("", OutputStr, Len));
+ else
+ return (DbgPrompt(MessageStr, OutputStr, Len));
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+ return NO_ERROR;
+}
+
+void
+PMNTDbgPrint(
+ char *str,
+ ULONG l1,
+ ULONG l2,
+ ULONG l3,
+ ULONG l4
+ )
+{
+ ULONG r1, r2, r3, r4;
+ char *ptr=str, percent=0;
+ int param=1, i, str_length;
+ char *print_buffer = NULL;
+ char tmp_buf[512];
+
+ //So that we can see what has been sprintf'ed before problem
+ for (i=0; i<512; i++) tmp_buf[i]='\0';
+
+ // Using sprintf() because richer in formats. Also, DbgPrint hits a break-
+ // point when called with bad pointer.
+
+ //Validate string itself
+ try
+ {
+ str_length = strlen(str);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ DbgPrint("PMNTDbgPrint: illegal string - %x:%x",
+ FLATTOSEL(str),
+ (ULONG)str & 0xFFFF);
+ return;
+ }
+
+ // Look for %s (need to xlate address if that's the case)
+ while (*ptr)
+ {
+ if (*ptr == '%')
+ {
+ percent = !percent;
+ }
+ else if (percent)
+ {
+ percent = 0;
+ if (*ptr == 's')
+ {
+ switch (param)
+ {
+ case 1:
+ r1 = (ULONG)FARPTRTOFLAT(l1);
+ validate_user_str(&(char *)r1);
+ break;
+ case 2:
+ r2 = (ULONG)FARPTRTOFLAT(l2);
+ validate_user_str(&(char *)r2);
+ break;
+ case 3:
+ r3 = (ULONG)FARPTRTOFLAT(l3);
+ validate_user_str(&(char *)r3);
+ break;
+ case 4:
+ r4 = (ULONG)FARPTRTOFLAT(l4);
+ validate_user_str(&(char *)r4);
+ break;
+ }
+ }
+ else
+ {
+ switch (param)
+ {
+ case 1:
+ r1 = l1;
+ break;
+ case 2:
+ r2 = l2;
+ break;
+ case 3:
+ r3 = l3;
+ break;
+ case 4:
+ r4 = l4;
+ break;
+ }
+ }
+ param++;
+ }
+ ptr++;
+ }
+
+ try
+ {
+ int i;
+
+ if (str_length >= 512)
+ {
+ print_buffer = RtlAllocateHeap(Od2Heap, 0, str_length + 1);
+ sprintf(print_buffer, str, r1, r2, r3, r4);
+ for (i=0; i<str_length;)
+ {
+ strncpy(tmp_buf, print_buffer + i, 256);
+ // strncpy() doesn't append a \0 when count is reached
+ tmp_buf[256] = '\0';
+ i += 256; // may be less at the end of the string but we just
+ // need to make i > str_length so that's fine
+ DbgPrint(tmp_buf);
+ }
+ RtlFreeHeap(Od2Heap, 0, print_buffer);
+ }
+ else
+ {
+ sprintf(tmp_buf, str, r1, r2, r3, r4);
+ DbgPrint(tmp_buf);
+ }
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ DbgPrint("PMNTDbgPrint: access violation calling sprintf()\n");
+ DbgPrint("str = %x:%x, l1=%x, l2=%x, l3=%x, l4=%x\n",
+ FLATTOSEL(str),
+ (ULONG)str & 0xFFFF,
+ l1,
+ l2,
+ l3,
+ l4);
+ DbgPrint("tmp_buf=%s, r1=%x, r2=%x, r3=%x, r4=%x\n",
+ tmp_buf,
+ r1,
+ r2,
+ r3,
+ r4);
+ if (print_buffer != NULL)
+ RtlFreeHeap(Od2Heap, 0, print_buffer);
+ return;
+ }
+}
+
+/* Just to resolve entry. This call is used by DISPLAY.DLL:
+ - called by pmdisp\egafam\egavga\egainit.asm, ring3_VioGetPSAddress()
+ - ring3_VioGetPSAddress() is called (indirectly, via a ring3_GetPSAddress()
+ ULONG variable) by pmdisp\egafam\cellblt.asm, DeviceSetAVIOFont2() routine
+*/
+ULONG
+VioGetPSAddress(void)
+{
+ KdPrint(("VioGetPSAddress: not implemented yet\n"));
+
+ return 0L;
+}
+
+VOID
+DosSetFgnd(
+ ULONG Level,
+ ULONG Tid
+ )
+{
+ UNREFERENCED_PARAMETER(Level);
+ UNREFERENCED_PARAMETER(Tid);
+
+// KdPrint(("DosSetFgnd(%d,%d): not implemented yet\n",
+// Level, Tid));
+ return;
+}
+
+VOID
+DosSystemService(void)
+{
+ KdPrint(("DosSystemService (DOSCALLS.88): not implemented yet\n"));
+ return;
+}
+
+APIRET
+VioRedrawSize(
+ PULONG pRedrawSize)
+{
+ try
+ {
+ *pRedrawSize = 0xFFFFFFFF;
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ return NO_ERROR;
+}
+
+APIRET
+PMNTGetPgmName(
+ PSZ Buffer,
+ ULONG BufferLength)
+{
+ Od2ProbeForWrite(Buffer,BufferLength,1);
+ if (BufferLength > 1)
+ {
+ strncpy(Buffer,Od2Process->ApplName,BufferLength);
+ Buffer[BufferLength-1]='\0';
+ }
+ else
+ {
+ if (BufferLength == 1) Buffer[0]='\0';
+ }
+
+ return NO_ERROR;
+}
+
+extern ULONG Ow2bNewSession;
+
+DECLARE_HANDLE(HKEY);
+typedef HKEY *PHKEY;
+#define HKEY_LOCAL_MACHINE (( HKEY ) 0x80000002 )
+typedef ACCESS_MASK REGSAM;
+
+LONG
+APIENTRY
+RegOpenKeyExA (
+ HKEY hKey,
+ LPCSTR lpSubKey,
+ DWORD ulOptions,
+ REGSAM samDesired,
+ PHKEY phkResult
+ );
+
+LONG
+APIENTRY
+RegQueryValueExA (
+ HKEY hKey,
+ LPCSTR lpValueName,
+ PULONG lpReserved,
+ PULONG lpType,
+ PBYTE lpData,
+ PULONG lpcbData
+ );
+
+LONG
+APIENTRY
+RegCloseKey (
+ HKEY hKey
+ );
+
+#define PMSHELL_TITLE_LEN 40
+
+APIRET
+PMNTSetConsoleTitle(
+ PSZ Buffer)
+{
+ CHAR BufferTmp[PMSHELL_TITLE_LEN];
+ DWORD cb;
+ DWORD type;
+ HKEY hkey;
+
+ try
+ {
+ Od2ProbeForRead(Buffer,1,1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+#if DBG
+ DbgPrint("PMNTSetConsoleTile: error, bad pointer parameter\n");
+#endif
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ // Note that the code below also takes care that the Print Manager won't
+ // set the console title unless started independently because if PMSPOOL
+ // was started by PMShell, it won't be a new session
+
+ if (OS2SS_IS_NEW_SESSION( Ow2bNewSession )) {
+ if (ProcessIsPMShell()) {
+ if (!RegOpenKeyExA(
+ HKEY_LOCAL_MACHINE,
+ "SOFTWARE\\Microsoft\\OS/2 Subsystem for NT\\1.0\\PMSHELL",
+ 0,
+ KEY_QUERY_VALUE,
+ &hkey
+ ))
+ {
+ DWORD RemoveCloseMenuItem = 0;
+
+ // Found key SOFTWARE\Microsoft\OS/2 Subsystem for NT\1.0\PMSHELL
+ cb = PMSHELL_TITLE_LEN-1;
+ if (!RegQueryValueExA(
+ hkey,
+ "Title",
+ NULL,
+ &type,
+ BufferTmp,
+ &cb
+ ))
+ {
+ BufferTmp[cb] = '\0';
+ Buffer = BufferTmp;
+ }
+
+ cb = sizeof(DWORD);
+ if (!RegQueryValueExA(
+ hkey,
+ "RemoveCloseMenuItem",
+ NULL,
+ &type,
+ &RemoveCloseMenuItem,
+ &cb
+ ))
+ {
+ if (RemoveCloseMenuItem)
+ {
+ // PatrickQ 5/2/96.This option means we don't want to
+ // allow user to select the close system menu option
+ // on PMShell - Required by CBA
+ PMNTRemoveCloseMenuItem();
+ }
+ }
+
+ RegCloseKey(hkey);
+ }
+
+ if (Buffer != BufferTmp) {
+ Buffer = "PM Shell";
+ }
+ }
+
+
+ if (SetConsoleTitleA(Buffer))
+ return(NO_ERROR);
+ else
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ return NO_ERROR;
+}
+
+APIRET
+PMNTSetPMShellFlag()
+{
+
+ if (!ProcessIsPMShell())
+ {
+#if DBG
+ DbgPrint("PMNTSetPMShellFlag: internal error, flag wasn't set !!!\n");
+#endif
+ SetPMShellFlag();
+ }
+
+ // Let PMShell go down first on logoff/shutdown
+ // Default priority for apps is 0x280
+ SetProcessShutdownParameters(0x290L, 0);
+
+ return(NO_ERROR);
+}
+
+APIRET
+PMNTSetSubprocSem(HSEM hsem)
+{
+
+ PMSubprocSem32 = (ULONG)hsem;
+
+ return(NO_ERROR);
+}
+
+ULONG
+FindWindowA(
+ PSZ lpClassName ,
+ PSZ lpWindowName);
+
+ULONG
+PMNTGetOurWindow()
+{
+ DWORD SavedTitleLength = 0;
+ UCHAR SavedTitle[256];
+ NTSTATUS Status;
+ PROCESS_BASIC_INFORMATION ProcessInfo;
+ UCHAR UniqueTitle[256] = { 'O', 'S', '2' , 'S', 'S', ':', '\0' };
+ ULONG Hwnd = 0;
+ DWORD StartingMsec;
+
+ // No need to figure out our window handle for non-root OS/2 ss programs
+ if (!PMNTIsSessionRoot())
+ return (0);
+
+ /**********************************
+ * Save the current Console title *
+ **********************************/
+
+ SavedTitleLength = GetConsoleTitleA(SavedTitle,256);
+
+ if (SavedTitleLength == 0)
+ {
+#if DBG
+ DbgPrint("PMNTGetOurWindow: GetConsoleTitle failed, error=0x%x\n",
+ GetLastError());
+#endif
+ return (0);
+ }
+
+ SavedTitle[255]='\0';
+
+ Status = NtQueryInformationProcess(
+ NtCurrentProcess(),
+ ProcessBasicInformation,
+ (PVOID)(&ProcessInfo),
+ sizeof(ProcessInfo),
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ DbgPrint("PMNTGetOurWindow: NtQueryInformationProcess failed, Status == %X\n",
+ Status);
+#endif // DBG
+ return (0);
+ }
+
+ // Make a string out of the PID
+ ltoa(ProcessInfo.UniqueProcessId,
+ UniqueTitle+strlen(UniqueTitle),
+ 16);
+
+ if (!SetConsoleTitleA(UniqueTitle))
+ {
+#if DBG
+ DbgPrint("PMNTGetOurWindow: SetConsoleTitle failed, error=0x%x\n",
+ GetLastError());
+#endif
+ return (0);
+ }
+
+ //PQPQ 12/28/95 - Just try to find the window once. If you fail, don't worry
+ // about it. The loop previously used to get the window handle created a
+ // problem with Yosef's fix for the CBA to allow turning DosStartSession
+ // calls into background execution in the same session. This happened
+ // because sibling processes reset the console title to other strings so we
+ // failed to find the temporary string among the existing windows.
+ Hwnd = (ULONG)FindWindowA("ConsoleWindowClass", UniqueTitle);
+
+
+#if 0 //PQPQ
+ StartingMsec = GetTickCount();
+ while (!(Hwnd = (ULONG)FindWindowA("ConsoleWindowClass", UniqueTitle)))
+ {
+ // Don't spend more than 60 seconds trying to get the window handle
+ if ((GetTickCount() - StartingMsec) > 60000)
+ {
+#if DBG
+ DbgPrint("PMNTGetOurWindow: giving up on trying to find our window handle, error=0x%x\n",
+ GetLastError());
+#endif
+ break;
+ }
+ }
+#endif //PQPQ
+
+ /*****************************
+ * Restore the Console title *
+ *****************************/
+
+ if (!SetConsoleTitleA(SavedTitle))
+ {
+#if DBG
+ DbgPrint("PMNTGetOurWindow: SetConsoleTitle(%s) failed, error=0x%x\n",
+ SavedTitle,
+ GetLastError());
+#endif
+ }
+ return (Hwnd);
+}
+
+APIRET
+PMNTQueryScreenSize(PUSHORT xRight, PUSHORT yTop)
+{
+ if (!PMNTRegisteredDisplayAdapter)
+ {
+#if DBG
+ DbgPrint("PMNTQueryScreenSize: ERROR, called before PMNTRegisterDisplayAdapter() !\n");
+#endif
+ return (ERROR_INVALID_PARAMETER);
+ }
+
+ try
+ {
+ *xRight = (USHORT)ScreenX;
+ *yTop = (USHORT)ScreenY;
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ return (ERROR_INVALID_PARAMETER);
+ }
+
+ return(NO_ERROR);
+}
+
+APIRET
+PMNTProcessIsPMShell()
+{
+ return(ProcessIsPMShell());
+}
+
+#pragma pack(1)
+// OS/2 structure => aligned to 1
+typedef struct _WHOISINFO { /* whois */
+ USHORT segNum;
+ USHORT mte;
+ char names[ 256 ];
+} WHOISINFO;
+#pragma pack()
+
+APIRET
+PMNTIdentifyCodeSelector(
+ SEL Sel,
+ WHOISINFO *pWhois)
+{
+ OS2_API_MSG m;
+ P_LDRIDENTIFYCODESELECTOR_MSG a = &m.u.LdrIdentifyCodeSelector;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+
+ try
+ {
+ Od2ProbeForWrite(pWhois, sizeof(WHOISINFO), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ CaptureBuffer = Od2AllocateCaptureBuffer(
+ 1,
+ 0,
+ 256
+ );
+
+ if (CaptureBuffer == NULL)
+ {
+#if DBG
+ DbgPrint("PMNTIdentifyCodeSelector: Od2AllocateCaptureBuffer failed\n");
+#endif
+ return NO_ERROR;
+ }
+
+ Od2CaptureMessageString( CaptureBuffer,
+ NULL,
+ 0,
+ 256,
+ &a->ModName
+ );
+
+ a->sel = Sel;
+
+ Od2CallSubsystem( &m, CaptureBuffer, Op2IdentifyCodeSelector, sizeof( *a ) );
+
+ pWhois->segNum = a->segNum;
+ pWhois->mte = a->mte;
+ // Do not exceed size of names field (256)
+ strncpy(pWhois->names, a->ModName.Buffer, 256);
+
+ Od2FreeCaptureBuffer( CaptureBuffer );
+
+ return NO_ERROR;
+}
+
+VOID
+PMNTGetSystemTime(
+ PULONG pTime)
+{
+ LARGE_INTEGER tm;
+ NTSTATUS Status;
+
+ Status = NtQuerySystemTime(
+ &tm
+ );
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ DbgPrint("PMNTGetSystemTime: failed, Status=%x\n", Status);
+#endif
+ *pTime = 0;
+ return;
+ }
+
+ *pTime = tm.LowPart / 10000L;
+}
+
+APIRET
+PMNTVioGetConfig( IN ULONG usConfigId, // this is no longer reserved value
+ IN OUT PVIOCONFIGINFO Config,
+ IN ULONG hVio)
+{
+ return(VioGetConfig(usConfigId,Config,hVio));
+}
+
+APIRET
+PMNTVioGetCp( IN ULONG usReserved,
+ OUT PUSHORT pIdCodePage,
+ IN ULONG hVio)
+{
+ return(VioGetCp(usReserved,pIdCodePage,hVio));
+}
+
+VOID
+DosSysTrace(void)
+{
+ KdPrint(("DosSysTrace (DOSCALLS.90): not implemented yet\n"));
+ return;
+}
+
+APIRET
+DosSMPause()
+{
+ KdPrint(("DosSMPause (SESMGR.26): not implemented yet\n"));
+
+ return(NO_ERROR);
+}
+
+APIRET
+MouInitReal(PSZ pszDriverName)
+{
+ UNREFERENCED_PARAMETER(pszDriverName);
+
+#if DBG
+ //
+ // bvscalls may call it from bvsdinit.c during VioShellInit()
+ // anyway as metioned in the programmer's reference:
+ // "The function is used only by the task manager"
+ // which we do not implement
+ //
+ if (!ProcessIsPMShell()) {
+ DbgPrint("MouInitReal (MOUCALLS.27): not implemented yet\n");
+ }
+#endif
+
+ return(NO_ERROR);
+}
+
+
+#if 0
+// Spring cleaning - APIs no longer needed
+VOID
+QHKeybdHandle(void)
+{
+ KdPrint(("QHKeybdHandle (SESMGR.34): not implemented yet\n"));
+ return;
+}
+
+VOID
+QHMouseHandle(void)
+{
+ KdPrint(("QHMouseHandle (SESMGR.35): not implemented yet\n"));
+ return;
+}
+
+VOID
+DosIRamSemWake(void)
+{
+ KdPrint(("DosIRamSemWake (DOSCALLS.125): not implemented yet\n"));
+ return;
+}
+
+// DOSCALLS.18
+APIRET
+DosISemRequest(
+ IN HSEM hsem,
+ IN LONG lTimeout
+ )
+{
+ return DosSemRequest(hsem, lTimeout);
+}
+
+VOID
+DosUnknownApi54(void)
+{
+ KdPrint(("DosUknownApi54 (DOSCALLS.54): not implemented yet\n"));
+ return;
+}
+
+VOID
+DosUnknownApi90(void)
+{
+ KdPrint(("DosUknownApi90 (DOSCALLS.90): not implemented yet\n"));
+ return;
+}
+
+VOID
+DosUnknownApi105(void)
+{
+ KdPrint(("DosUknownApi105 (DOSCALLS.105): not implemented yet\n"));
+ return;
+}
+
+VOID
+DosICopy(void)
+{
+ KdPrint(("DosICopy (DOSCALLS.200): not implemented yet\n"));
+ return;
+}
+
+VOID
+DosGiveSegList(void)
+{
+ KdPrint(("DosGiveSegList (DOSCALLS.209): not implemented yet\n"));
+ return;
+}
+
+VOID
+VioSSWSwitch(void)
+{
+ KdPrint(("VioSSWSwitch (VIOCALLS.36): not implemented yet\n"));
+ return;
+}
+
+/* MOUCALLS.10 */
+APIRET
+MouSetHotKey(
+ IN ULONG p1,
+ IN ULONG p2,
+ IN ULONG hMou)
+{
+ KdPrint(("MouSetHotKey (%x, %x, %x): not implemented yet\n", p1, p2, hMou));
+
+ return NO_ERROR;
+}
+
+APIRET
+KbdFree(
+ IN ULONG hkbd) //BUGBUG - not necessarily correct prototype, just a guess
+{
+ KdPrint(("KbdFree (%x): not implemented yet\n",hkbd));
+
+ return NO_ERROR;
+}
+
+APIRET
+MouFree(
+ IN ULONG hMou) //BUGBUG - not necessarily correct prototype, just a guess
+{
+ KdPrint(("MouFree (%x): not implemented yet\n",hMou));
+
+ return NO_ERROR;
+}
+
+APIRET
+VioFree(
+ IN ULONG hVio) //BUGBUG - not necessarily correct prototype, just a guess
+{
+ KdPrint(("VioFree (%x): not implemented yet\n",hVio));
+
+ return NO_ERROR;
+}
+
+/* DOSCALLS.55 */
+APIRET
+DosSGSwitchMe(
+ IN ULONG p1,
+ IN ULONG p2)
+{
+ KdPrint(("DosSGSwitchMe(%d,%d): not implemented yet\n", p1, p2));
+
+ return NO_ERROR;
+}
+
+VOID
+KbdSwitchFgnd(void)
+{
+ KdPrint(("KbdSwitchFgnd (KBDCALLS.19): not implemented yet\n"));
+ return;
+}
+
+/* MOUCALLS.5 */
+APIRET
+MouShellInit(void)
+{
+ KdPrint(("MouShellInit (MOUCALLS.5): not implemented yet\n"));
+
+ return NO_ERROR;
+}
+
+// VIOCALLS.54
+APIRET
+VioShellInit(
+ ULONG addr)
+{
+ KdPrint(("VioShellInit (%x): not implemented yet\n", addr));
+
+ return NO_ERROR;
+}
+
+VOID
+VioRestore(void)
+{
+ KdPrint(("VioRestore (VIOCALLS.41): not implemented yet\n"));
+ return;
+}
+
+VOID
+VioSave(void)
+{
+ KdPrint(("VioSave (VIOCALLS.20): not implemented yet\n"));
+ return;
+}
+
+VOID
+VioSRFunBlock(void)
+{
+ KdPrint(("VioSRFunBlock (VIOCALLS.16): not implemented yet\n"));
+ return;
+}
+
+VOID
+VioSRFBlock(void)
+{
+ KdPrint(("VioSRFBlock (VIOCALLS.17): not implemented yet\n"));
+ return;
+}
+
+#endif // 0
+
+#ifdef JAPAN // MSKK [ShigeO] Aug 10, 1993 Win32 font on PM/NT
+
+/***************************************************************\
+* FontHandles
+*
+* History:
+* Aug 11, 1993 ShigeO Created
+\***************************************************************/
+#define MAX_FONTS 32
+HANDLE ahFont[MAX_FONTS];
+ULONG ulFontCount;
+
+/***************************************************************\
+* GetFontHandle()
+*
+* History:
+* Aug 11, 1993 ShigeO Created
+\***************************************************************/
+HANDLE GetFontHandle(
+ ULONG ulFont)
+{
+ if(ulFont && (ulFont <= ulFontCount)) {
+ return ahFont[ulFont-1];
+ }
+ return (HANDLE)0;
+}
+
+/***************************************************************\
+* PutFontHandle()
+*
+* History:
+* Aug 10, 1993 ShigeO Created
+\***************************************************************/
+ULONG PutFontHandle(
+ HANDLE hFont)
+{
+ if(hFont && (ulFontCount < MAX_FONTS)) {
+ ahFont[ulFontCount++] = hFont;
+ return ulFontCount;
+ }
+ return 0L;
+}
+
+/***************************************************************\
+* GetFontID()
+*
+* History:
+* Aug 10, 1993 ShigeO Created
+\***************************************************************/
+ULONG GetFontID(
+ VOID)
+{
+ if(ulFontCount < MAX_FONTS) {
+ return ulFontCount+1;
+ }
+ return 0L;
+}
+
+/***************************************************************\
+* SelectFont()
+*
+* History:
+* Aug 10, 1993 ShigeO Created
+\***************************************************************/
+HANDLE
+SelectFont(
+ HANDLE hFont)
+{
+ static HANDLE hFontPrev = (HANDLE)0;
+ static HANDLE hDC = (HANDLE)0;
+ HANDLE hFontTmp;
+
+ if(hFont == hFontPrev) {
+ return hDC;
+ }
+ if(!hDC && (!(hDC = CreateDCA("DISPLAY", NULL, NULL, NULL)))) {
+ return (HANDLE)0;
+ }
+ hFontTmp = SelectObject(hDC, hFont);
+ if(!hFontTmp || hFontTmp == (HANDLE)0xFFFFFFFFL) {
+ return (HANDLE)0;
+ }
+ hFontPrev = hFont;
+ return hDC;
+}
+
+/***************************************************************\
+* PMNTCreateFontIndirect()
+*
+* History:
+* Aug 10, 1993 ShigeO Created
+\***************************************************************/
+ULONG
+PMNTCreateFontIndirect(
+ PVOID lplf)
+{
+ HANDLE hFont;
+
+ if(!GetFontID()) {
+ return 0L;
+ }
+ if(!(hFont = CreateFontIndirectA(lplf))) {
+ return 0L;
+ }
+ return PutFontHandle(hFont);
+}
+
+/***************************************************************\
+* PMNTGetTextMetrics()
+*
+* History:
+* Aug 10, 1993 ShigeO Created
+\***************************************************************/
+ULONG
+PMNTGetTextMetrics(
+ ULONG ulFont,
+ PVOID lptm)
+{
+ HANDLE hDC;
+ HANDLE hFont;
+
+ if(!(hFont = GetFontHandle(ulFont))) {
+ return 0L;
+ }
+ if(!(hDC = SelectFont(hFont))) {
+ return 0L;
+ }
+ if(!(GetTextMetricsA(hDC, lptm))) {
+ return 0L;
+ }
+ return 1L;
+}
+
+/***************************************************************\
+* PMNTGetFontBitmap()
+*
+* History:
+* Aug 10, 1993 ShigeO Created
+\***************************************************************/
+ULONG
+PMNTGetStringBitmap(
+ ULONG ulFont,
+ LPCSTR lpszStr,
+ UINT cbStr,
+ UINT cbData,
+ PVOID lpSB)
+{
+ HANDLE hDC;
+ HANDLE hFont;
+
+ if(!(hFont = GetFontHandle(ulFont))) {
+ return 0L;
+ }
+ if(!(hDC = SelectFont(hFont))) {
+ return 0L;
+ }
+ if(!(GetStringBitmapA(hDC, lpszStr, cbStr, cbData, lpSB))) {
+ return 0L;
+ }
+ return 1L;
+}
+
+#endif // JAPAN
+
+HANDLE hPMNTVDMEvent;
+#ifndef PMNT_DAYTONA
+HANDLE hPMNTVDMEvent1;
+HANDLE hPMNTVDMEventReady;
+#endif // not PMNT_DAYTONA
+
+HANDLE
+__stdcall
+CreateEventW(
+ PVOID lpEventAttributes,
+ BOOL bManualReset,
+ BOOL bInitialState,
+ PVOID lpName
+ );
+
+BOOLEAN
+Os2InitializeVDMEvents()
+{
+ //
+ // Create the global subsystem PMShell synchronization Nt event
+ // (create in the unsignalled state - when PMShell comes up, it will
+ // signal it)
+ //
+
+ hPMNTVDMEvent = CreateEventW(NULL,
+ FALSE,
+ FALSE,
+ NULL);
+
+#ifndef PMNT_DAYTONA
+
+ //
+ // Create the 2nd global subsystem PMShell synchronization Nt event
+ // (create in the unsignalled state - when PMShell comes up, it will
+ // signal it)
+ //
+
+ hPMNTVDMEvent1 = CreateEventW(NULL,
+ FALSE,
+ FALSE,
+ NULL);
+
+
+ hPMNTVDMEventReady = CreateEventW(NULL,
+ FALSE,
+ FALSE,
+ NULL);
+#endif // not PMNT_DAYTONA
+
+ if ((hPMNTVDMEvent == NULL)
+#ifndef PMNT_DAYTONA
+ || (hPMNTVDMEvent1 == NULL) || (hPMNTVDMEvent == NULL)
+#endif // not PMNT_DAYTONA
+ )
+ {
+#if DBG
+ DbgPrint("Os2InitializeVDMEvent: error at CreateEvent\n");
+#endif
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+Os2WaitForVDMThread(HANDLE hEvent)
+{
+ ULONG rc;
+ if (hEvent == 0)
+ hEvent = hPMNTVDMEvent; // Use default value
+
+ if(rc = WaitForSingleObject(hEvent, INFINITE))
+ {
+#if DBG
+ DbgPrint("Os2WaitForVDMThread: WaitForSingleObject(%x, INFINITE) failed, rc = %d\n",
+ hEvent, rc);
+#endif // DBG
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#ifndef PMNT_DAYTONA
+BOOLEAN
+Os2WaitForVDMThreadReady()
+{
+ ULONG rc;
+
+ if(rc = WaitForSingleObject(hPMNTVDMEventReady, INFINITE))
+ {
+#if DBG
+ DbgPrint("Os2WaitForVDMThread: WaitForSingleObject(hPMNTVDMEventReady, INFINITE) failed, rc = %d\n",
+ rc);
+#endif // DBG
+ return FALSE;
+ }
+ return TRUE;
+}
+#endif // not PMNT_DAYTONA
+
+extern HANDLE hStartHardwareEvent;
+extern HANDLE hEndHardwareEvent;
+
+BOOL
+__stdcall
+SetEvent(
+ HANDLE hEvent
+ );
+
+#ifndef PMNT_DAYTONA
+VOID
+Os2VDMGetStartThread(
+ IN PVOID Parameter
+ )
+{
+ ULONG rc;
+
+ // Notify the creator of this thread that we are alive and about to wait for
+ // the Console
+ if(!SetEvent(hPMNTVDMEventReady))
+ {
+#if DBG
+ DbgPrint("Os2VDMGetStartThread: SetEvent(hPMNTVDMEventReady) failed, error=%x\n",
+ GetLastError());
+#endif // DBG
+ ExitThread(1L);
+ }
+
+ // Wait for Console
+ if (rc = WaitForSingleObject(hStartHardwareEvent, INFINITE))
+ {
+#if DBG
+ DbgPrint("Os2VDMGetStartThread: WaitForSingleObject(hStartHardwareEvent, INFINITE) failed, rc = %d\n",
+ rc);
+#endif // DBG
+ ExitThread(rc);
+ }
+
+ // Release PMNTGetFullScreen
+ if (!SetEvent((Parameter == NULL) ? hPMNTVDMEvent:(HANDLE)Parameter))
+ {
+#if DBG
+ DbgPrint("Os2VDMGetStartThread: SetEvent(%x) failed, error=%x\n",
+ (Parameter == NULL) ? hPMNTVDMEvent:(HANDLE)Parameter,
+ GetLastError());
+#endif // DBG
+ ExitThread(1L);
+ }
+
+ ExitThread(0L);
+}
+#endif // not PMNT_DAYTONA
+
+/*****************************************************************************
+ * Os2VDMThread: *
+ * Created & used by PMNTSetFullScreen(). It will handle the handshake with *
+ * the Console for the first transaction which indicates we have received *
+ * the control of the screen, i.e. right after going full-screen. *
+ *****************************************************************************/
+VOID
+Os2VDMThread(
+ IN PVOID Parameter
+ )
+{
+ ULONG rc;
+#ifndef PMNT_DAYTONA
+ DWORD Status;
+ HANDLE ThreadHandle = NULL;
+ ULONG Tid;
+#endif // not PMNT_DAYTONA
+
+#if DBG
+ DbgPrint("Os2VDMThread: waiting for getting hardware\n");
+#endif // DBG
+
+ if (rc = WaitForSingleObject(hStartHardwareEvent, INFINITE))
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: WaitForSingleObject(hStartHardwareEvent, INFINITE) #1 failed, rc = %d\n",
+ rc);
+#endif // DBG
+ ExitThread(rc);
+ }
+
+#ifdef PMNT_DAYTONA
+ if (!SetEvent(hEndHardwareEvent))
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: SetEvent(hEndHardwareEvent) #1 failed, error=%x\n",
+ GetLastError());
+#endif // DBG
+ ExitThread(1L);
+ }
+
+ if (rc = WaitForSingleObject(hStartHardwareEvent, INFINITE))
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: WaitForSingleObject(hStartHardwareEvent, INFINITE) #2 failed, rc = %d\n",
+ rc);
+#endif // DBG
+ ExitThread(rc);
+ }
+ if (!SetEvent(hEndHardwareEvent))
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: SetEvent(hEndHardwareEvent) #2 failed, error=%x\n",
+ GetLastError());
+#endif // DBG
+ ExitThread(1L);
+ }
+#else // not PMNT_DAYTONA
+ // Create a thread that will wait on the StartHardware event before
+ // we release the Console. This will prevent the Console from
+ // setting the event twice without letting us sense it twice
+
+ ThreadHandle = CreateThread( NULL,
+ 0,
+ (PFNTHREAD)Os2VDMGetStartThread,
+ hPMNTVDMEvent1,
+ 0,
+ &Tid);
+
+ if (ThreadHandle)
+ {
+ // Free memory associated with the thread object
+ Status = NtClose(ThreadHandle);
+#if DBG
+ if (!(Status >= 0))
+ {
+ DbgPrint("Os2VDMThread: NtClose(%x) failed, status=%x\n",
+ ThreadHandle, Status);
+ }
+#endif // DBG
+
+ // Wait till Os2VDMGetStartThread has started and is just about to
+ // call WaitForSingleObject(hStartHardwareEvent, INFINITE)
+ if (!Os2WaitForVDMThreadReady())
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: Os2WaitForVDMThread isn't useful, ThreadHandle = NULL\n");
+#endif // DBG
+ ThreadHandle = NULL;
+ }
+#if DBG
+ else
+ DbgPrint("Os2VDMThread: Os2VDMGetStartThread is ready\n");
+#endif // DBG
+ }
+#if DBG
+ else
+ {
+ DbgPrint("Os2VDMThread: CreateThread for Os2VDMGetStartThread failed, error=%x\n",
+ GetLastError());
+ }
+#endif // DBG
+
+ // Now we can safely notify the Console
+ if (!SetEvent(hEndHardwareEvent))
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: SetEvent(hEndHardwareEvent) fail, error=%x\n",
+ GetLastError());
+#endif
+ ExitThread(1L);
+ }
+
+ if (ThreadHandle != NULL)
+ {
+#if DBG
+ DbgPrint("Os2VDMThread waiting for Os2VDMGetStartThread()\n");
+#endif
+ // Wait for Os2VDMGetStartThread() to get events from the
+ // Console signifying we went full-screen
+ if (!Os2WaitForVDMThread(hPMNTVDMEvent1))
+ {
+ ExitThread(1L);
+ }
+ }
+ else
+ {
+ if (rc = WaitForSingleObject(hStartHardwareEvent, INFINITE))
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: WaitForSingleObject(hStartHardwareEvent, INFINITE) #2 failed, rc = %d\n",
+ rc);
+#endif
+ ExitThread(1L);
+ }
+ }
+#endif // not PMNT_DAYTONA
+
+ // Release PMNTSetFullScreen
+ if (!SetEvent(hPMNTVDMEvent))
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: SetEvent(hPMNTVDMEvent) fail, error=%x\n",
+ GetLastError());
+#endif
+ ExitThread(1L);
+ }
+
+#if DBG
+ DbgPrint("Os2VDMThread: wait for getting hardware done !\n");
+#endif
+
+ ExitThread(0L);
+}
+
+#endif /* PMNT */