--- /dev/null
- while (&CacheBlockToFree->ListEntry != &CacheDrive->CacheBlockHead && CacheBlockToFree->LockedInCache == TRUE)
+/*
+ * FreeLoader
+ * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <freeldr.h>
+#include <debug.h>
+
+DBG_DEFAULT_CHANNEL(CACHE);
+
+// Returns a pointer to a CACHE_BLOCK structure
+// Adds the block to the cache manager block list
+// in cache memory if it isn't already there
+PCACHE_BLOCK CacheInternalGetBlockPointer(PCACHE_DRIVE CacheDrive, ULONG BlockNumber)
+{
+ PCACHE_BLOCK CacheBlock = NULL;
+
+ TRACE("CacheInternalGetBlockPointer() BlockNumber = %d\n", BlockNumber);
+
+ CacheBlock = CacheInternalFindBlock(CacheDrive, BlockNumber);
+
+ if (CacheBlock != NULL)
+ {
+ TRACE("Cache hit! BlockNumber: %d CacheBlock->BlockNumber: %d\n", BlockNumber, CacheBlock->BlockNumber);
+
+ return CacheBlock;
+ }
+
+ TRACE("Cache miss! BlockNumber: %d\n", BlockNumber);
+
+ CacheBlock = CacheInternalAddBlockToCache(CacheDrive, BlockNumber);
+
+ // Optimize the block list so it has a LRU structure
+ CacheInternalOptimizeBlockList(CacheDrive, CacheBlock);
+
+ return CacheBlock;
+}
+
+PCACHE_BLOCK CacheInternalFindBlock(PCACHE_DRIVE CacheDrive, ULONG BlockNumber)
+{
+ PCACHE_BLOCK CacheBlock = NULL;
+
+ TRACE("CacheInternalFindBlock() BlockNumber = %d\n", BlockNumber);
+
+ //
+ // Make sure the block list has entries before I start searching it.
+ //
+ if (!IsListEmpty(&CacheDrive->CacheBlockHead))
+ {
+ //
+ // Search the list and find the BIOS drive number
+ //
+ CacheBlock = CONTAINING_RECORD(CacheDrive->CacheBlockHead.Flink, CACHE_BLOCK, ListEntry);
+
+ while (&CacheBlock->ListEntry != &CacheDrive->CacheBlockHead)
+ {
+ //
+ // We found the block, so return it
+ //
+ if (CacheBlock->BlockNumber == BlockNumber)
+ {
+ //
+ // Increment the blocks access count
+ //
+ CacheBlock->AccessCount++;
+
+ return CacheBlock;
+ }
+
+ CacheBlock = CONTAINING_RECORD(CacheBlock->ListEntry.Flink, CACHE_BLOCK, ListEntry);
+ }
+ }
+
+ return NULL;
+}
+
+PCACHE_BLOCK CacheInternalAddBlockToCache(PCACHE_DRIVE CacheDrive, ULONG BlockNumber)
+{
+ PCACHE_BLOCK CacheBlock = NULL;
+
+ TRACE("CacheInternalAddBlockToCache() BlockNumber = %d\n", BlockNumber);
+
+ // Check the size of the cache so we don't exceed our limits
+ CacheInternalCheckCacheSizeLimits(CacheDrive);
+
+ // We will need to add the block to the
+ // drive's list of cached blocks. So allocate
+ // the block memory.
+ CacheBlock = FrLdrTempAlloc(sizeof(CACHE_BLOCK), TAG_CACHE_BLOCK);
+ if (CacheBlock == NULL)
+ {
+ return NULL;
+ }
+
+ // Now initialize the structure and
+ // allocate room for the block data
+ RtlZeroMemory(CacheBlock, sizeof(CACHE_BLOCK));
+ CacheBlock->BlockNumber = BlockNumber;
+ CacheBlock->BlockData = FrLdrTempAlloc(CacheDrive->BlockSize * CacheDrive->BytesPerSector,
+ TAG_CACHE_DATA);
+ if (CacheBlock->BlockData ==NULL)
+ {
+ FrLdrTempFree(CacheBlock, TAG_CACHE_BLOCK);
+ return NULL;
+ }
+
+ // Now try to read in the block
+ if (!MachDiskReadLogicalSectors(CacheDrive->DriveNumber, (BlockNumber * CacheDrive->BlockSize), CacheDrive->BlockSize, (PVOID)DISKREADBUFFER))
+ {
+ FrLdrTempFree(CacheBlock->BlockData, TAG_CACHE_DATA);
+ FrLdrTempFree(CacheBlock, TAG_CACHE_BLOCK);
+ return NULL;
+ }
+ RtlCopyMemory(CacheBlock->BlockData, (PVOID)DISKREADBUFFER, CacheDrive->BlockSize * CacheDrive->BytesPerSector);
+
+ // Add it to our list of blocks managed by the cache
+ InsertTailList(&CacheDrive->CacheBlockHead, &CacheBlock->ListEntry);
+
+ // Update the cache data
+ CacheBlockCount++;
+ CacheSizeCurrent = CacheBlockCount * (CacheDrive->BlockSize * CacheDrive->BytesPerSector);
+
+ CacheInternalDumpBlockList(CacheDrive);
+
+ return CacheBlock;
+}
+
+BOOLEAN CacheInternalFreeBlock(PCACHE_DRIVE CacheDrive)
+{
+ PCACHE_BLOCK CacheBlockToFree;
+
+ TRACE("CacheInternalFreeBlock()\n");
+
+ // Get a pointer to the last item in the block list
+ // that isn't forced to be in the cache and remove
+ // it from the list
+ CacheBlockToFree = CONTAINING_RECORD(CacheDrive->CacheBlockHead.Blink, CACHE_BLOCK, ListEntry);
++ while (&CacheBlockToFree->ListEntry != &CacheDrive->CacheBlockHead && CacheBlockToFree->LockedInCache)
+ {
+ CacheBlockToFree = CONTAINING_RECORD(CacheBlockToFree->ListEntry.Blink, CACHE_BLOCK, ListEntry);
+ }
+
+ // No blocks left in cache that can be freed
+ // so just return
+ if (IsListEmpty(&CacheDrive->CacheBlockHead))
+ {
+ return FALSE;
+ }
+
+ RemoveEntryList(&CacheBlockToFree->ListEntry);
+
+ // Free the block memory and the block structure
+ FrLdrTempFree(CacheBlockToFree->BlockData, TAG_CACHE_DATA);
+ FrLdrTempFree(CacheBlockToFree, TAG_CACHE_BLOCK);
+
+ // Update the cache data
+ CacheBlockCount--;
+ CacheSizeCurrent = CacheBlockCount * (CacheDrive->BlockSize * CacheDrive->BytesPerSector);
+
+ return TRUE;
+}
+
+VOID CacheInternalCheckCacheSizeLimits(PCACHE_DRIVE CacheDrive)
+{
+ SIZE_T NewCacheSize;
+
+ TRACE("CacheInternalCheckCacheSizeLimits()\n");
+
+ // Calculate the size of the cache if we added a block
+ NewCacheSize = (CacheBlockCount + 1) * (CacheDrive->BlockSize * CacheDrive->BytesPerSector);
+
+ // Check the new size against the cache size limit
+ if (NewCacheSize > CacheSizeLimit)
+ {
+ CacheInternalFreeBlock(CacheDrive);
+ CacheInternalDumpBlockList(CacheDrive);
+ }
+}
+
+VOID CacheInternalDumpBlockList(PCACHE_DRIVE CacheDrive)
+{
+ PCACHE_BLOCK CacheBlock;
+
+ TRACE("Dumping block list for BIOS drive 0x%x.\n", CacheDrive->DriveNumber);
+ TRACE("BytesPerSector: %d.\n", CacheDrive->BytesPerSector);
+ TRACE("BlockSize: %d.\n", CacheDrive->BlockSize);
+ TRACE("CacheSizeLimit: %d.\n", CacheSizeLimit);
+ TRACE("CacheSizeCurrent: %d.\n", CacheSizeCurrent);
+ TRACE("CacheBlockCount: %d.\n", CacheBlockCount);
+
+ CacheBlock = CONTAINING_RECORD(CacheDrive->CacheBlockHead.Flink, CACHE_BLOCK, ListEntry);
+ while (&CacheBlock->ListEntry != &CacheDrive->CacheBlockHead)
+ {
+ TRACE("Cache Block: CacheBlock: 0x%x\n", CacheBlock);
+ TRACE("Cache Block: Block Number: %d\n", CacheBlock->BlockNumber);
+ TRACE("Cache Block: Access Count: %d\n", CacheBlock->AccessCount);
+ TRACE("Cache Block: Block Data: 0x%x\n", CacheBlock->BlockData);
+ TRACE("Cache Block: Locked In Cache: %d\n", CacheBlock->LockedInCache);
+
+ if (CacheBlock->BlockData == NULL)
+ {
+ BugCheck("CacheBlock->BlockData == NULL\n");
+ }
+
+ CacheBlock = CONTAINING_RECORD(CacheBlock->ListEntry.Flink, CACHE_BLOCK, ListEntry);
+ }
+}
+
+VOID CacheInternalOptimizeBlockList(PCACHE_DRIVE CacheDrive, PCACHE_BLOCK CacheBlock)
+{
+
+ TRACE("CacheInternalOptimizeBlockList()\n");
+
+ // Don't do this if this block is already at the head of the list
+ if (&CacheBlock->ListEntry != CacheDrive->CacheBlockHead.Flink)
+ {
+ // Remove this item from the block list
+ RemoveEntryList(&CacheBlock->ListEntry);
+
+ // Re-insert it at the head of the list
+ InsertHeadList(&CacheDrive->CacheBlockHead, &CacheBlock->ListEntry);
+ }
+}
--- /dev/null
- if ((CacheManagerInitialized == TRUE) &&
+/*
+ * FreeLoader
+ * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <freeldr.h>
+#include <debug.h>
+
+DBG_DEFAULT_CHANNEL(CACHE);
+
+///////////////////////////////////////////////////////////////////////////////////////
+//
+// Internal data
+//
+///////////////////////////////////////////////////////////////////////////////////////
+CACHE_DRIVE CacheManagerDrive;
+BOOLEAN CacheManagerInitialized = FALSE;
+BOOLEAN CacheManagerDataInvalid = FALSE;
+ULONG CacheBlockCount = 0;
+SIZE_T CacheSizeLimit = 0;
+SIZE_T CacheSizeCurrent = 0;
+
+BOOLEAN CacheInitializeDrive(UCHAR DriveNumber)
+{
+ PCACHE_BLOCK NextCacheBlock;
+ GEOMETRY DriveGeometry;
+
+ // If we already have a cache for this drive then
+ // by all means lets keep it, unless it is a removable
+ // drive, in which case we'll invalidate the cache
- (CacheManagerDataInvalid != TRUE))
++ if ((CacheManagerInitialized) &&
+ (DriveNumber == CacheManagerDrive.DriveNumber) &&
+ (DriveNumber >= 0x80) &&
++ (!CacheManagerDataInvalid))
+ {
+ return TRUE;
+ }
+
+ CacheManagerDataInvalid = FALSE;
+
+ //
+ // If we have already been initialized then free
+ // the old data
+ //
+ if (CacheManagerInitialized)
+ {
+ CacheManagerInitialized = FALSE;
+
+ TRACE("CacheBlockCount: %d\n", CacheBlockCount);
+ TRACE("CacheSizeLimit: %d\n", CacheSizeLimit);
+ TRACE("CacheSizeCurrent: %d\n", CacheSizeCurrent);
+ //
+ // Loop through and free the cache blocks
+ //
+ while (!IsListEmpty(&CacheManagerDrive.CacheBlockHead))
+ {
+ NextCacheBlock = CONTAINING_RECORD(RemoveHeadList(&CacheManagerDrive.CacheBlockHead),
+ CACHE_BLOCK,
+ ListEntry);
+
+ FrLdrTempFree(NextCacheBlock->BlockData, TAG_CACHE_DATA);
+ FrLdrTempFree(NextCacheBlock, TAG_CACHE_BLOCK);
+ }
+ }
+
+ // Initialize the structure
+ RtlZeroMemory(&CacheManagerDrive, sizeof(CACHE_DRIVE));
+ InitializeListHead(&CacheManagerDrive.CacheBlockHead);
+ CacheManagerDrive.DriveNumber = DriveNumber;
+ if (!MachDiskGetDriveGeometry(DriveNumber, &DriveGeometry))
+ {
+ return FALSE;
+ }
+ CacheManagerDrive.BytesPerSector = DriveGeometry.BytesPerSector;
+
+ // Get the number of sectors in each cache block
+ CacheManagerDrive.BlockSize = MachDiskGetCacheableBlockCount(DriveNumber);
+
+ CacheBlockCount = 0;
+ CacheSizeLimit = TotalPagesInLookupTable / 8 * MM_PAGE_SIZE;
+ CacheSizeCurrent = 0;
+ if (CacheSizeLimit > TEMP_HEAP_SIZE - (128 * 1024))
+ {
+ CacheSizeLimit = TEMP_HEAP_SIZE - (128 * 1024);
+ }
+
+ CacheManagerInitialized = TRUE;
+
+ TRACE("Initializing BIOS drive 0x%x.\n", DriveNumber);
+ TRACE("BytesPerSector: %d.\n", CacheManagerDrive.BytesPerSector);
+ TRACE("BlockSize: %d.\n", CacheManagerDrive.BlockSize);
+ TRACE("CacheSizeLimit: %d.\n", CacheSizeLimit);
+
+ return TRUE;
+}
+
+VOID CacheInvalidateCacheData(VOID)
+{
+ CacheManagerDataInvalid = TRUE;
+}
+
+BOOLEAN CacheReadDiskSectors(UCHAR DiskNumber, ULONGLONG StartSector, ULONG SectorCount, PVOID Buffer)
+{
+ PCACHE_BLOCK CacheBlock;
+ ULONG StartBlock;
+ ULONG SectorOffsetInStartBlock;
+ ULONG CopyLengthInStartBlock;
+ ULONG EndBlock;
+ ULONG SectorOffsetInEndBlock;
+ ULONG BlockCount;
+ ULONG Idx;
+
+ TRACE("CacheReadDiskSectors() DiskNumber: 0x%x StartSector: %I64d SectorCount: %d Buffer: 0x%x\n", DiskNumber, StartSector, SectorCount, Buffer);
+
+ // If we aren't initialized yet then they can't do this
+ if (CacheManagerInitialized == FALSE)
+ {
+ return FALSE;
+ }
+
+ //
+ // Caculate which blocks we must cache
+ //
+ StartBlock = (ULONG)(StartSector / CacheManagerDrive.BlockSize);
+ SectorOffsetInStartBlock = (ULONG)(StartSector % CacheManagerDrive.BlockSize);
+ CopyLengthInStartBlock = (ULONG)((SectorCount > (CacheManagerDrive.BlockSize - SectorOffsetInStartBlock)) ? (CacheManagerDrive.BlockSize - SectorOffsetInStartBlock) : SectorCount);
+ EndBlock = (ULONG)((StartSector + (SectorCount - 1)) / CacheManagerDrive.BlockSize);
+ SectorOffsetInEndBlock = (ULONG)(1 + (StartSector + (SectorCount - 1)) % CacheManagerDrive.BlockSize);
+ BlockCount = (EndBlock - StartBlock) + 1;
+ TRACE("StartBlock: %d SectorOffsetInStartBlock: %d CopyLengthInStartBlock: %d EndBlock: %d SectorOffsetInEndBlock: %d BlockCount: %d\n", StartBlock, SectorOffsetInStartBlock, CopyLengthInStartBlock, EndBlock, SectorOffsetInEndBlock, BlockCount);
+
+ //
+ // Read the first block into the buffer
+ //
+ if (BlockCount > 0)
+ {
+ //
+ // Get cache block pointer (this forces the disk sectors into the cache memory)
+ //
+ CacheBlock = CacheInternalGetBlockPointer(&CacheManagerDrive, StartBlock);
+ if (CacheBlock == NULL)
+ {
+ return FALSE;
+ }
+
+ //
+ // Copy the portion requested into the buffer
+ //
+ RtlCopyMemory(Buffer,
+ (PVOID)((ULONG_PTR)CacheBlock->BlockData + (SectorOffsetInStartBlock * CacheManagerDrive.BytesPerSector)),
+ (CopyLengthInStartBlock * CacheManagerDrive.BytesPerSector));
+ TRACE("1 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer, ((ULONG_PTR)CacheBlock->BlockData + (SectorOffsetInStartBlock * CacheManagerDrive.BytesPerSector)), (CopyLengthInStartBlock * CacheManagerDrive.BytesPerSector));
+
+ //
+ // Update the buffer address
+ //
+ Buffer = (PVOID)((ULONG_PTR)Buffer + (CopyLengthInStartBlock * CacheManagerDrive.BytesPerSector));
+
+ //
+ // Update the block count
+ //
+ BlockCount--;
+ }
+
+ //
+ // Loop through the middle blocks and read them into the buffer
+ //
+ for (Idx=StartBlock+1; BlockCount>1; Idx++)
+ {
+ //
+ // Get cache block pointer (this forces the disk sectors into the cache memory)
+ //
+ CacheBlock = CacheInternalGetBlockPointer(&CacheManagerDrive, Idx);
+ if (CacheBlock == NULL)
+ {
+ return FALSE;
+ }
+
+ //
+ // Copy the portion requested into the buffer
+ //
+ RtlCopyMemory(Buffer,
+ CacheBlock->BlockData,
+ CacheManagerDrive.BlockSize * CacheManagerDrive.BytesPerSector);
+ TRACE("2 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer, CacheBlock->BlockData, CacheManagerDrive.BlockSize * CacheManagerDrive.BytesPerSector);
+
+ //
+ // Update the buffer address
+ //
+ Buffer = (PVOID)((ULONG_PTR)Buffer + (CacheManagerDrive.BlockSize * CacheManagerDrive.BytesPerSector));
+
+ //
+ // Update the block count
+ //
+ BlockCount--;
+ }
+
+ //
+ // Read the last block into the buffer
+ //
+ if (BlockCount > 0)
+ {
+ //
+ // Get cache block pointer (this forces the disk sectors into the cache memory)
+ //
+ CacheBlock = CacheInternalGetBlockPointer(&CacheManagerDrive, EndBlock);
+ if (CacheBlock == NULL)
+ {
+ return FALSE;
+ }
+
+ //
+ // Copy the portion requested into the buffer
+ //
+ RtlCopyMemory(Buffer,
+ CacheBlock->BlockData,
+ SectorOffsetInEndBlock * CacheManagerDrive.BytesPerSector);
+ TRACE("3 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer, CacheBlock->BlockData, SectorOffsetInEndBlock * CacheManagerDrive.BytesPerSector);
+
+ //
+ // Update the buffer address
+ //
+ Buffer = (PVOID)((ULONG_PTR)Buffer + (SectorOffsetInEndBlock * CacheManagerDrive.BytesPerSector));
+
+ //
+ // Update the block count
+ //
+ BlockCount--;
+ }
+
+ return TRUE;
+}
+
+#if 0
+BOOLEAN CacheForceDiskSectorsIntoCache(UCHAR DiskNumber, ULONGLONG StartSector, ULONG SectorCount)
+{
+ PCACHE_BLOCK CacheBlock;
+ ULONG StartBlock;
+ ULONG EndBlock;
+ ULONG BlockCount;
+ ULONG Idx;
+
+ TRACE("CacheForceDiskSectorsIntoCache() DiskNumber: 0x%x StartSector: %d SectorCount: %d\n", DiskNumber, StartSector, SectorCount);
+
+ // If we aren't initialized yet then they can't do this
+ if (CacheManagerInitialized == FALSE)
+ {
+ return FALSE;
+ }
+
+ //
+ // Caculate which blocks we must cache
+ //
+ StartBlock = StartSector / CacheManagerDrive.BlockSize;
+ EndBlock = (StartSector + SectorCount) / CacheManagerDrive.BlockSize;
+ BlockCount = (EndBlock - StartBlock) + 1;
+
+ //
+ // Loop through and cache them
+ //
+ for (Idx=StartBlock; Idx<(StartBlock+BlockCount); Idx++)
+ {
+ //
+ // Get cache block pointer (this forces the disk sectors into the cache memory)
+ //
+ CacheBlock = CacheInternalGetBlockPointer(&CacheManagerDrive, Idx);
+ if (CacheBlock == NULL)
+ {
+ return FALSE;
+ }
+
+ //
+ // Lock the sectors into the cache
+ //
+ CacheBlock->LockedInCache = TRUE;
+ }
+
+ return TRUE;
+}
+#endif
+
+BOOLEAN CacheReleaseMemory(ULONG MinimumAmountToRelease)
+{
+ ULONG AmountReleased;
+
+ TRACE("CacheReleaseMemory() MinimumAmountToRelease = %d\n", MinimumAmountToRelease);
+
+ // If we aren't initialized yet then they can't do this
+ if (CacheManagerInitialized == FALSE)
+ {
+ return FALSE;
+ }
+
+ // Loop through and try to free the requested amount of memory
+ for (AmountReleased=0; AmountReleased<MinimumAmountToRelease; )
+ {
+ // Try to free a block
+ // If this fails then break out of the loop
+ if (!CacheInternalFreeBlock(&CacheManagerDrive))
+ {
+ break;
+ }
+
+ // It succeeded so increment the amount of memory we have freed
+ AmountReleased += CacheManagerDrive.BlockSize * CacheManagerDrive.BytesPerSector;
+ }
+
+ // Return status
+ return (AmountReleased >= MinimumAmountToRelease);
+}
--- /dev/null
- if ((NewStyleLinuxKernel == FALSE) && (LinuxHasInitrd == TRUE))
+/*
+ * FreeLoader
+ * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _M_ARM
+
+#include <freeldr.h>
+#include <debug.h>
+#ifdef __i386__
+#define LINUX_READ_CHUNK_SIZE 0x20000 // Read 128k at a time
+
+DBG_DEFAULT_CHANNEL(LINUX);
+
+PLINUX_BOOTSECTOR LinuxBootSector = NULL;
+PLINUX_SETUPSECTOR LinuxSetupSector = NULL;
+ULONG SetupSectorSize = 0;
+BOOLEAN NewStyleLinuxKernel = FALSE;
+ULONG LinuxKernelSize = 0;
+ULONG LinuxInitrdSize = 0;
+CHAR LinuxKernelName[260];
+CHAR LinuxInitrdName[260];
+BOOLEAN LinuxHasInitrd = FALSE;
+CHAR LinuxCommandLine[260] = "";
+ULONG LinuxCommandLineSize = 0;
+PVOID LinuxKernelLoadAddress = NULL;
+PVOID LinuxInitrdLoadAddress = NULL;
+CHAR LinuxBootDescription[80];
+CHAR LinuxBootPath[260] = "";
+
+BOOLEAN RemoveQuotes(PCHAR QuotedString)
+{
+ CHAR TempString[200];
+ PCHAR p;
+ PSTR Start;
+
+ //
+ // Skip spaces up to "
+ //
+ p = QuotedString;
+ while (*p == ' ' || *p == '"')
+ p++;
+ Start = p;
+
+ //
+ // Go up to next "
+ //
+ while (*p != '"' && *p != ANSI_NULL)
+ p++;
+ *p = ANSI_NULL;
+
+ //
+ // Copy result
+ //
+ strcpy(TempString, Start);
+ strcpy(QuotedString, TempString);
+
+ return TRUE;
+}
+
+VOID
+LoadAndBootLinux(IN OperatingSystemItem* OperatingSystem,
+ IN USHORT OperatingSystemVersion)
+{
+ PCSTR SectionName = OperatingSystem->SystemPartition;
+ PCSTR Description = OperatingSystem->LoadIdentifier;
+ PFILE LinuxKernel = 0;
+ PFILE LinuxInitrdFile = 0;
+ CHAR TempString[260];
+
+ UiDrawBackdrop();
+
+ if (Description)
+ {
+ sprintf(LinuxBootDescription, "Loading %s...", Description);
+ }
+ else
+ {
+ strcpy(LinuxBootDescription, "Loading Linux...");
+ }
+
+ UiDrawStatusText(LinuxBootDescription);
+ UiDrawProgressBarCenter(0, 100, LinuxBootDescription);
+
+ // Parse the .ini file section
+ if (!LinuxParseIniSection(SectionName))
+ {
+ goto LinuxBootFailed;
+ }
+
+ // Open the kernel
+ LinuxKernel = FsOpenFile(LinuxKernelName);
+ if (!LinuxKernel)
+ {
+ sprintf(TempString, "Linux kernel \'%s\' not found.", LinuxKernelName);
+ UiMessageBox(TempString);
+ goto LinuxBootFailed;
+ }
+
+ // Open the initrd file image (if necessary)
+ if (LinuxHasInitrd)
+ {
+ LinuxInitrdFile = FsOpenFile(LinuxInitrdName);
+ if (!LinuxInitrdFile)
+ {
+ sprintf(TempString, "Linux initrd image \'%s\' not found.", LinuxInitrdName);
+ UiMessageBox(TempString);
+ goto LinuxBootFailed;
+ }
+ }
+
+ // Read the boot sector
+ if (!LinuxReadBootSector(LinuxKernel))
+ {
+ goto LinuxBootFailed;
+ }
+
+ // Read the setup sector
+ if (!LinuxReadSetupSector(LinuxKernel))
+ {
+ goto LinuxBootFailed;
+ }
+
+ // Calc kernel size
+ LinuxKernelSize = FsGetFileSize(LinuxKernel) - (512 + SetupSectorSize);
+
+ // Get the file size
+ LinuxInitrdSize = FsGetFileSize(LinuxInitrdFile);
+
+ // Read the kernel
+ if (!LinuxReadKernel(LinuxKernel))
+ {
+ goto LinuxBootFailed;
+ }
+
+ // Read the initrd (if necessary)
+ if (LinuxHasInitrd)
+ {
+ if (!LinuxReadInitrd(LinuxInitrdFile))
+ {
+ goto LinuxBootFailed;
+ }
+ }
+
+ // If the default root device is set to FLOPPY (0000h), change to /dev/fd0 (0200h)
+ if (LinuxBootSector->RootDevice == 0x0000)
+ {
+ LinuxBootSector->RootDevice = 0x0200;
+ }
+
+ if (LinuxSetupSector->Version >= 0x0202)
+ {
+ LinuxSetupSector->CommandLinePointer = 0x99000;
+ }
+ else
+ {
+ LinuxBootSector->CommandLineMagic = LINUX_COMMAND_LINE_MAGIC;
+ LinuxBootSector->CommandLineOffset = 0x9000;
+ }
+
+ if (NewStyleLinuxKernel)
+ {
+ LinuxSetupSector->TypeOfLoader = LINUX_LOADER_TYPE_FREELOADER;
+ }
+ else
+ {
+ LinuxSetupSector->LoadFlags = 0;
+ }
+
+ RtlCopyMemory((PVOID)0x90000, LinuxBootSector, 512);
+ RtlCopyMemory((PVOID)0x90200, LinuxSetupSector, SetupSectorSize);
+ RtlCopyMemory((PVOID)0x99000, LinuxCommandLine, LinuxCommandLineSize);
+
+ UiUnInitialize("Booting Linux...");
+
+ DiskStopFloppyMotor();
+
+ if (LinuxSetupSector->LoadFlags & LINUX_FLAG_LOAD_HIGH)
+ {
+ BootNewLinuxKernel();
+ }
+ else
+ {
+ BootOldLinuxKernel(LinuxKernelSize);
+ }
+
+
+LinuxBootFailed:
+
+ if (LinuxKernel)
+ {
+ FsCloseFile(LinuxKernel);
+ }
+ if (LinuxInitrdFile)
+ {
+ FsCloseFile(LinuxInitrdFile);
+ }
+
+ if (LinuxBootSector != NULL)
+ {
+ MmFreeMemory(LinuxBootSector);
+ }
+ if (LinuxSetupSector != NULL)
+ {
+ MmFreeMemory(LinuxSetupSector);
+ }
+ if (LinuxKernelLoadAddress != NULL)
+ {
+ MmFreeMemory(LinuxKernelLoadAddress);
+ }
+ if (LinuxInitrdLoadAddress != NULL)
+ {
+ MmFreeMemory(LinuxInitrdLoadAddress);
+ }
+
+ LinuxBootSector = NULL;
+ LinuxSetupSector = NULL;
+ LinuxKernelLoadAddress = NULL;
+ LinuxInitrdLoadAddress = NULL;
+ SetupSectorSize = 0;
+ NewStyleLinuxKernel = FALSE;
+ LinuxKernelSize = 0;
+ LinuxHasInitrd = FALSE;
+ strcpy(LinuxCommandLine, "");
+ LinuxCommandLineSize = 0;
+}
+
+BOOLEAN LinuxParseIniSection(PCSTR SectionName)
+{
+ ULONG_PTR SectionId;
+ CHAR SettingName[260];
+
+ // Find all the message box settings and run them
+ UiShowMessageBoxesInSection(SectionName);
+
+ // Try to open the operating system section in the .ini file
+ if (!IniOpenSection(SectionName, &SectionId))
+ {
+ sprintf(SettingName, "Section [%s] not found in freeldr.ini.\n", SectionName);
+ UiMessageBox(SettingName);
+ return FALSE;
+ }
+
+ if (!IniReadSettingByName(SectionId, "BootPath", LinuxBootPath, sizeof(LinuxBootPath)))
+ {
+ UiMessageBox("Boot path not specified for selected OS!");
+ return FALSE;
+ }
+
+ // Get the kernel name
+ if (!IniReadSettingByName(SectionId, "Kernel", LinuxKernelName, sizeof(LinuxKernelName)))
+ {
+ UiMessageBox("Linux kernel filename not specified for selected OS!");
+ return FALSE;
+ }
+
+ // Get the initrd name
+ if (IniReadSettingByName(SectionId, "Initrd", LinuxInitrdName, sizeof(LinuxInitrdName)))
+ {
+ LinuxHasInitrd = TRUE;
+ }
+
+ // Get the command line
+ if (IniReadSettingByName(SectionId, "CommandLine", LinuxCommandLine, sizeof(LinuxCommandLine)))
+ {
+ RemoveQuotes(LinuxCommandLine);
+ LinuxCommandLineSize = strlen(LinuxCommandLine) + 1;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN LinuxReadBootSector(PFILE LinuxKernelFile)
+{
+ // Allocate memory for boot sector
+ LinuxBootSector = MmAllocateMemoryWithType(512, LoaderSystemCode);
+ if (LinuxBootSector == NULL)
+ {
+ return FALSE;
+ }
+
+ // Read linux boot sector
+ FsSetFilePointer(LinuxKernelFile, 0);
+ if (!FsReadFile(LinuxKernelFile, 512, NULL, LinuxBootSector))
+ {
+ return FALSE;
+ }
+
+ // Check for validity
+ if (LinuxBootSector->BootFlag != LINUX_BOOT_SECTOR_MAGIC)
+ {
+ UiMessageBox("Invalid boot sector magic (0xaa55)");
+ return FALSE;
+ }
+
+ DbgDumpBuffer(DPRINT_LINUX, LinuxBootSector, 512);
+
+ TRACE("SetupSectors: %d\n", LinuxBootSector->SetupSectors);
+ TRACE("RootFlags: 0x%x\n", LinuxBootSector->RootFlags);
+ TRACE("SystemSize: 0x%x\n", LinuxBootSector->SystemSize);
+ TRACE("SwapDevice: 0x%x\n", LinuxBootSector->SwapDevice);
+ TRACE("RamSize: 0x%x\n", LinuxBootSector->RamSize);
+ TRACE("VideoMode: 0x%x\n", LinuxBootSector->VideoMode);
+ TRACE("RootDevice: 0x%x\n", LinuxBootSector->RootDevice);
+ TRACE("BootFlag: 0x%x\n", LinuxBootSector->BootFlag);
+
+ return TRUE;
+}
+
+BOOLEAN LinuxReadSetupSector(PFILE LinuxKernelFile)
+{
+ UCHAR TempLinuxSetupSector[512];
+
+ LinuxSetupSector = (PLINUX_SETUPSECTOR)TempLinuxSetupSector;
+
+ // Read first linux setup sector
+ FsSetFilePointer(LinuxKernelFile, 512);
+ if (!FsReadFile(LinuxKernelFile, 512, NULL, TempLinuxSetupSector))
+ {
+ return FALSE;
+ }
+
+ // Check the kernel version
+ if (!LinuxCheckKernelVersion())
+ {
+ return FALSE;
+ }
+
+ if (NewStyleLinuxKernel)
+ {
+ SetupSectorSize = 512 * LinuxBootSector->SetupSectors;
+ }
+ else
+ {
+ SetupSectorSize = 4 * 512; // Always 4 setup sectors
+ }
+
+ // Allocate memory for setup sectors
+ LinuxSetupSector = MmAllocateMemoryWithType(SetupSectorSize, LoaderSystemCode);
+ if (LinuxSetupSector == NULL)
+ {
+ return FALSE;
+ }
+
+ // Copy over first setup sector
+ RtlCopyMemory(LinuxSetupSector, TempLinuxSetupSector, 512);
+
+ // Read in the rest of the linux setup sectors
+ FsSetFilePointer(LinuxKernelFile, 1024);
+ if (!FsReadFile(LinuxKernelFile, SetupSectorSize - 512, NULL, (PVOID)((ULONG_PTR)LinuxSetupSector + 512)))
+ {
+ return FALSE;
+ }
+
+ DbgDumpBuffer(DPRINT_LINUX, LinuxSetupSector, SetupSectorSize);
+
+ TRACE("SetupHeaderSignature: 0x%x (HdrS)\n", LinuxSetupSector->SetupHeaderSignature);
+ TRACE("Version: 0x%x\n", LinuxSetupSector->Version);
+ TRACE("RealModeSwitch: 0x%x\n", LinuxSetupSector->RealModeSwitch);
+ TRACE("SetupSeg: 0x%x\n", LinuxSetupSector->SetupSeg);
+ TRACE("StartSystemSeg: 0x%x\n", LinuxSetupSector->StartSystemSeg);
+ TRACE("KernelVersion: 0x%x\n", LinuxSetupSector->KernelVersion);
+ TRACE("TypeOfLoader: 0x%x\n", LinuxSetupSector->TypeOfLoader);
+ TRACE("LoadFlags: 0x%x\n", LinuxSetupSector->LoadFlags);
+ TRACE("SetupMoveSize: 0x%x\n", LinuxSetupSector->SetupMoveSize);
+ TRACE("Code32Start: 0x%x\n", LinuxSetupSector->Code32Start);
+ TRACE("RamdiskAddress: 0x%x\n", LinuxSetupSector->RamdiskAddress);
+ TRACE("RamdiskSize: 0x%x\n", LinuxSetupSector->RamdiskSize);
+ TRACE("BootSectKludgeOffset: 0x%x\n", LinuxSetupSector->BootSectKludgeOffset);
+ TRACE("BootSectKludgeSegment: 0x%x\n", LinuxSetupSector->BootSectKludgeSegment);
+ TRACE("HeapEnd: 0x%x\n", LinuxSetupSector->HeapEnd);
+
+ return TRUE;
+}
+
+BOOLEAN LinuxReadKernel(PFILE LinuxKernelFile)
+{
+ ULONG BytesLoaded;
+ CHAR StatusText[260];
+ PVOID LoadAddress;
+
+ sprintf(StatusText, "Loading %s", LinuxKernelName);
+ UiDrawStatusText(StatusText);
+
+ // Allocate memory for Linux kernel
+ LinuxKernelLoadAddress = MmAllocateMemoryAtAddress(LinuxKernelSize, (PVOID)LINUX_KERNEL_LOAD_ADDRESS, LoaderSystemCode);
+ if (LinuxKernelLoadAddress != (PVOID)LINUX_KERNEL_LOAD_ADDRESS)
+ {
+ return FALSE;
+ }
+
+ LoadAddress = LinuxKernelLoadAddress;
+
+ // Read linux kernel to 0x100000 (1mb)
+ FsSetFilePointer(LinuxKernelFile, 512 + SetupSectorSize);
+ for (BytesLoaded=0; BytesLoaded<LinuxKernelSize; )
+ {
+ if (!FsReadFile(LinuxKernelFile, LINUX_READ_CHUNK_SIZE, NULL, LoadAddress))
+ {
+ return FALSE;
+ }
+
+ BytesLoaded += LINUX_READ_CHUNK_SIZE;
+ LoadAddress = (PVOID)((ULONG_PTR)LoadAddress + LINUX_READ_CHUNK_SIZE);
+
+ UiDrawProgressBarCenter(BytesLoaded, LinuxKernelSize + LinuxInitrdSize, LinuxBootDescription);
+ }
+
+ return TRUE;
+}
+
+BOOLEAN LinuxCheckKernelVersion(VOID)
+{
+ // Just assume old kernel until we find otherwise
+ NewStyleLinuxKernel = FALSE;
+
+ // Check for new style setup header
+ if (LinuxSetupSector->SetupHeaderSignature != LINUX_SETUP_HEADER_ID)
+ {
+ NewStyleLinuxKernel = FALSE;
+ }
+ // Check for version below 2.0
+ else if (LinuxSetupSector->Version < 0x0200)
+ {
+ NewStyleLinuxKernel = FALSE;
+ }
+ // Check for version 2.0
+ else if (LinuxSetupSector->Version == 0x0200)
+ {
+ NewStyleLinuxKernel = TRUE;
+ }
+ // Check for version 2.01+
+ else if (LinuxSetupSector->Version >= 0x0201)
+ {
+ NewStyleLinuxKernel = TRUE;
+ LinuxSetupSector->HeapEnd = 0x9000;
+ LinuxSetupSector->LoadFlags |= LINUX_FLAG_CAN_USE_HEAP;
+ }
+
++ if ((NewStyleLinuxKernel == FALSE) && (LinuxHasInitrd))
+ {
+ UiMessageBox("Error: Cannot load a ramdisk (initrd) with an old kernel image.");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN LinuxReadInitrd(PFILE LinuxInitrdFile)
+{
+ ULONG BytesLoaded;
+ CHAR StatusText[260];
+
+ sprintf(StatusText, "Loading %s", LinuxInitrdName);
+ UiDrawStatusText(StatusText);
+
+ // Allocate memory for the ramdisk
+ //LinuxInitrdLoadAddress = MmAllocateMemory(LinuxInitrdSize);
+ // Try to align it at the next MB boundary after the kernel
+ //LinuxInitrdLoadAddress = MmAllocateMemoryAtAddress(LinuxInitrdSize, (PVOID)ROUND_UP((LINUX_KERNEL_LOAD_ADDRESS + LinuxKernelSize), 0x100000));
+ if (LinuxSetupSector->Version <= 0x0202)
+ {
+ LinuxInitrdLoadAddress = MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize, (PVOID)LINUX_MAX_INITRD_ADDRESS, LoaderSystemCode);
+ }
+ else
+ {
+ LinuxInitrdLoadAddress = MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize, (PVOID)LinuxSetupSector->InitrdAddressMax, LoaderSystemCode);
+ }
+ if (LinuxInitrdLoadAddress == NULL)
+ {
+ return FALSE;
+ }
+
+ // Set the information in the setup struct
+ LinuxSetupSector->RamdiskAddress = (ULONG)LinuxInitrdLoadAddress;
+ LinuxSetupSector->RamdiskSize = LinuxInitrdSize;
+
+ TRACE("RamdiskAddress: 0x%x\n", LinuxSetupSector->RamdiskAddress);
+ TRACE("RamdiskSize: 0x%x\n", LinuxSetupSector->RamdiskSize);
+
+ if (LinuxSetupSector->Version >= 0x0203)
+ {
+ TRACE("InitrdAddressMax: 0x%x\n", LinuxSetupSector->InitrdAddressMax);
+ }
+
+ // Read in the ramdisk
+ for (BytesLoaded=0; BytesLoaded<LinuxInitrdSize; )
+ {
+ if (!FsReadFile(LinuxInitrdFile, LINUX_READ_CHUNK_SIZE, NULL, (PVOID)LinuxInitrdLoadAddress))
+ {
+ return FALSE;
+ }
+
+ BytesLoaded += LINUX_READ_CHUNK_SIZE;
+ LinuxInitrdLoadAddress = (PVOID)((ULONG_PTR)LinuxInitrdLoadAddress + LINUX_READ_CHUNK_SIZE);
+
+ UiDrawProgressBarCenter(BytesLoaded + LinuxKernelSize, LinuxInitrdSize + LinuxKernelSize, LinuxBootDescription);
+ }
+
+ return TRUE;
+}
+#endif /* __i386__ */
+#endif
--- /dev/null
- CurrentSet = (LastKnownGood == TRUE) ? LastKnownGoodSet : DefaultSet;
+/*
+ * FreeLoader
+ *
+ * Copyright (C) 2014 Timo Kreuzer <timo.kreuzer@reactos.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <freeldr.h>
+#include <cmlib.h>
+#include <debug.h>
+
+DBG_DEFAULT_CHANNEL(REGISTRY);
+
+static PCMHIVE CmHive;
+static PCM_KEY_NODE RootKeyNode;
+static FRLDRHKEY CurrentControlSetKey;
+
+BOOLEAN
+RegImportBinaryHive(
+ _In_ PCHAR ChunkBase,
+ _In_ ULONG ChunkSize)
+{
+ NTSTATUS Status;
+ TRACE("RegImportBinaryHive(%p, 0x%lx)\n", ChunkBase, ChunkSize);
+
+ /* Allocate and initialize the hive */
+ CmHive = FrLdrTempAlloc(sizeof(CMHIVE), 'eviH');
+ Status = HvInitialize(&CmHive->Hive,
+ HINIT_FLAT,
+ 0,
+ 0,
+ ChunkBase,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 1,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ FrLdrTempFree(CmHive, 'eviH');
+ ERR("Invalid hive Signature!\n");
+ return FALSE;
+ }
+
+ /* Save the root key node */
+ RootKeyNode = HvGetCell(&CmHive->Hive, CmHive->Hive.BaseBlock->RootCell);
+
+ TRACE("RegImportBinaryHive done\n");
+ return TRUE;
+}
+
+VOID
+RegInitializeRegistry(VOID)
+{
+ /* Nothing to do */
+}
+
+
+LONG
+RegInitCurrentControlSet(
+ _In_ BOOLEAN LastKnownGood)
+{
+ WCHAR ControlSetKeyName[80];
+ FRLDRHKEY SelectKey;
+ FRLDRHKEY SystemKey;
+ ULONG CurrentSet = 0;
+ ULONG DefaultSet = 0;
+ ULONG LastKnownGoodSet = 0;
+ ULONG DataSize;
+ LONG Error;
+ TRACE("RegInitCurrentControlSet\n");
+
+ Error = RegOpenKey(NULL,
+ L"\\Registry\\Machine\\SYSTEM\\Select",
+ &SelectKey);
+ if (Error != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKey() failed (Error %u)\n", (int)Error);
+ return Error;
+ }
+
+ DataSize = sizeof(ULONG);
+ Error = RegQueryValue(SelectKey,
+ L"Default",
+ NULL,
+ (PUCHAR)&DefaultSet,
+ &DataSize);
+ if (Error != ERROR_SUCCESS)
+ {
+ ERR("RegQueryValue('Default') failed (Error %u)\n", (int)Error);
+ return Error;
+ }
+
+ DataSize = sizeof(ULONG);
+ Error = RegQueryValue(SelectKey,
+ L"LastKnownGood",
+ NULL,
+ (PUCHAR)&LastKnownGoodSet,
+ &DataSize);
+ if (Error != ERROR_SUCCESS)
+ {
+ ERR("RegQueryValue('Default') failed (Error %u)\n", (int)Error);
+ return Error;
+ }
+
++ CurrentSet = (LastKnownGood) ? LastKnownGoodSet : DefaultSet;
+ wcscpy(ControlSetKeyName, L"ControlSet");
+ switch(CurrentSet)
+ {
+ case 1:
+ wcscat(ControlSetKeyName, L"001");
+ break;
+ case 2:
+ wcscat(ControlSetKeyName, L"002");
+ break;
+ case 3:
+ wcscat(ControlSetKeyName, L"003");
+ break;
+ case 4:
+ wcscat(ControlSetKeyName, L"004");
+ break;
+ case 5:
+ wcscat(ControlSetKeyName, L"005");
+ break;
+ }
+
+ Error = RegOpenKey(NULL,
+ L"\\Registry\\Machine\\SYSTEM",
+ &SystemKey);
+ if (Error != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKey(SystemKey) failed (Error %lu)\n", Error);
+ return Error;
+ }
+
+ Error = RegOpenKey(SystemKey,
+ ControlSetKeyName,
+ &CurrentControlSetKey);
+ if (Error != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKey(CurrentControlSetKey) failed (Error %lu)\n", Error);
+ return Error;
+ }
+
+ TRACE("RegInitCurrentControlSet done\n");
+ return ERROR_SUCCESS;
+}
+
+static
+BOOLEAN
+GetNextPathElement(
+ _Out_ PUNICODE_STRING NextElement,
+ _Inout_ PUNICODE_STRING RemainingPath)
+{
+ /* Check if there are any characters left */
+ if (RemainingPath->Length < sizeof(WCHAR))
+ {
+ /* Nothing left, bail out early */
+ return FALSE;
+ }
+
+ /* The next path elements starts with the remaining path */
+ NextElement->Buffer = RemainingPath->Buffer;
+
+ /* Loop until the path element ends */
+ while ((RemainingPath->Length >= sizeof(WCHAR)) &&
+ (RemainingPath->Buffer[0] != '\\'))
+ {
+ /* Skip this character */
+ RemainingPath->Buffer++;
+ RemainingPath->Length -= sizeof(WCHAR);
+ }
+
+ NextElement->Length = (RemainingPath->Buffer - NextElement->Buffer) * sizeof(WCHAR);
+ NextElement->MaximumLength = NextElement->Length;
+
+ /* Check if the path element ended with a path separator */
+ if (RemainingPath->Length >= sizeof(WCHAR))
+ {
+ /* Skip the path separator */
+ ASSERT(RemainingPath->Buffer[0] == '\\');
+ RemainingPath->Buffer++;
+ RemainingPath->Length -= sizeof(WCHAR);
+ }
+
+ /* Return whether we got any characters */
+ return TRUE;
+}
+
+static
+PCM_KEY_NODE
+RegpFindSubkeyInIndex(
+ _In_ PHHIVE Hive,
+ _In_ PCM_KEY_INDEX IndexCell,
+ _In_ PUNICODE_STRING SubKeyName)
+{
+ PCM_KEY_NODE SubKeyNode;
+ ULONG i;
+ TRACE("RegpFindSubkeyInIndex('%wZ')\n", SubKeyName);
+
+ /* Check the cell type */
+ if ((IndexCell->Signature == CM_KEY_INDEX_ROOT) ||
+ (IndexCell->Signature == CM_KEY_INDEX_LEAF))
+ {
+ ASSERT(FALSE);
+
+ /* Enumerate subindex cells */
+ for (i = 0; i < IndexCell->Count; i++)
+ {
+ /* Get the subindex cell and call the function recursively */
+ PCM_KEY_INDEX SubIndexCell = HvGetCell(Hive, IndexCell->List[i]);
+
+ SubKeyNode = RegpFindSubkeyInIndex(Hive, SubIndexCell, SubKeyName);
+ if (SubKeyNode != NULL)
+ {
+ return SubKeyNode;
+ }
+ }
+ }
+ else if ((IndexCell->Signature == CM_KEY_FAST_LEAF) ||
+ (IndexCell->Signature == CM_KEY_HASH_LEAF))
+ {
+ /* Directly enumerate subkey nodes */
+ PCM_KEY_FAST_INDEX HashCell = (PCM_KEY_FAST_INDEX)IndexCell;
+ for (i = 0; i < HashCell->Count; i++)
+ {
+ SubKeyNode = HvGetCell(Hive, HashCell->List[i].Cell);
+ ASSERT(SubKeyNode->Signature == CM_KEY_NODE_SIGNATURE);
+
+ TRACE(" RegpFindSubkeyInIndex: checking '%.*s'\n",
+ SubKeyNode->NameLength, SubKeyNode->Name);
+ if (CmCompareKeyName(SubKeyNode, SubKeyName, TRUE))
+ {
+ return SubKeyNode;
+ }
+ }
+ }
+ else
+ {
+ ASSERT(FALSE);
+ }
+
+ return NULL;
+}
+
+LONG
+RegEnumKey(
+ _In_ FRLDRHKEY Key,
+ _In_ ULONG Index,
+ _Out_ PWCHAR Name,
+ _Inout_ ULONG* NameSize,
+ _Out_opt_ FRLDRHKEY *SubKey)
+{
+ PHHIVE Hive = &CmHive->Hive;
+ PCM_KEY_NODE KeyNode, SubKeyNode;
+ PCM_KEY_INDEX IndexCell;
+ PCM_KEY_FAST_INDEX HashCell;
+ TRACE("RegEnumKey(%p, %lu, %p, %p->%u)\n",
+ Key, Index, Name, NameSize, NameSize ? *NameSize : 0);
+
+ /* Get the key node */
+ KeyNode = (PCM_KEY_NODE)Key;
+ ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
+
+ /* Check if the index is valid */
+ if ((KeyNode->SubKeyCounts[Stable] == 0) ||
+ (Index >= KeyNode->SubKeyCounts[Stable]))
+ {
+ TRACE("RegEnumKey index out of bounds\n");
+ return ERROR_NO_MORE_ITEMS;
+ }
+
+ /* Get the index cell */
+ IndexCell = HvGetCell(Hive, KeyNode->SubKeyLists[Stable]);
+ TRACE("IndexCell: %x, SubKeyCounts: %x\n", IndexCell, KeyNode->SubKeyCounts[Stable]);
+
+ /* Check the cell type */
+ if ((IndexCell->Signature == CM_KEY_FAST_LEAF) ||
+ (IndexCell->Signature == CM_KEY_HASH_LEAF))
+ {
+ /* Get the value cell */
+ HashCell = (PCM_KEY_FAST_INDEX)IndexCell;
+ SubKeyNode = HvGetCell(Hive, HashCell->List[Index].Cell);
+ }
+ else
+ {
+ ASSERT(FALSE);
+ }
+
+ *NameSize = CmCopyKeyName(SubKeyNode, Name, *NameSize);
+
+ if (SubKey != NULL)
+ {
+ *SubKey = (FRLDRHKEY)SubKeyNode;
+ }
+
+ TRACE("RegEnumKey done -> %u, '%.*s'\n", *NameSize, *NameSize, Name);
+ return STATUS_SUCCESS;
+}
+
+LONG
+RegOpenKey(
+ _In_ FRLDRHKEY ParentKey,
+ _In_z_ PCWSTR KeyName,
+ _Out_ PFRLDRHKEY Key)
+{
+ UNICODE_STRING RemainingPath, SubKeyName;
+ UNICODE_STRING CurrentControlSet = RTL_CONSTANT_STRING(L"CurrentControlSet");
+ PHHIVE Hive = &CmHive->Hive;
+ PCM_KEY_NODE KeyNode;
+ PCM_KEY_INDEX IndexCell;
+ TRACE("RegOpenKey(%p, '%S', %p)\n", ParentKey, KeyName, Key);
+
+ /* Initialize the remaining path name */
+ RtlInitUnicodeString(&RemainingPath, KeyName);
+
+ /* Get the parent key node */
+ KeyNode = (PCM_KEY_NODE)ParentKey;
+
+ /* Check if we have a parent key */
+ if (KeyNode == NULL)
+ {
+ UNICODE_STRING SubKeyName1, SubKeyName2, SubKeyName3;
+ UNICODE_STRING RegistryPath = RTL_CONSTANT_STRING(L"Registry");
+ UNICODE_STRING MachinePath = RTL_CONSTANT_STRING(L"MACHINE");
+ UNICODE_STRING SystemPath = RTL_CONSTANT_STRING(L"SYSTEM");
+ TRACE("RegOpenKey: absolute path\n");
+
+ if ((RemainingPath.Length < sizeof(WCHAR)) ||
+ RemainingPath.Buffer[0] != '\\')
+ {
+ /* The key path is not absolute */
+ ERR("RegOpenKey: invalid path '%S' (%wZ)\n", KeyName, &RemainingPath);
+ return ERROR_PATH_NOT_FOUND;
+ }
+
+ /* Skip initial path separator */
+ RemainingPath.Buffer++;
+ RemainingPath.Length -= sizeof(WCHAR);
+
+ /* Get the first 3 path elements */
+ GetNextPathElement(&SubKeyName1, &RemainingPath);
+ GetNextPathElement(&SubKeyName2, &RemainingPath);
+ GetNextPathElement(&SubKeyName3, &RemainingPath);
+ TRACE("RegOpenKey: %wZ / %wZ / %wZ\n", &SubKeyName1, &SubKeyName2, &SubKeyName3);
+
+ /* Check if we have the correct path */
+ if (!RtlEqualUnicodeString(&SubKeyName1, &RegistryPath, TRUE) ||
+ !RtlEqualUnicodeString(&SubKeyName2, &MachinePath, TRUE) ||
+ !RtlEqualUnicodeString(&SubKeyName3, &SystemPath, TRUE))
+ {
+ /* The key path is not inside HKLM\Machine\System */
+ ERR("RegOpenKey: invalid path '%S' (%wZ)\n", KeyName, &RemainingPath);
+ return ERROR_PATH_NOT_FOUND;
+ }
+
+ /* Use the root key */
+ KeyNode = RootKeyNode;
+ }
+
+ ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
+
+ /* Check if this is the root key */
+ if (KeyNode == RootKeyNode)
+ {
+ UNICODE_STRING TempPath = RemainingPath;
+
+ /* Get the first path element */
+ GetNextPathElement(&SubKeyName, &TempPath);
+
+ /* Check if this is CurrentControlSet */
+ if (RtlEqualUnicodeString(&SubKeyName, &CurrentControlSet, TRUE))
+ {
+ /* Use the CurrentControlSetKey and update the remaining path */
+ KeyNode = (PCM_KEY_NODE)CurrentControlSetKey;
+ RemainingPath = TempPath;
+ }
+ }
+
+ TRACE("RegOpenKey: RemainingPath '%wZ'\n", &RemainingPath);
+
+ /* Loop while there are path elements */
+ while (GetNextPathElement(&SubKeyName, &RemainingPath))
+ {
+ TRACE("RegOpenKey: next element '%wZ'\n", &SubKeyName);
+
+ /* Check if there is any subkey */
+ if (KeyNode->SubKeyCounts[Stable] == 0)
+ {
+ return ERROR_PATH_NOT_FOUND;
+ }
+
+ /* Get the top level index cell */
+ IndexCell = HvGetCell(Hive, KeyNode->SubKeyLists[Stable]);
+
+ /* Get the next sub key */
+ KeyNode = RegpFindSubkeyInIndex(Hive, IndexCell, &SubKeyName);
+ if (KeyNode == NULL)
+ {
+
+ ERR("Did not find sub key '%wZ' (full %S)\n", &RemainingPath, KeyName);
+ return ERROR_PATH_NOT_FOUND;
+ }
+ }
+
+ TRACE("RegOpenKey done\n");
+ *Key = (FRLDRHKEY)KeyNode;
+ return ERROR_SUCCESS;
+}
+
+static
+VOID
+RepGetValueData(
+ _In_ PHHIVE Hive,
+ _In_ PCM_KEY_VALUE ValueCell,
+ _Out_opt_ ULONG* Type,
+ _Out_opt_ PUCHAR Data,
+ _Inout_opt_ ULONG* DataSize)
+{
+ ULONG DataLength;
+
+ /* Does the caller want the type? */
+ if (Type != NULL)
+ {
+ *Type = ValueCell->Type;
+ }
+
+ /* Does the caller provide DataSize? */
+ if (DataSize != NULL)
+ {
+ /* Get the data length */
+ DataLength = ValueCell->DataLength & REG_DATA_SIZE_MASK;
+
+ /* Does the caller want the data? */
+ if ((Data != NULL) && (*DataSize != 0))
+ {
+ /* Check where the data is stored */
+ if ((DataLength <= sizeof(HCELL_INDEX)) &&
+ (ValueCell->DataLength & REG_DATA_IN_OFFSET))
+ {
+ /* The data member contains the data */
+ RtlCopyMemory(Data,
+ &ValueCell->Data,
+ min(*DataSize, DataLength));
+ }
+ else
+ {
+ /* The data member contains the data cell index */
+ PVOID DataCell = HvGetCell(Hive, ValueCell->Data);
+ RtlCopyMemory(Data,
+ DataCell,
+ min(*DataSize, ValueCell->DataLength));
+ }
+
+ }
+
+ /* Return the actual data length */
+ *DataSize = DataLength;
+ }
+}
+
+LONG
+RegQueryValue(
+ _In_ FRLDRHKEY Key,
+ _In_z_ PCWSTR ValueName,
+ _Out_opt_ ULONG* Type,
+ _Out_opt_ PUCHAR Data,
+ _Inout_opt_ ULONG* DataSize)
+{
+ PHHIVE Hive = &CmHive->Hive;
+ PCM_KEY_NODE KeyNode;
+ PCM_KEY_VALUE ValueCell;
+ PVALUE_LIST_CELL ValueListCell;
+ UNICODE_STRING ValueNameString;
+ ULONG i;
+ TRACE("RegQueryValue(%p, '%S', %p, %p, %p)\n",
+ Key, ValueName, Type, Data, DataSize);
+
+ /* Get the key node */
+ KeyNode = (PCM_KEY_NODE)Key;
+ ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
+
+ /* Check if there are any values */
+ if (KeyNode->ValueList.Count == 0)
+ {
+ TRACE("RegQueryValue no values in key (%.*s)\n",
+ KeyNode->NameLength, KeyNode->Name);
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ /* Initialize value name string */
+ RtlInitUnicodeString(&ValueNameString, ValueName);
+
+ ValueListCell = (PVALUE_LIST_CELL)HvGetCell(Hive, KeyNode->ValueList.List);
+ TRACE("ValueListCell: %x\n", ValueListCell);
+
+ /* Loop all values */
+ for (i = 0; i < KeyNode->ValueList.Count; i++)
+ {
+ /* Get the subkey node and check the name */
+ ValueCell = HvGetCell(Hive, ValueListCell->ValueOffset[i]);
+
+ /* Compare the value name */
+ TRACE("checking %.*s\n", ValueCell->NameLength, ValueCell->Name);
+ if (CmCompareKeyValueName(ValueCell, &ValueNameString, TRUE))
+ {
+ RepGetValueData(Hive, ValueCell, Type, Data, DataSize);
+ TRACE("RegQueryValue success\n");
+ return STATUS_SUCCESS;
+ }
+ }
+
+ TRACE("RegQueryValue value not found\n");
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+LONG
+RegEnumValue(
+ _In_ FRLDRHKEY Key,
+ _In_ ULONG Index,
+ _Out_ PWCHAR ValueName,
+ _Inout_ ULONG* NameSize,
+ _Out_ ULONG* Type,
+ _Out_ PUCHAR Data,
+ _Inout_ ULONG* DataSize)
+{
+ PHHIVE Hive = &CmHive->Hive;
+ PCM_KEY_NODE KeyNode;
+ PCM_KEY_VALUE ValueCell;
+ PVALUE_LIST_CELL ValueListCell;
+ TRACE("RegEnumValue(%p, %lu, %S, %p, %p, %p, %p (%lu))\n",
+ Key, Index, ValueName, NameSize, Type, Data, DataSize, *DataSize);
+
+ /* Get the key node */
+ KeyNode = (PCM_KEY_NODE)Key;
+ ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
+
+ /* Check if the index is valid */
+ if ((KeyNode->ValueList.Count == 0) ||
+ (Index >= KeyNode->ValueList.Count))
+ {
+ ERR("RegEnumValue: index invalid\n");
+ return ERROR_NO_MORE_ITEMS;
+ }
+
+ ValueListCell = (PVALUE_LIST_CELL)HvGetCell(Hive, KeyNode->ValueList.List);
+ TRACE("ValueListCell: %x\n", ValueListCell);
+
+ /* Get the value cell */
+ ValueCell = HvGetCell(Hive, ValueListCell->ValueOffset[Index]);
+ ASSERT(ValueCell != NULL);
+
+ if (NameSize != NULL)
+ {
+ *NameSize = CmCopyKeyValueName(ValueCell, ValueName, *NameSize);
+ }
+
+ RepGetValueData(Hive, ValueCell, Type, Data, DataSize);
+
+ if (DataSize != NULL)
+ {
+ if ((Data != NULL) && (*DataSize != 0))
+ {
+ RtlCopyMemory(Data,
+ &ValueCell->Data,
+ min(*DataSize, ValueCell->DataLength));
+ }
+
+ *DataSize = ValueCell->DataLength;
+ }
+
+ TRACE("RegEnumValue done\n");
+ return STATUS_SUCCESS;
+}
+
+/* EOF */
--- /dev/null
- if (ppdev->bDDInitialized == TRUE)
+/*
+ * ReactOS Generic Framebuffer display driver directdraw interface
+ *
+ * Copyright (C) 2006 Magnus Olsen
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "framebuf.h"
+
+VOID APIENTRY
+DrvDisableDirectDraw( IN DHPDEV dhpdev)
+{
+ PPDEV ppdev = (PPDEV)dhpdev;
+ ppdev->bDDInitialized = FALSE;
+ /* Add Clean up code here if we need it
+ when we shout down directx interface */
+}
+
+BOOL APIENTRY
+DrvEnableDirectDraw(
+ IN DHPDEV dhpdev,
+ OUT DD_CALLBACKS *pCallBacks,
+ OUT DD_SURFACECALLBACKS *pSurfaceCallBacks,
+ OUT DD_PALETTECALLBACKS *pPaletteCallBacks)
+{
+ PPDEV ppdev = (PPDEV)dhpdev;
+
- if ( bDDrawHeap == TRUE)
++ if (ppdev->bDDInitialized)
+ {
+ return TRUE;
+ }
+
+ /* Setup pixel format */
+ ppdev->ddpfDisplay.dwSize = sizeof( DDPIXELFORMAT );
+ ppdev->ddpfDisplay.dwFourCC = 0;
+
+ ppdev->ddpfDisplay.dwRBitMask = ppdev->RedMask;
+ ppdev->ddpfDisplay.dwGBitMask = ppdev->GreenMask;
+ ppdev->ddpfDisplay.dwBBitMask = ppdev->BlueMask;
+
+ ppdev->ddpfDisplay.dwRGBBitCount=ppdev->BitsPerPixel;
+ ppdev->ddpfDisplay.dwRGBAlphaBitMask = 0;
+ ppdev->ddpfDisplay.dwFlags = DDPF_RGB;
+
+ ppdev->pvmList = NULL;
+
+ switch(ppdev->iDitherFormat)
+ {
+ case BMF_8BPP:
+ ppdev->ddpfDisplay.dwFlags |= DDPF_PALETTEINDEXED8;
+ break;
+
+ case BMF_16BPP:
+ switch(ppdev->RedMask)
+ {
+ case 0x7C00:
+ ppdev->ddpfDisplay.dwRGBAlphaBitMask = 0x8000;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case BMF_24BPP:
+ break;
+
+ case BMF_32BPP:
+ ppdev->ddpfDisplay.dwRGBAlphaBitMask = 0xff000000;
+ break;
+
+ default:
+ /* FIXME unknown pixel bits */
+ ppdev->ddpfDisplay.dwRGBBitCount=0;
+ break;
+ }
+
+ if (pCallBacks !=NULL)
+ {
+ memset(pCallBacks,0,sizeof(DD_CALLBACKS));
+
+ /* FILL pCallBacks with hal stuff */
+ pCallBacks->dwSize = sizeof(DDHAL_DDCALLBACKS);
+ pCallBacks->CanCreateSurface = (PDD_CANCREATESURFACE)DdCanCreateSurface;
+ pCallBacks->CreateSurface = (PDD_CREATESURFACE)DdCreateSurface;
+
+ /* Fill in the HAL Callback flags */
+ pCallBacks->dwFlags = DDHAL_CB32_CANCREATESURFACE | DDHAL_CB32_CREATESURFACE;
+ }
+
+ if (pSurfaceCallBacks !=NULL)
+ {
+ memset(pSurfaceCallBacks,0,sizeof(DD_SURFACECALLBACKS));
+
+ /* FILL pSurfaceCallBacks with hal stuff */
+ // pSurfaceCallBacks.dwSize = sizeof(DDHAL_DDSURFACECALLBACKS);
+ // pSurfaceCallBacks.DestroySurface = DdDestroySurface;
+ // pSurfaceCallBacks.Lock = DdLock;
+ // pSurfaceCallBacks.Blt = DdBlt;
+
+ // pSurfaceCallBacks->dwFlags = DDHAL_SURFCB32_DESTROYSURFACE | DDHAL_SURFCB32_LOCK | DDHAL_SURFCB32_BLT ;
+ }
+
+ if (pPaletteCallBacks !=NULL)
+ {
+ memset(pPaletteCallBacks,0,sizeof(DD_PALETTECALLBACKS));
+ /* FILL pPaletteCallBacks with hal stuff */
+ /* We will not support this callback in the framebuf.dll */
+ }
+
+
+ /* Fixme fill the ppdev->dxHalInfo with the info we need */
+ ppdev->bDDInitialized = TRUE;
+ return ppdev->bDDInitialized;
+}
+
+BOOL APIENTRY
+DrvGetDirectDrawInfo(
+ IN DHPDEV dhpdev,
+ OUT DD_HALINFO *pHalInfo,
+ OUT DWORD *pdwNumHeaps,
+ OUT VIDEOMEMORY *pvmList,
+ OUT DWORD *pdwNumFourCCCodes,
+ OUT DWORD *pdwFourCC)
+{
+ PPDEV ppdev = (PPDEV)dhpdev;
+ LONG i;
+ DWORD heap = 1; /* we always alloc one heap */
+ BOOL bDDrawHeap = FALSE;
+
+ if (ppdev == NULL)
+ return FALSE;
+
+ /* check so pHalInfo, pdwNumHeaps, pdwNumFourCCCodes is not NULL
+ pdwFourCC and pvmList can be null
+ */
+
+ if (pHalInfo == NULL)
+ return FALSE;
+
+ if (pdwNumHeaps == NULL)
+ return FALSE;
+
+ if (pdwNumFourCCCodes == NULL)
+ return FALSE;
+
+ /* Setup heap */
+ if ( (ppdev->ScreenWidth < ppdev->MemWidth) || (ppdev->ScreenHeight < ppdev->MemHeight))
+ {
+ bDDrawHeap = TRUE;
+ heap++;
+ }
+
+ ppdev->dwHeap = heap;
+ *pdwNumHeaps = heap;
+
+ /* We do not support other fourcc */
+ *pdwNumFourCCCodes = 0;
+
+
+ /*
+ check see if pvmList and pdwFourCC are frist call
+ or frist. Secon call we fill in pHalInfo info
+ */
+
+ if(!(pvmList && pdwFourCC))
+ {
+
+ RtlZeroMemory(pHalInfo, sizeof(DD_HALINFO));
+ pHalInfo->dwSize = sizeof(DD_HALINFO);
+
+ pHalInfo->ddCaps.dwCaps = DDCAPS_BLT | DDCAPS_BLTQUEUE | DDCAPS_BLTCOLORFILL | DDCAPS_READSCANLINE |
+ DDCAPS_BLTSTRETCH | DDCAPS_COLORKEY | DDCAPS_CANBLTSYSMEM;
+
+ pHalInfo->ddCaps.dwFXCaps = DDFXCAPS_BLTSTRETCHY | DDFXCAPS_BLTSTRETCHX |
+ DDFXCAPS_BLTSTRETCHYN | DDFXCAPS_BLTSTRETCHXN |
+ DDFXCAPS_BLTSHRINKY | DDFXCAPS_BLTSHRINKX |
+ DDFXCAPS_BLTSHRINKYN | DDFXCAPS_BLTSHRINKXN |
+ DDFXCAPS_BLTMIRRORUPDOWN | DDFXCAPS_BLTMIRRORLEFTRIGHT;
+
+ pHalInfo->ddCaps.dwCaps2 = DDCAPS2_NONLOCALVIDMEM | DDCAPS2_NONLOCALVIDMEMCAPS;
+
+ pHalInfo->ddCaps.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP;
+
+ pHalInfo->ddCaps.dwCKeyCaps = DDCKEYCAPS_SRCBLT | DDCKEYCAPS_SRCBLTCLRSPACE;
+
+ pHalInfo->ddCaps.dwSVBCaps = DDCAPS_BLT;
+ pHalInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM;
+
+ /* Calc how much memmory is left on the video cards memmory */
+ pHalInfo->ddCaps.dwVidMemTotal = (ppdev->MemHeight - ppdev->ScreenHeight) * ppdev->ScreenDelta;
+
+ /* fill in some basic info that we need */
+ pHalInfo->vmiData.pvPrimary = ppdev->ScreenPtr;
+ pHalInfo->vmiData.dwDisplayWidth = ppdev->ScreenWidth;
+ pHalInfo->vmiData.dwDisplayHeight = ppdev->ScreenHeight;
+ pHalInfo->vmiData.lDisplayPitch = ppdev->ScreenDelta;
+ pHalInfo->vmiData.ddpfDisplay.dwSize = sizeof(DDPIXELFORMAT);
+ pHalInfo->vmiData.ddpfDisplay.dwFlags = DDPF_RGB;
+ pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount = ppdev->BitsPerPixel;
+ pHalInfo->vmiData.ddpfDisplay.dwRBitMask = ppdev->RedMask;
+ pHalInfo->vmiData.ddpfDisplay.dwGBitMask = ppdev->GreenMask;
+ pHalInfo->vmiData.ddpfDisplay.dwBBitMask = ppdev->BlueMask;
+ pHalInfo->vmiData.dwOffscreenAlign = 4;
+
+ if ( ppdev->BitsPerPixel == 8 )
+ {
+ pHalInfo->vmiData.ddpfDisplay.dwFlags |= DDPF_PALETTEINDEXED8;
+ }
+
+ /* FIXME
+ Config the rops we do not doing that yet
+ for we need write the rops table
+ */
+ for(i=0;i<DD_ROP_SPACE;i++ )
+ {
+ // pHALInfo->ddCaps.dwSVBRops[i] = rops[i];
+ // pHALInfo->ddCaps.dwRops[i] = rops[i];
+ }
+ }
+
+ /* Now build pvmList info */
+ if(pvmList)
+ {
+ ppdev->pvmList = pvmList;
+
++ if (bDDrawHeap)
+ {
+ pvmList->dwFlags = VIDMEM_ISLINEAR ;
+ pvmList->fpStart = ppdev->ScreenHeight * ppdev->ScreenDelta;
+ pvmList->fpEnd = ppdev->MemHeight * ppdev->ScreenDelta - 1;
+ pvmList->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ pvmList++;
+ }
+
+ pvmList->fpStart = 0;
+ pvmList->fpEnd = (ppdev->MemHeight * ppdev->ScreenDelta) - 1;
+ pvmList->dwFlags = VIDMEM_ISNONLOCAL | VIDMEM_ISLINEAR | VIDMEM_ISWC;
+ pvmList->ddsCaps.dwCaps = DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER ;
+ pvmList->ddsCapsAlt.dwCaps = DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER;
+
+ pvmList = ppdev->pvmList;
+ }
+
+ return TRUE;
+}
--- /dev/null
- if (ppdev->PointerAttributes.Enable == TRUE)
+/*
+ * ReactOS Generic Framebuffer display driver
+ *
+ * Copyright (C) 2004 Filip Navara
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "framebuf.h"
+
+#ifndef EXPERIMENTAL_MOUSE_CURSOR_SUPPORT
+
+/*
+ * DrvSetPointerShape
+ *
+ * Sets the new pointer shape.
+ *
+ * Status
+ * @unimplemented
+ */
+
+ULONG APIENTRY
+DrvSetPointerShape(
+ IN SURFOBJ *pso,
+ IN SURFOBJ *psoMask,
+ IN SURFOBJ *psoColor,
+ IN XLATEOBJ *pxlo,
+ IN LONG xHot,
+ IN LONG yHot,
+ IN LONG x,
+ IN LONG y,
+ IN RECTL *prcl,
+ IN FLONG fl)
+{
+/* return SPS_DECLINE;*/
+ return EngSetPointerShape(pso, psoMask, psoColor, pxlo, xHot, yHot, x, y, prcl, fl);
+}
+
+/*
+ * DrvMovePointer
+ *
+ * Moves the pointer to a new position and ensures that GDI does not interfere
+ * with the display of the pointer.
+ *
+ * Status
+ * @unimplemented
+ */
+
+VOID APIENTRY
+DrvMovePointer(
+ IN SURFOBJ *pso,
+ IN LONG x,
+ IN LONG y,
+ IN RECTL *prcl)
+{
+ EngMovePointer(pso, x, y, prcl);
+}
+
+#else
+
+VOID FASTCALL
+IntHideMousePointer(PPDEV ppdev, SURFOBJ *DestSurface)
+{
+ if (ppdev->PointerAttributes.Enable == FALSE)
+ {
+ return;
+ }
+
+ ppdev->PointerAttributes.Enable = FALSE;
+ if (ppdev->PointerSaveSurface != NULL)
+ {
+ RECTL DestRect;
+ POINTL SrcPoint;
+ SURFOBJ *SaveSurface;
+ SURFOBJ *MaskSurface;
+
+ DestRect.left = max(ppdev->PointerAttributes.Column, 0);
+ DestRect.top = max(ppdev->PointerAttributes.Row, 0);
+ DestRect.right = min(
+ ppdev->PointerAttributes.Column + ppdev->PointerAttributes.Width,
+ ppdev->ScreenWidth - 1);
+ DestRect.bottom = min(
+ ppdev->PointerAttributes.Row + ppdev->PointerAttributes.Height,
+ ppdev->ScreenHeight - 1);
+
+ SrcPoint.x = max(-ppdev->PointerAttributes.Column, 0);
+ SrcPoint.y = max(-ppdev->PointerAttributes.Row, 0);
+
+ SaveSurface = EngLockSurface(ppdev->PointerSaveSurface);
+ MaskSurface = EngLockSurface(ppdev->PointerMaskSurface);
+ EngBitBlt(DestSurface, SaveSurface, MaskSurface, NULL, NULL,
+ &DestRect, &SrcPoint, &SrcPoint, NULL, NULL, SRCCOPY);
+ EngUnlockSurface(MaskSurface);
+ EngUnlockSurface(SaveSurface);
+ }
+}
+
+VOID FASTCALL
+IntShowMousePointer(PPDEV ppdev, SURFOBJ *DestSurface)
+{
++ if (ppdev->PointerAttributes.Enable)
+ {
+ return;
+ }
+
+ ppdev->PointerAttributes.Enable = TRUE;
+
+ /*
+ * Copy the pixels under the cursor to temporary surface.
+ */
+
+ if (ppdev->PointerSaveSurface != NULL)
+ {
+ RECTL DestRect;
+ POINTL SrcPoint;
+ SURFOBJ *SaveSurface;
+
+ SrcPoint.x = max(ppdev->PointerAttributes.Column, 0);
+ SrcPoint.y = max(ppdev->PointerAttributes.Row, 0);
+
+ DestRect.left = SrcPoint.x - ppdev->PointerAttributes.Column;
+ DestRect.top = SrcPoint.y - ppdev->PointerAttributes.Row;
+ DestRect.right = min(
+ ppdev->PointerAttributes.Width,
+ ppdev->ScreenWidth - ppdev->PointerAttributes.Column - 1);
+ DestRect.bottom = min(
+ ppdev->PointerAttributes.Height,
+ ppdev->ScreenHeight - ppdev->PointerAttributes.Row - 1);
+
+ SaveSurface = EngLockSurface(ppdev->PointerSaveSurface);
+ EngBitBlt(SaveSurface, DestSurface, NULL, NULL, NULL,
+ &DestRect, &SrcPoint, NULL, NULL, NULL, SRCCOPY);
+ EngUnlockSurface(SaveSurface);
+ }
+
+ /*
+ * Blit the cursor on the screen.
+ */
+
+ {
+ RECTL DestRect;
+ POINTL SrcPoint;
+ SURFOBJ *ColorSurf;
+ SURFOBJ *MaskSurf;
+
+ DestRect.left = max(ppdev->PointerAttributes.Column, 0);
+ DestRect.top = max(ppdev->PointerAttributes.Row, 0);
+ DestRect.right = min(
+ ppdev->PointerAttributes.Column + ppdev->PointerAttributes.Width,
+ ppdev->ScreenWidth - 1);
+ DestRect.bottom = min(
+ ppdev->PointerAttributes.Row + ppdev->PointerAttributes.Height,
+ ppdev->ScreenHeight - 1);
+
+ SrcPoint.x = max(-ppdev->PointerAttributes.Column, 0);
+ SrcPoint.y = max(-ppdev->PointerAttributes.Row, 0);
+
+ MaskSurf = EngLockSurface(ppdev->PointerMaskSurface);
+ if (ppdev->PointerColorSurface != NULL)
+ {
+ ColorSurf = EngLockSurface(ppdev->PointerColorSurface);
+ EngBitBlt(DestSurface, ColorSurf, MaskSurf, NULL, ppdev->PointerXlateObject,
+ &DestRect, &SrcPoint, &SrcPoint, NULL, NULL, 0xAACC);
+ EngUnlockSurface(ColorSurf);
+ }
+ else
+ {
+ /* FIXME */
+ EngBitBlt(DestSurface, MaskSurf, NULL, NULL, ppdev->PointerXlateObject,
+ &DestRect, &SrcPoint, NULL, NULL, NULL, SRCAND);
+ SrcPoint.y += ppdev->PointerAttributes.Height;
+ EngBitBlt(DestSurface, MaskSurf, NULL, NULL, ppdev->PointerXlateObject,
+ &DestRect, &SrcPoint, NULL, NULL, NULL, SRCINVERT);
+ }
+ EngUnlockSurface(MaskSurf);
+ }
+}
+
+/*
+ * DrvSetPointerShape
+ *
+ * Sets the new pointer shape.
+ *
+ * Status
+ * @implemented
+ */
+
+ULONG APIENTRY
+DrvSetPointerShape(
+ IN SURFOBJ *pso,
+ IN SURFOBJ *psoMask,
+ IN SURFOBJ *psoColor,
+ IN XLATEOBJ *pxlo,
+ IN LONG xHot,
+ IN LONG yHot,
+ IN LONG x,
+ IN LONG y,
+ IN RECTL *prcl,
+ IN FLONG fl)
+{
+ PPDEV ppdev = (PPDEV)pso->dhpdev;
+ SURFOBJ *TempSurfObj;
+
+ IntHideMousePointer(ppdev, pso);
+
+ if (ppdev->PointerColorSurface != NULL)
+ {
+ /* FIXME: Is this really needed? */
+ TempSurfObj = EngLockSurface(ppdev->PointerColorSurface);
+ EngFreeMem(TempSurfObj->pvBits);
+ TempSurfObj->pvBits = 0;
+ EngUnlockSurface(TempSurfObj);
+
+ EngDeleteSurface(ppdev->PointerColorSurface);
+ ppdev->PointerMaskSurface = NULL;
+ }
+
+ if (ppdev->PointerMaskSurface != NULL)
+ {
+ /* FIXME: Is this really needed? */
+ TempSurfObj = EngLockSurface(ppdev->PointerMaskSurface);
+ EngFreeMem(TempSurfObj->pvBits);
+ TempSurfObj->pvBits = 0;
+ EngUnlockSurface(TempSurfObj);
+
+ EngDeleteSurface(ppdev->PointerMaskSurface);
+ ppdev->PointerMaskSurface = NULL;
+ }
+
+ if (ppdev->PointerSaveSurface != NULL)
+ {
+ EngDeleteSurface(ppdev->PointerSaveSurface);
+ ppdev->PointerSaveSurface = NULL;
+ }
+
+ /*
+ * See if we are being asked to hide the pointer.
+ */
+
+ if (psoMask == NULL)
+ {
+ return SPS_ACCEPT_EXCLUDE;
+ }
+
+ ppdev->PointerHotSpot.x = xHot;
+ ppdev->PointerHotSpot.y = yHot;
+
+ ppdev->PointerXlateObject = pxlo;
+ ppdev->PointerAttributes.Column = x - xHot;
+ ppdev->PointerAttributes.Row = y - yHot;
+ ppdev->PointerAttributes.Width = psoMask->lDelta << 3;
+ ppdev->PointerAttributes.Height = (psoMask->cjBits / psoMask->lDelta) >> 1;
+
+ if (psoColor != NULL)
+ {
+ SIZEL Size;
+ PBYTE Bits;
+
+ Size.cx = ppdev->PointerAttributes.Width;
+ Size.cy = ppdev->PointerAttributes.Height;
+ Bits = EngAllocMem(0, psoColor->cjBits, ALLOC_TAG);
+ memcpy(Bits, psoColor->pvBits, psoColor->cjBits);
+
+ ppdev->PointerColorSurface = (HSURF)EngCreateBitmap(Size,
+ psoColor->lDelta, psoColor->iBitmapFormat, 0, Bits);
+ }
+ else
+ {
+ ppdev->PointerColorSurface = NULL;
+ }
+
+ if (psoMask != NULL)
+ {
+ SIZEL Size;
+ PBYTE Bits;
+
+ Size.cx = ppdev->PointerAttributes.Width;
+ Size.cy = ppdev->PointerAttributes.Height << 1;
+ Bits = EngAllocMem(0, psoMask->cjBits, ALLOC_TAG);
+ memcpy(Bits, psoMask->pvBits, psoMask->cjBits);
+
+ ppdev->PointerMaskSurface = (HSURF)EngCreateBitmap(Size,
+ psoMask->lDelta, psoMask->iBitmapFormat, 0, Bits);
+ }
+ else
+ {
+ ppdev->PointerMaskSurface = NULL;
+ }
+
+ /*
+ * Create surface for saving the pixels under the cursor.
+ */
+
+ {
+ SIZEL Size;
+ LONG lDelta;
+
+ Size.cx = ppdev->PointerAttributes.Width;
+ Size.cy = ppdev->PointerAttributes.Height;
+
+ switch (pso->iBitmapFormat)
+ {
+ case BMF_8BPP: lDelta = Size.cx; break;
+ case BMF_16BPP: lDelta = Size.cx << 1; break;
+ case BMF_24BPP: lDelta = Size.cx * 3; break;
+ case BMF_32BPP: lDelta = Size.cx << 2; break;
+ }
+
+ ppdev->PointerSaveSurface = (HSURF)EngCreateBitmap(
+ Size, lDelta, pso->iBitmapFormat, BMF_NOZEROINIT, NULL);
+ }
+
+ IntShowMousePointer(ppdev, pso);
+
+ return SPS_ACCEPT_EXCLUDE;
+}
+
+/*
+ * DrvMovePointer
+ *
+ * Moves the pointer to a new position and ensures that GDI does not interfere
+ * with the display of the pointer.
+ *
+ * Status
+ * @implemented
+ */
+
+VOID APIENTRY
+DrvMovePointer(
+ IN SURFOBJ *pso,
+ IN LONG x,
+ IN LONG y,
+ IN RECTL *prcl)
+{
+ PPDEV ppdev = (PPDEV)pso->dhpdev;
+ BOOL WasVisible;
+
+ WasVisible = ppdev->PointerAttributes.Enable;
+ if (WasVisible)
+ {
+ IntHideMousePointer(ppdev, pso);
+ }
+
+ if (x == -1)
+ {
+ return;
+ }
+
+ ppdev->PointerAttributes.Column = x - ppdev->PointerHotSpot.x;
+ ppdev->PointerAttributes.Row = y - ppdev->PointerHotSpot.y;
+
+ if (WasVisible)
+ {
+ IntShowMousePointer(ppdev, pso);
+ }
+}
+
+#endif
--- /dev/null
- if (ppdev->bDDInitialized == TRUE)
+/*
+ * ReactOS Generic Framebuffer display driver directdraw interface
+ *
+ * Copyright (C) 2006 Magnus Olsen
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "framebuf.h"
+
+VOID APIENTRY
+DrvDisableDirectDraw( IN DHPDEV dhpdev)
+{
+ PPDEV ppdev = (PPDEV)dhpdev;
+ ppdev->bDDInitialized = FALSE;
+ /* Add Clean up code here if we need it
+ when we shout down directx interface */
+}
+
+BOOL APIENTRY
+DrvEnableDirectDraw(
+ IN DHPDEV dhpdev,
+ OUT DD_CALLBACKS *pCallBacks,
+ OUT DD_SURFACECALLBACKS *pSurfaceCallBacks,
+ OUT DD_PALETTECALLBACKS *pPaletteCallBacks)
+{
+ PPDEV ppdev = (PPDEV)dhpdev;
+
- if ( bDDrawHeap == TRUE)
++ if (ppdev->bDDInitialized)
+ {
+ return TRUE;
+ }
+
+ /* Setup pixel format */
+ ppdev->ddpfDisplay.dwSize = sizeof( DDPIXELFORMAT );
+ ppdev->ddpfDisplay.dwFourCC = 0;
+
+ ppdev->ddpfDisplay.dwRBitMask = ppdev->RedMask;
+ ppdev->ddpfDisplay.dwGBitMask = ppdev->GreenMask;
+ ppdev->ddpfDisplay.dwBBitMask = ppdev->BlueMask;
+
+ ppdev->ddpfDisplay.dwRGBBitCount=ppdev->BitsPerPixel;
+ ppdev->ddpfDisplay.dwRGBAlphaBitMask = 0;
+ ppdev->ddpfDisplay.dwFlags = DDPF_RGB;
+
+ ppdev->pvmList = NULL;
+
+ switch(ppdev->iDitherFormat)
+ {
+ case BMF_8BPP:
+ ppdev->ddpfDisplay.dwFlags |= DDPF_PALETTEINDEXED8;
+ break;
+
+ case BMF_16BPP:
+ switch(ppdev->RedMask)
+ {
+ case 0x7C00:
+ ppdev->ddpfDisplay.dwRGBAlphaBitMask = 0x8000;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case BMF_24BPP:
+ break;
+
+ case BMF_32BPP:
+ ppdev->ddpfDisplay.dwRGBAlphaBitMask = 0xff000000;
+ break;
+
+ default:
+ /* FIXME unknown pixel bits */
+ ppdev->ddpfDisplay.dwRGBBitCount=0;
+ break;
+ }
+
+ if (pCallBacks !=NULL)
+ {
+ memset(pCallBacks,0,sizeof(DD_CALLBACKS));
+
+ /* FILL pCallBacks with hal stuff */
+ pCallBacks->dwSize = sizeof(DDHAL_DDCALLBACKS);
+ pCallBacks->CanCreateSurface = (PDD_CANCREATESURFACE)DdCanCreateSurface;
+ pCallBacks->CreateSurface = (PDD_CREATESURFACE)DdCreateSurface;
+
+ /* Fill in the HAL Callback flags */
+ pCallBacks->dwFlags = DDHAL_CB32_CANCREATESURFACE | DDHAL_CB32_CREATESURFACE;
+ }
+
+ if (pSurfaceCallBacks !=NULL)
+ {
+ memset(pSurfaceCallBacks,0,sizeof(DD_SURFACECALLBACKS));
+
+ /* FILL pSurfaceCallBacks with hal stuff */
+ // pSurfaceCallBacks.dwSize = sizeof(DDHAL_DDSURFACECALLBACKS);
+ // pSurfaceCallBacks.DestroySurface = DdDestroySurface;
+ // pSurfaceCallBacks.Lock = DdLock;
+ // pSurfaceCallBacks.Blt = DdBlt;
+
+ // pSurfaceCallBacks->dwFlags = DDHAL_SURFCB32_DESTROYSURFACE | DDHAL_SURFCB32_LOCK | DDHAL_SURFCB32_BLT ;
+ }
+
+ if (pPaletteCallBacks !=NULL)
+ {
+ memset(pPaletteCallBacks,0,sizeof(DD_PALETTECALLBACKS));
+ /* FILL pPaletteCallBacks with hal stuff */
+ /* We will not support this callback in the framebuf.dll */
+ }
+
+
+ /* Fixme fill the ppdev->dxHalInfo with the info we need */
+ ppdev->bDDInitialized = TRUE;
+ return ppdev->bDDInitialized;
+}
+
+BOOL APIENTRY
+DrvGetDirectDrawInfo(
+ IN DHPDEV dhpdev,
+ OUT DD_HALINFO *pHalInfo,
+ OUT DWORD *pdwNumHeaps,
+ OUT VIDEOMEMORY *pvmList,
+ OUT DWORD *pdwNumFourCCCodes,
+ OUT DWORD *pdwFourCC)
+{
+ PPDEV ppdev = (PPDEV)dhpdev;
+ LONG i;
+ DWORD heap = 1; /* we always alloc one heap */
+ BOOL bDDrawHeap = FALSE;
+
+ if (ppdev == NULL)
+ return FALSE;
+
+ /* check so pHalInfo, pdwNumHeaps, pdwNumFourCCCodes is not NULL
+ pdwFourCC and pvmList can be null
+ */
+
+ if (pHalInfo == NULL)
+ return FALSE;
+
+ if (pdwNumHeaps == NULL)
+ return FALSE;
+
+ if (pdwNumFourCCCodes == NULL)
+ return FALSE;
+
+ /* Setup heap */
+ if ( (ppdev->ScreenWidth < ppdev->MemWidth) || (ppdev->ScreenHeight < ppdev->MemHeight))
+ {
+ bDDrawHeap = TRUE;
+ heap++;
+ }
+
+ ppdev->dwHeap = heap;
+ *pdwNumHeaps = heap;
+
+ /* We do not support other fourcc */
+ *pdwNumFourCCCodes = 0;
+
+
+ /*
+ check see if pvmList and pdwFourCC are frist call
+ or frist. Secon call we fill in pHalInfo info
+ */
+
+ if(!(pvmList && pdwFourCC))
+ {
+
+ RtlZeroMemory(pHalInfo, sizeof(DD_HALINFO));
+ pHalInfo->dwSize = sizeof(DD_HALINFO);
+
+ pHalInfo->ddCaps.dwCaps = DDCAPS_BLT | DDCAPS_BLTQUEUE | DDCAPS_BLTCOLORFILL | DDCAPS_READSCANLINE |
+ DDCAPS_BLTSTRETCH | DDCAPS_COLORKEY | DDCAPS_CANBLTSYSMEM;
+
+ pHalInfo->ddCaps.dwFXCaps = DDFXCAPS_BLTSTRETCHY | DDFXCAPS_BLTSTRETCHX |
+ DDFXCAPS_BLTSTRETCHYN | DDFXCAPS_BLTSTRETCHXN |
+ DDFXCAPS_BLTSHRINKY | DDFXCAPS_BLTSHRINKX |
+ DDFXCAPS_BLTSHRINKYN | DDFXCAPS_BLTSHRINKXN |
+ DDFXCAPS_BLTMIRRORUPDOWN | DDFXCAPS_BLTMIRRORLEFTRIGHT;
+
+ pHalInfo->ddCaps.dwCaps2 = DDCAPS2_NONLOCALVIDMEM | DDCAPS2_NONLOCALVIDMEMCAPS;
+
+ pHalInfo->ddCaps.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP;
+
+ pHalInfo->ddCaps.dwCKeyCaps = DDCKEYCAPS_SRCBLT | DDCKEYCAPS_SRCBLTCLRSPACE;
+
+ pHalInfo->ddCaps.dwSVBCaps = DDCAPS_BLT;
+ pHalInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM;
+
+ /* Calc how much memmory is left on the video cards memmory */
+ pHalInfo->ddCaps.dwVidMemTotal = (ppdev->MemHeight - ppdev->ScreenHeight) * ppdev->ScreenDelta;
+
+ /* fill in some basic info that we need */
+ pHalInfo->vmiData.pvPrimary = ppdev->ScreenPtr;
+ pHalInfo->vmiData.dwDisplayWidth = ppdev->ScreenWidth;
+ pHalInfo->vmiData.dwDisplayHeight = ppdev->ScreenHeight;
+ pHalInfo->vmiData.lDisplayPitch = ppdev->ScreenDelta;
+ pHalInfo->vmiData.ddpfDisplay.dwSize = sizeof(DDPIXELFORMAT);
+ pHalInfo->vmiData.ddpfDisplay.dwFlags = DDPF_RGB;
+ pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount = ppdev->BitsPerPixel;
+ pHalInfo->vmiData.ddpfDisplay.dwRBitMask = ppdev->RedMask;
+ pHalInfo->vmiData.ddpfDisplay.dwGBitMask = ppdev->GreenMask;
+ pHalInfo->vmiData.ddpfDisplay.dwBBitMask = ppdev->BlueMask;
+ pHalInfo->vmiData.dwOffscreenAlign = 4;
+
+ if ( ppdev->BitsPerPixel == 8 )
+ {
+ pHalInfo->vmiData.ddpfDisplay.dwFlags |= DDPF_PALETTEINDEXED8;
+ }
+
+ /* FIXME
+ Config the rops we do not doing that yet
+ for we need write the rops table
+ */
+ for(i=0;i<DD_ROP_SPACE;i++ )
+ {
+ // pHALInfo->ddCaps.dwSVBRops[i] = rops[i];
+ // pHALInfo->ddCaps.dwRops[i] = rops[i];
+ }
+ }
+
+ /* Now build pvmList info */
+ if(pvmList)
+ {
+ ppdev->pvmList = pvmList;
+
++ if (bDDrawHeap)
+ {
+ pvmList->dwFlags = VIDMEM_ISLINEAR ;
+ pvmList->fpStart = ppdev->ScreenHeight * ppdev->ScreenDelta;
+ pvmList->fpEnd = ppdev->MemHeight * ppdev->ScreenDelta - 1;
+ pvmList->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ pvmList++;
+ }
+
+ pvmList->fpStart = 0;
+ pvmList->fpEnd = (ppdev->MemHeight * ppdev->ScreenDelta) - 1;
+ pvmList->dwFlags = VIDMEM_ISNONLOCAL | VIDMEM_ISLINEAR | VIDMEM_ISWC;
+ pvmList->ddsCaps.dwCaps = DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER ;
+ pvmList->ddsCapsAlt.dwCaps = DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER;
+
+ pvmList = ppdev->pvmList;
+ }
+
+ return TRUE;
+}
+
--- /dev/null
- if(Enable==TRUE)
+/*
+ * PROJECT: ReactOS VGA display driver
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: drivers/video/displays/vga/main/enable.c
+ * PURPOSE:
+ * PROGRAMMERS:
+ */
+
+#include <vgaddi.h>
+
+static BOOL VGAInitialized = FALSE;
+
+static DRVFN FuncList[] =
+{
+ /* Required Display driver fuctions */
+ {INDEX_DrvAssertMode, (PFN) DrvAssertMode},
+ {INDEX_DrvCompletePDEV, (PFN) DrvCompletePDEV},
+ {INDEX_DrvCopyBits, (PFN) DrvCopyBits},
+ {INDEX_DrvDisablePDEV, (PFN) DrvDisablePDEV},
+ {INDEX_DrvDisableSurface, (PFN) DrvDisableSurface},
+ {INDEX_DrvEnablePDEV, (PFN) DrvEnablePDEV},
+ {INDEX_DrvEnableSurface, (PFN) DrvEnableSurface},
+ {INDEX_DrvGetModes, (PFN) DrvGetModes},
+ {INDEX_DrvLineTo, (PFN) DrvLineTo},
+ {INDEX_DrvPaint, (PFN) DrvPaint},
+ {INDEX_DrvBitBlt, (PFN) DrvBitBlt},
+ {INDEX_DrvTransparentBlt, (PFN) DrvTransparentBlt},
+ {INDEX_DrvMovePointer, (PFN) DrvMovePointer},
+ {INDEX_DrvSetPointerShape, (PFN) DrvSetPointerShape},
+
+#if 0
+ /* Optional Display driver functions */
+ {INDEX_, },
+ {INDEX_DescribePixelFormat, (PFN) VGADDIDescribePixelFormat},
+ {INDEX_DrvDitherColor, (PFN) VGADDIDitherColor},
+ {INDEX_DrvFillPath, (PFN) VGADDIFillPath},
+ {INDEX_DrvGetTrueTypeFile, (PFN) VGADDIGetTrueTypeFile},
+ {INDEX_DrvLoadFontFile, (PFN) VGADDILoadFontFile},
+ {INDEX_DrvQueryFont, (PFN) VGADDIQueryFont},
+ {INDEX_DrvQueryFontCaps, (PFN) VGADDIQueryFontCaps},
+ {INDEX_DrvQueryFontData, (PFN) VGADDIQueryFontData},
+ {INDEX_DrvQueryFontFile, (PFN) VGADDIQueryFontFile},
+ {INDEX_DrvQueryFontTree, (PFN) VGADDIQueryFontTree},
+ {INDEX_DrvQueryTrueTypeOutline, (PFN) VGADDIQueryTrueTypeOutline},
+ {INDEX_DrvQueryTrueTypeTable, (PFN) VGADDIQueryTrueTypeTable},
+ {INDEX_DrvRealizeBrush, (PFN) VGADDIRealizeBrush},
+ {INDEX_DrvResetPDEV, (PFN) VGADDIResetPDEV},
+ {INDEX_DrvSetPalette, (PFN) VGADDISetPalette},
+ {INDEX_DrvSetPixelFormat, (PFN) VGADDISetPixelFormat},
+ {INDEX_DrvStretchBlt, (PFN) VGADDIStretchBlt},
+ {INDEX_DrvStrokePath, (PFN) VGADDIStrokePath},
+ {INDEX_DrvSwapBuffers, (PFN) VGADDISwapBuffers},
+ {INDEX_DrvTextOut, (PFN) VGADDITextOut},
+ {INDEX_DrvUnloadFontFile, (PFN) VGADDIUnloadFontFile},
+#endif
+};
+
+static GDIINFO gaulCap = {
+ GDI_DRIVER_VERSION, // ulVersion
+ DT_RASDISPLAY, // ulTechnology
+ 0, // ulHorzSize
+ 0, // ulVertSize
+ 0, // ulHorzRes (filled in at initialization)
+ 0, // ulVertRes (filled in at initialization)
+ 4, // cBitsPixel
+ 1, // cPlanes
+ 16, // ulNumColors
+ 0, // flRaster (DDI reserved field)
+
+ 96, // ulLogPixelsX (must be set to 96 according to MSDN)
+ 96, // ulLogPixelsY (must be set to 96 according to MSDN)
+
+ TC_RA_ABLE | TC_SCROLLBLT, // flTextCaps
+
+ 6, // ulDACRed
+ 6, // ulDACGreen
+ 6, // ulDACBlue
+
+ 0x0024, // ulAspectX (one-to-one aspect ratio)
+ 0x0024, // ulAspectY
+ 0x0033, // ulAspectXY
+
+ 1, // xStyleStep
+ 1, // yStyleSte;
+ 3, // denStyleStep
+
+ { 0, 0 }, // ptlPhysOffset
+ { 0, 0 }, // szlPhysSize
+
+ 0, // ulNumPalReg (win3.1 16 color drivers say 0 too)
+
+// These fields are for halftone initialization.
+
+ { // ciDevice, ColorInfo
+ { 6700, 3300, 0 }, // Red
+ { 2100, 7100, 0 }, // Green
+ { 1400, 800, 0 }, // Blue
+ { 1750, 3950, 0 }, // Cyan
+ { 4050, 2050, 0 }, // Magenta
+ { 4400, 5200, 0 }, // Yellow
+ { 3127, 3290, 0 }, // AlignmentWhite
+ 20000, // RedGamma
+ 20000, // GreenGamma
+ 20000, // BlueGamma
+ 0, 0, 0, 0, 0, 0
+ },
+
+ 0, // ulDevicePelsDPI
+ PRIMARY_ORDER_CBA, // ulPrimaryOrder
+ HT_PATSIZE_4x4_M, // ulHTPatternSize
+ HT_FORMAT_4BPP_IRGB, // ulHTOutputFormat
+ HT_FLAG_ADDITIVE_PRIMS, // flHTFlags
+
+ 0, // ulVRefresh
+ 8, // ulBltAlignment
+ 0, // ulPanningHorzRes
+ 0, // ulPanningVertRes
+
+ 0, // xPanningAlignment
+ 0, // yPanningAlignment
+ 0, // cxHTPat
+ 0, // cyHTPat
+ NULL, // pHTPatA
+ NULL, // pHTPatB
+ NULL, // pHTPatC
+ 0, // flShadeBlend
+ 0, // ulPhysicalPixelCharacteristics
+ 0 // ulPhysicalPixelGamma
+};
+
+// Palette for VGA
+
+typedef struct _VGALOGPALETTE
+{
+ USHORT ident;
+ USHORT NumEntries;
+ PALETTEENTRY PaletteEntry[16];
+} VGALOGPALETTE;
+
+const VGALOGPALETTE VGApalette =
+{
+
+ 0x400, // driver version
+ 16, // num entries
+ {
+ { 0x00, 0x00, 0x00, 0x00 }, // 0
+ { 0x80, 0x00, 0x00, 0x00 }, // 1
+ { 0x00, 0x80, 0x00, 0x00 }, // 2
+ { 0x80, 0x80, 0x00, 0x00 }, // 3
+ { 0x00, 0x00, 0x80, 0x00 }, // 4
+ { 0x80, 0x00, 0x80, 0x00 }, // 5
+ { 0x00, 0x80, 0x80, 0x00 }, // 6
+ { 0x80, 0x80, 0x80, 0x00 }, // 7
+ { 0xc0, 0xc0, 0xc0, 0x00 }, // 8
+ { 0xff, 0x00, 0x00, 0x00 }, // 9
+ { 0x00, 0xff, 0x00, 0x00 }, // 10
+ { 0xff, 0xff, 0x00, 0x00 }, // 11
+ { 0x00, 0x00, 0xff, 0x00 }, // 12
+ { 0xff, 0x00, 0xff, 0x00 }, // 13
+ { 0x00, 0xff, 0xff, 0x00 }, // 14
+ { 0xff, 0xff, 0xff, 0x00 } // 15
+ }
+};
+
+// Devinfo structure passed back to the engine in DrvEnablePDEV
+
+#define SYSTM_LOGFONT {16,7,0,0,700,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,VARIABLE_PITCH | FF_DONTCARE, L"System"}
+#define HELVE_LOGFONT {12,9,0,0,400,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_STROKE_PRECIS,PROOF_QUALITY,VARIABLE_PITCH | FF_DONTCARE, L"MS Sans Serif"}
+#define COURI_LOGFONT {12,9,0,0,400,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_STROKE_PRECIS,PROOF_QUALITY,FIXED_PITCH | FF_DONTCARE, L"Courier"}
+
+DEVINFO devinfoVGA =
+{
+ (GCAPS_OPAQUERECT | GCAPS_HORIZSTRIKE | GCAPS_ALTERNATEFILL | GCAPS_MONO_DITHER | GCAPS_COLOR_DITHER |
+ GCAPS_WINDINGFILL | GCAPS_DITHERONREALIZE
+ ), // Graphics capabilities
+
+ SYSTM_LOGFONT, // Default font description
+ HELVE_LOGFONT, // ANSI variable font description
+ COURI_LOGFONT, // ANSI fixed font description
+ 0, // Count of device fonts
+ BMF_4BPP, // preferred DIB format
+ 8, // Width of color dither
+ 8, // Height of color dither
+ NULL, // Default palette to use for this device
+ 0 // flGraphicsCaps2
+};
+
+BOOL APIENTRY
+DrvEnableDriver(IN ULONG EngineVersion,
+ IN ULONG SizeOfDED,
+ OUT PDRVENABLEDATA DriveEnableData)
+{
+ DPRINT("DrvEnableDriver called...\n");
+
+ vgaPreCalc();
+
+ VGADDI_InitializeOffScreenMem((SCREEN_X * SCREEN_Y) >> 3, 65536 - ((SCREEN_X * SCREEN_Y) >> 3));
+
+ DriveEnableData->pdrvfn = FuncList;
+ DriveEnableData->c = sizeof(FuncList) / sizeof(DRVFN);
+ DriveEnableData->iDriverVersion = DDI_DRIVER_VERSION_NT4;
+
+ return TRUE;
+}
+
+// DrvDisableDriver
+// DESCRIPTION:
+// This function is called by the KMGDI at exit. It should cleanup.
+// ARGUMENTS:
+// NONE
+// RETURNS:
+// NONE
+
+VOID APIENTRY
+DrvDisableDriver(VOID)
+{
+ return;
+}
+
+// ----------------------------------------------- Driver Implementation
+
+
+// DrvEnablePDEV
+// DESCRIPTION:
+// This function is called after DrvEnableDriver to get information
+// about the mode that is to be used. This function just returns
+// information, and should not yet initialize the mode.
+// ARGUMENTS:
+// IN DEVMODEW * DM Describes the mode requested
+// IN LPWSTR LogAddress
+// IN ULONG PatternCount number of patterns expected
+// OUT HSURF * SurfPatterns array to contain pattern handles
+// IN ULONG GDIInfoSize the size of the GDIInfo object passed in
+// OUT ULONG * GDIInfo GDI Info object
+// IN ULONG DevInfoSize the size of the DevInfo object passed in
+// OUT ULONG * DevInfo Device Info object
+// IN LPWSTR DevDataFile ignore
+// IN LPWSTR DeviceName Device name
+// IN HANDLE Driver handle to KM driver
+// RETURNS:
+// DHPDEV a handle to a DPev object
+
+DHPDEV APIENTRY
+DrvEnablePDEV(IN DEVMODEW *DM,
+ IN LPWSTR LogAddress,
+ IN ULONG PatternCount,
+ OUT HSURF *SurfPatterns,
+ IN ULONG GDIInfoSize,
+ OUT ULONG *GDIInfo,
+ IN ULONG DevInfoSize,
+ OUT DEVINFO *DevInfo,
+ IN HDEV Dev,
+ IN LPWSTR DeviceName,
+ IN HANDLE Driver)
+{
+ PPDEV PDev;
+
+ PDev = EngAllocMem(FL_ZERO_MEMORY, sizeof(PDEV), ALLOC_TAG);
+ if (PDev == NULL)
+ {
+ DPRINT1("EngAllocMem failed for PDEV\n");
+ return NULL;
+ }
+ PDev->KMDriver = Driver;
+ DPRINT( "PDev: %x, Driver: %x\n", PDev, PDev->KMDriver );
+
+ gaulCap.ulHorzRes = SCREEN_X;
+ gaulCap.ulVertRes = SCREEN_Y;
+ if (sizeof(GDIINFO) < GDIInfoSize)
+ GDIInfoSize = sizeof(GDIINFO);
+ memcpy(GDIInfo, &gaulCap, GDIInfoSize);
+ DM->dmBitsPerPel = gaulCap.cBitsPixel * gaulCap.cPlanes;
+ DM->dmPelsWidth = gaulCap.ulHorzRes;
+ DM->dmPelsHeight = gaulCap.ulVertRes;
+
+ devinfoVGA.hpalDefault = EngCreatePalette(PAL_INDEXED, 16, (ULONG *) VGApalette.PaletteEntry, 0, 0, 0);
+ if (sizeof(DEVINFO) < DevInfoSize)
+ DevInfoSize = sizeof(DEVINFO);
+ memcpy(DevInfo, &devinfoVGA, DevInfoSize);
+
+ return (DHPDEV) PDev;
+}
+
+
+// DrvCompletePDEV
+// DESCRIPTION
+// Called after initialization of PDEV is complete. Supplies
+// a reference to the GDI handle for the PDEV.
+
+VOID APIENTRY
+DrvCompletePDEV(IN DHPDEV PDev,
+ IN HDEV Dev)
+{
+ ((PPDEV) PDev)->GDIDevHandle = Dev; // Handle to the DC
+}
+
+
+BOOL APIENTRY
+DrvAssertMode(IN DHPDEV DPev,
+ IN BOOL Enable)
+{
+ PPDEV ppdev = (PPDEV)DPev;
+ ULONG returnedDataLength;
+
++ if (Enable)
+ {
+ /* Reenable our graphics mode */
+ if (!InitPointer(ppdev))
+ {
+ /* Failed to set pointer */
+ return FALSE;
+ }
+
+ if (!VGAInitialized)
+ {
+ if (!InitVGA(ppdev, FALSE))
+ {
+ /* Failed to initialize the VGA */
+ return FALSE;
+ }
+ VGAInitialized = TRUE;
+ }
+ }
+ else
+ {
+ /* Go back to last known mode */
+ DPRINT( "ppdev: %x, KMDriver: %x", ppdev, ppdev->KMDriver );
+ if (EngDeviceIoControl(ppdev->KMDriver, IOCTL_VIDEO_RESET_DEVICE, NULL, 0, NULL, 0, &returnedDataLength))
+ {
+ /* Failed to go back to mode */
+ return FALSE;
+ }
+ VGAInitialized = FALSE;
+ }
+ return TRUE;
+}
+
+
+VOID APIENTRY
+DrvDisablePDEV(IN DHPDEV PDev)
+{
+ PPDEV ppdev = (PPDEV)PDev;
+
+ /* EngDeletePalette(devinfoVGA.hpalDefault); */
+ if (ppdev->pjPreallocSSBBuffer)
+ EngFreeMem(ppdev->pjPreallocSSBBuffer);
+
+ if (ppdev->pucDIB4ToVGAConvBuffer)
+ EngFreeMem(ppdev->pucDIB4ToVGAConvBuffer);
+
+ DPRINT("Freeing PDEV\n");
+ EngFreeMem(PDev);
+}
+
+
+VOID APIENTRY
+DrvDisableSurface(IN DHPDEV PDev)
+{
+ PPDEV ppdev = (PPDEV)PDev;
+ PDEVSURF pdsurf = ppdev->AssociatedSurf;
+
+ DPRINT("KMDriver: %x\n", ppdev->KMDriver);
+ DeinitVGA(ppdev);
+ /* EngFreeMem(pdsurf->BankSelectInfo); */
+
+ if (pdsurf->BankInfo != NULL)
+ EngFreeMem(pdsurf->BankInfo);
+ if (pdsurf->BankInfo2RW != NULL)
+ EngFreeMem(pdsurf->BankInfo2RW);
+ if (pdsurf->BankBufferPlane0 != NULL)
+ EngFreeMem(pdsurf->BankBufferPlane0);
+ if (ppdev->pPointerAttributes != NULL)
+ EngFreeMem(ppdev->pPointerAttributes);
+
+ /* free any pending saved screen bit blocks */
+#if 0
+ pSSB = pdsurf->ssbList;
+ while (pSSB != (PSAVED_SCREEN_BITS) NULL)
+ {
+ /* Point to the next saved screen bits block */
+ pSSBNext = (PSAVED_SCREEN_BITS) pSSB->pvNextSSB;
+
+ /* Free the current block */
+ EngFreeMem(pSSB);
+ pSSB = pSSBNext;
+ }
+#endif
+ EngDeleteSurface((HSURF) ppdev->SurfHandle);
+ /* EngFreeMem(pdsurf); */ /* free the surface */
+}
+
+
+static VOID
+InitSavedBits(IN PPDEV ppdev)
+{
+ if (!(ppdev->fl & DRIVER_OFFSCREEN_REFRESHED))
+ return;
+
+ /* set up rect to right of visible screen */
+ ppdev->SavedBitsRight.left = ppdev->sizeSurf.cx;
+ ppdev->SavedBitsRight.top = 0;
+ ppdev->SavedBitsRight.right = ppdev->sizeMem.cx - PLANAR_PELS_PER_CPU_ADDRESS;
+ ppdev->SavedBitsRight.bottom = ppdev->sizeSurf.cy;
+
+ if ((ppdev->SavedBitsRight.right <= ppdev->SavedBitsRight.left) ||
+ (ppdev->SavedBitsRight.bottom <= ppdev->SavedBitsRight.top))
+ {
+ ppdev->SavedBitsRight.left = 0;
+ ppdev->SavedBitsRight.top = 0;
+ ppdev->SavedBitsRight.right = 0;
+ ppdev->SavedBitsRight.bottom = 0;
+ }
+
+ /* set up rect below visible screen */
+ ppdev->SavedBitsBottom.left = 0;
+ ppdev->SavedBitsBottom.top = ppdev->sizeSurf.cy;
+ ppdev->SavedBitsBottom.right = ppdev->sizeMem.cx - PLANAR_PELS_PER_CPU_ADDRESS;
+ ppdev->SavedBitsBottom.bottom = ppdev->sizeMem.cy - ppdev->NumScansUsedByPointer;
+
+ if ((ppdev->SavedBitsBottom.right <= ppdev->SavedBitsBottom.left) ||
+ (ppdev->SavedBitsBottom.bottom <= ppdev->SavedBitsBottom.top))
+ {
+ ppdev->SavedBitsBottom.left = 0;
+ ppdev->SavedBitsBottom.top = 0;
+ ppdev->SavedBitsBottom.right = 0;
+ ppdev->SavedBitsBottom.bottom = 0;
+ }
+
+ ppdev->BitsSaved = FALSE;
+}
+
+
+HSURF APIENTRY
+DrvEnableSurface(IN DHPDEV PDev)
+{
+ PPDEV ppdev = (PPDEV)PDev;
+ PDEVSURF pdsurf;
+ DHSURF dhsurf;
+ HSURF hsurf;
+
+ DPRINT("DrvEnableSurface() called\n");
+
+ /* Initialize the VGA */
+ if (!VGAInitialized)
+ {
+ if (!InitVGA(ppdev, TRUE))
+ goto error_done;
+ VGAInitialized = TRUE;
+ }
+
+ /* dhsurf is of type DEVSURF, which is the drivers specialized surface type */
+ dhsurf = (DHSURF)EngAllocMem(0, sizeof(DEVSURF), ALLOC_TAG);
+ if (dhsurf == (DHSURF) 0)
+ goto error_done;
+
+ pdsurf = (PDEVSURF) dhsurf;
+ pdsurf->ident = DEVSURF_IDENT;
+ pdsurf->flSurf = 0;
+ pdsurf->Format = BMF_PHYSDEVICE;
+ pdsurf->jReserved1 = 0;
+ pdsurf->jReserved2 = 0;
+ pdsurf->ppdev = ppdev;
+ pdsurf->sizeSurf.cx = ppdev->sizeSurf.cx;
+ pdsurf->sizeSurf.cy = ppdev->sizeSurf.cy;
+ pdsurf->NextPlane = 0;
+ pdsurf->Scan0 = ppdev->fbScreen;
+ pdsurf->BitmapStart = ppdev->fbScreen;
+ pdsurf->StartBmp = ppdev->fbScreen;
+ pdsurf->BankInfo = NULL;
+ pdsurf->BankInfo2RW = NULL;
+ pdsurf->BankBufferPlane0 = NULL;
+
+/* pdsurf->Conv = &ConvertBuffer[0]; */
+
+ if (!InitPointer(ppdev))
+ {
+ DPRINT1("DrvEnablePDEV failed bInitPointer\n");
+ goto error_clean;
+ }
+
+/* if (!SetUpBanking(pdsurf, ppdev))
+ {
+ DPRINT1("DrvEnablePDEV failed SetUpBanking\n");
+ goto error_clean;
+ } BANKING CODE UNIMPLEMENTED */
+
+ if ((hsurf = EngCreateDeviceSurface(dhsurf, ppdev->sizeSurf, BMF_4BPP)) ==
+ (HSURF)0)
+ {
+ /* Call to EngCreateDeviceSurface failed */
+ DPRINT("EngCreateDeviceSurface call failed\n");
+ goto error_clean;
+ }
+
+ InitSavedBits(ppdev);
+
+ if (EngAssociateSurface(hsurf, ppdev->GDIDevHandle, HOOK_BITBLT | HOOK_PAINT | HOOK_LINETO | HOOK_COPYBITS |
+ HOOK_TRANSPARENTBLT))
+ {
+ DPRINT("Successfully associated surface\n");
+ ppdev->SurfHandle = hsurf;
+ ppdev->AssociatedSurf = pdsurf;
+
+ /* Set up an empty saved screen block list */
+ pdsurf->ssbList = NULL;
+
+ return hsurf;
+ }
+ DPRINT("EngAssociateSurface() failed\n");
+ EngDeleteSurface(hsurf);
+
+error_clean:
+ EngFreeMem(dhsurf);
+
+error_done:
+ return (HSURF)0;
+}
+
+
+ULONG APIENTRY
+DrvGetModes(IN HANDLE Driver,
+ IN ULONG DataSize,
+ OUT PDEVMODEW DM)
+{
+ DWORD NumModes;
+ DWORD ModeSize;
+ DWORD OutputSize;
+ DWORD OutputModes = DataSize / (sizeof(DEVMODEW) + DRIVER_EXTRA_SIZE);
+ PVIDEO_MODE_INFORMATION VideoModeInformation, VideoTemp;
+
+ NumModes = getAvailableModes(Driver,
+ (PVIDEO_MODE_INFORMATION *) &VideoModeInformation,
+ &ModeSize);
+
+ if (NumModes == 0)
+ return 0;
+
+ if (DM == NULL)
+ {
+ OutputSize = NumModes * (sizeof(DEVMODEW) + DRIVER_EXTRA_SIZE);
+ }
+ else
+ {
+ OutputSize=0;
+ VideoTemp = VideoModeInformation;
+
+ do
+ {
+ if (VideoTemp->Length != 0)
+ {
+ if (OutputModes == 0)
+ break;
+
+ memset(DM, 0, sizeof(DEVMODEW));
+ memcpy(DM->dmDeviceName, DLL_NAME, sizeof(DLL_NAME));
+
+ DM->dmSpecVersion = DM_SPECVERSION;
+ DM->dmDriverVersion = DM_SPECVERSION;
+ DM->dmSize = sizeof(DEVMODEW);
+ DM->dmDriverExtra = DRIVER_EXTRA_SIZE;
+ DM->dmBitsPerPel = VideoTemp->NumberOfPlanes *
+ VideoTemp->BitsPerPlane;
+ DM->dmPelsWidth = VideoTemp->VisScreenWidth;
+ DM->dmPelsHeight = VideoTemp->VisScreenHeight;
+ DM->dmDisplayFrequency = VideoTemp->Frequency;
+ DM->dmDisplayFlags = 0;
+
+ DM->dmFields = DM_BITSPERPEL |
+ DM_PELSWIDTH |
+ DM_PELSHEIGHT |
+ DM_DISPLAYFREQUENCY |
+ DM_DISPLAYFLAGS ;
+
+ /* next DEVMODE entry */
+ OutputModes--;
+
+ DM = (PDEVMODEW) ( ((ULONG_PTR)DM) + sizeof(DEVMODEW) + DRIVER_EXTRA_SIZE);
+
+ OutputSize += (sizeof(DEVMODEW) + DRIVER_EXTRA_SIZE);
+ }
+
+ VideoTemp = (PVIDEO_MODE_INFORMATION)(((PUCHAR)VideoTemp) + ModeSize);
+
+ } while (--NumModes);
+ }
+ return OutputSize;
+}
+
+ULONG DbgPrint(PCCH Format,...)
+{
+ va_list ap;
+ va_start(ap, Format);
+ EngDebugPrint("VGADDI", (PCHAR)Format, ap);
+ va_end(ap);
+ return 0;
+}
+
+/* EOF */
--- /dev/null
- if (edgePixel == TRUE)
+/*
+ * PROJECT: ReactOS VGA display driver
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: drivers/video/displays/vga/vgavideo/vgavideo.c
+ * PURPOSE:
+ * PROGRAMMERS:
+ */
+
+#include <vgaddi.h>
+
+UCHAR PreCalcReverseByte[256];
+int maskbit[640];
+int y80[480];
+int xconv[640];
+int bit8[640];
+int startmasks[8];
+int endmasks[8];
+PBYTE vidmem;
+static ULONG UnpackPixel[256];
+
+static unsigned char leftMask;
+static int byteCounter;
+static unsigned char rightMask;
+
+UCHAR bytesPerPixel(ULONG Format)
+{
+ /* This function is taken from /subsys/win32k/eng/surface.c
+ * FIXME: GDI bitmaps are supposed to be pixel-packed. Right now if the
+ * pixel size if < 1 byte we expand it to 1 byte for simplicities sake */
+
+ switch (Format)
+ {
+ case BMF_1BPP:
+ return 1;
+
+ case BMF_4BPP:
+ case BMF_4RLE:
+ return 1;
+
+ case BMF_8BPP:
+ case BMF_8RLE:
+ return 1;
+
+ case BMF_16BPP:
+ return 2;
+
+ case BMF_24BPP:
+ return 3;
+
+ case BMF_32BPP:
+ return 4;
+
+ default:
+ return 0;
+ }
+}
+
+VOID vgaPreCalc()
+{
+ ULONG j;
+
+ startmasks[0] = 255;
+ startmasks[1] = 1;
+ startmasks[2] = 3;
+ startmasks[3] = 7;
+ startmasks[4] = 15;
+ startmasks[5] = 31;
+ startmasks[6] = 63;
+ startmasks[7] = 127;
+
+ endmasks[0] = 0;
+ endmasks[1] = 128;
+ endmasks[2] = 192;
+ endmasks[3] = 224;
+ endmasks[4] = 240;
+ endmasks[5] = 248;
+ endmasks[6] = 252;
+ endmasks[7] = 254;
+
+ for (j = 0; j < 80; j++)
+ {
+ maskbit[j*8] = 128;
+ maskbit[j*8+1] = 64;
+ maskbit[j*8+2] = 32;
+ maskbit[j*8+3] = 16;
+ maskbit[j*8+4] = 8;
+ maskbit[j*8+5] = 4;
+ maskbit[j*8+6] = 2;
+ maskbit[j*8+7] = 1;
+
+ bit8[j*8] = 7;
+ bit8[j*8+1] = 6;
+ bit8[j*8+2] = 5;
+ bit8[j*8+3] = 4;
+ bit8[j*8+4] = 3;
+ bit8[j*8+5] = 2;
+ bit8[j*8+6] = 1;
+ bit8[j*8+7] = 0;
+ }
+ for (j = 0; j < SCREEN_Y; j++)
+ y80[j] = j*80;
+ for (j = 0; j < SCREEN_X; j++)
+ xconv[j] = j >> 3;
+
+ for (j = 0; j < 256; j++)
+ {
+ PreCalcReverseByte[j] =
+ (((j >> 0) & 0x1) << 7) |
+ (((j >> 1) & 0x1) << 6) |
+ (((j >> 2) & 0x1) << 5) |
+ (((j >> 3) & 0x1) << 4) |
+ (((j >> 4) & 0x1) << 3) |
+ (((j >> 5) & 0x1) << 2) |
+ (((j >> 6) & 0x1) << 1) |
+ (((j >> 7) & 0x1) << 0);
+ }
+
+ for (j = 0; j < 256; j++)
+ {
+ UnpackPixel[j] =
+ (((j >> 0) & 0x1) << 4) |
+ (((j >> 1) & 0x1) << 0) |
+ (((j >> 2) & 0x1) << 12) |
+ (((j >> 3) & 0x1) << 8) |
+ (((j >> 4) & 0x1) << 20) |
+ (((j >> 5) & 0x1) << 16) |
+ (((j >> 6) & 0x1) << 28) |
+ (((j >> 7) & 0x1) << 24);
+ }
+}
+
+void
+get_masks(int x, int w)
+{
+ register int tmp;
+
+ leftMask = rightMask = 0;
+ byteCounter = w;
+ /* right margin */
+ tmp = (x+w) & 7;
+ if (tmp)
+ {
+ byteCounter -= tmp;
+ rightMask = (unsigned char)(0xff00 >> tmp);
+ }
+ /* left margin */
+ tmp = x & 7;
+ if (tmp)
+ {
+ byteCounter -= (8 - tmp);
+ leftMask = (0xff >> tmp);
+ }
+ /* too small ? */
+ if (byteCounter < 0)
+ {
+ leftMask &= rightMask;
+ rightMask = 0;
+ byteCounter = 0;
+ }
+ byteCounter /= 8;
+}
+
+VOID vgaPutPixel(INT x, INT y, UCHAR c)
+{
+ ULONG offset;
+
+ offset = xconv[x]+y80[y];
+
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D,maskbit[x]);
+
+ READ_REGISTER_UCHAR(vidmem + offset);
+ WRITE_REGISTER_UCHAR(vidmem + offset, c);
+}
+
+VOID vgaPutByte(INT x, INT y, UCHAR c)
+{
+ ULONG offset;
+
+ offset = xconv[x]+y80[y];
+
+ /* Set the write mode */
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D,0xff);
+
+ WRITE_REGISTER_UCHAR(vidmem + offset, c);
+}
+
+VOID vgaGetByte(
+ IN ULONG offset,
+ OUT UCHAR *b,
+ OUT UCHAR *g,
+ OUT UCHAR *r,
+ OUT UCHAR *i)
+{
+ WRITE_PORT_USHORT((PUSHORT)GRA_I, 0x0304);
+ *i = READ_REGISTER_UCHAR(vidmem + offset);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
+ *r = READ_REGISTER_UCHAR(vidmem + offset);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x01);
+ *g = READ_REGISTER_UCHAR(vidmem + offset);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
+ *b = READ_REGISTER_UCHAR(vidmem + offset);
+}
+
+INT vgaGetPixel(
+ IN INT x,
+ IN INT y)
+{
+ UCHAR mask, b, g, r, i;
+ ULONG offset;
+
+ offset = xconv[x] + y80[y];
+ vgaGetByte(offset, &b, &g, &r, &i);
+
+ mask = maskbit[x];
+ b = b & mask;
+ g = g & mask;
+ r = r & mask;
+ i = i & mask;
+
+ mask = bit8[x];
+ g = g >> mask;
+ b = b >> mask;
+ r = r >> mask;
+ i = i >> mask;
+
+ return (b + 2 * g + 4 * r + 8 * i);
+}
+
+BOOL vgaHLine(INT x, INT y, INT len, UCHAR c)
+{
+ ULONG orgx, pre1, midpre1;
+ //ULONG orgpre1;
+ LONG ileftpix, imidpix, irightpix;
+
+ orgx = x;
+
+ /*if ( len < 8 )
+ {
+ for (i = x; i < x+len; i++ )
+ vgaPutPixel ( i, y, c );
+
+ return TRUE;
+ }*/
+
+ /* Calculate the left mask pixels, middle bytes and right mask pixel */
+ ileftpix = 7 - mod8(x-1);
+ irightpix = mod8(x+len);
+ imidpix = (len-ileftpix-irightpix) / 8;
+
+ pre1 = xconv[(x-1)&~7] + y80[y];
+ //orgpre1=pre1;
+
+ /* check for overlap ( very short line ) */
+ if ( (ileftpix+irightpix) > len )
+ {
+ int mask = startmasks[ileftpix] & endmasks[irightpix];
+ /* Write left pixels */
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08); // set the mask
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D,mask);
+
+ READ_REGISTER_UCHAR(vidmem + pre1);
+ WRITE_REGISTER_UCHAR(vidmem + pre1, c);
+
+ return TRUE;
+ }
+
+ /* Left */
+ if ( ileftpix > 0 )
+ {
+ /* Write left pixels */
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08); // set the mask
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D,startmasks[ileftpix]);
+
+ READ_REGISTER_UCHAR(vidmem + pre1);
+ WRITE_REGISTER_UCHAR(vidmem + pre1, c);
+
+ /* Prepare new x for the middle */
+ x = orgx + 8;
+ }
+
+ if ( imidpix > 0 )
+ {
+ midpre1 = xconv[x] + y80[y];
+
+ /* Set mask to all pixels in byte */
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0xff);
+ memset(vidmem+midpre1, c, imidpix); // write middle pixels, no need to read in latch because of the width
+ }
+
+ if ( irightpix > 0 )
+ {
+ x = orgx + len - irightpix;
+ pre1 = xconv[x] + y80[y];
+
+ /* Write right pixels */
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08); // set the mask bits
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, endmasks[irightpix]);
+ READ_REGISTER_UCHAR(vidmem + pre1);
+ WRITE_REGISTER_UCHAR(vidmem + pre1, c);
+ }
+
+ return TRUE;
+}
+
+BOOL vgaVLine(INT x, INT y, INT len, UCHAR c)
+{
+ INT offset, i;
+
+ offset = xconv[x]+y80[y];
+
+#ifdef VGA_PERF
+ vgaSetBitMaskRegister ( maskbit[x] );
+#else
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08); // set the mask
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D,maskbit[x]);
+#endif
+
+ for(i=y; i<y+len; i++)
+ {
+ READ_REGISTER_UCHAR(vidmem + offset);
+ WRITE_REGISTER_UCHAR(vidmem + offset, c);
+ offset += 80;
+ }
+
+ return TRUE;
+}
+
+static const RECTL rclEmpty = { 0, 0, 0, 0 };
+
+BOOL VGADDIIntersectRect(PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2)
+{
+ prcDst->left = max(prcSrc1->left, prcSrc2->left);
+ prcDst->right = min(prcSrc1->right, prcSrc2->right);
+
+ if (prcDst->left < prcDst->right)
+ {
+ prcDst->top = max(prcSrc1->top, prcSrc2->top);
+ prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
+
+ if (prcDst->top < prcDst->bottom)
+ return TRUE;
+ }
+
+ *prcDst = rclEmpty;
+
+ return FALSE;
+}
+
+void DIB_BltFromVGA(int x, int y, int w, int h, void *b, int Dest_lDelta)
+{
+ ULONG plane;
+ ULONG left = x >> 3;
+ ULONG shift = x - (x & ~0x7);
+ UCHAR pixel, nextpixel;
+ LONG rightcount;
+ INT i, j;
+ LONG stride = w >> 3;
+
+ /* Calculate the number of rightmost bytes not in a dword block. */
+ if (w >= 8)
+ {
+ rightcount = w % 8;
+ }
+ else
+ {
+ stride = 0;
+ rightcount = w;
+ }
+
+ /* Reset the destination. */
+ for (j = 0; j < h; j++)
+ memset((PVOID)((ULONG_PTR)b + (j * Dest_lDelta)), 0, abs(Dest_lDelta));
+
+ for (plane = 0; plane < 4; plane++)
+ {
+ PUCHAR dest = b;
+
+ /* Select the plane we are reading in this iteration. */
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x04);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, plane);
+
+ for (j = 0; j < h; j++)
+ {
+ PULONG destline = (PULONG)dest;
+ PUCHAR src = vidmem + (y + j) * SCREEN_STRIDE + left;
+ /* Read the data for one plane for an eight aligned pixel block. */
+ nextpixel = PreCalcReverseByte[READ_REGISTER_UCHAR(src)];
+ for (i = 0; i < stride; i++, src++, destline++)
+ {
+ /* Form the data for one plane for an aligned block in the destination. */
+ pixel = nextpixel;
+ pixel >>= shift;
+
+ nextpixel = PreCalcReverseByte[READ_REGISTER_UCHAR(src + 1)];
+ pixel |= (nextpixel << (8 - shift));
+
+ /* Expand the plane data to 'chunky' format and store. */
+ *destline |= (UnpackPixel[pixel] << plane);
+ }
+ /* Handle any pixels not falling into a full block. */
+ if (rightcount != 0)
+ {
+ ULONG row;
+
+ /* Form the data for a complete block. */
+ pixel = nextpixel;
+ pixel >>= shift;
+
+ nextpixel = PreCalcReverseByte[READ_REGISTER_UCHAR(src + 1)];
+ pixel |= (nextpixel << (8 - shift));
+
+ row = UnpackPixel[pixel] << plane;
+
+ /* Store the data for each pixel in the destination. */
+ for (i = 0; i < rightcount; i++)
+ {
+ ((PUCHAR)destline)[i] |= (row & 0xFF);
+ row >>= 8;
+ }
+ }
+ dest += Dest_lDelta;
+ }
+ }
+
+#ifdef VGA_VERIFY
+ for (j = 0; j < h; j++)
+ {
+ for (i = 0; i < w; i += 2)
+ {
+ UCHAR c1, c2;
+ ULONG mask = (i < (w - 1)) ? 0xFF : 0xF0;
+
+ c1 = (vgaGetPixel(x + i, y + j) << 4) | (vgaGetPixel(x + i + 1, y + j));
+ c2 = ((PUCHAR)b)[(j * Dest_lDelta) + (i >> 1)];
+ if ((c1 & mask) != (c2 & mask))
+ EngDebugBreak();
+ }
+ }
+#endif /* VGA_VERIFY */
+}
+
+/* DIB blt to the VGA. */
+void DIB_BltToVGA(int x, int y, int w, int h, void *b, int Source_lDelta, int StartMod)
+{
+ PUCHAR pb, opb = b;
+ LONG i, j;
+ LONG x2 = x + w;
+ LONG y2 = y + h;
+ ULONG offset;
+
+ for (i = x; i < x2; i++)
+ {
+ pb = opb;
+ offset = xconv[i] + y80[y];
+
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08); // set the mask
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, maskbit[i]);
+
+ if (StartMod == ((i - x) % 2))
+ {
+ for (j = y; j < y2; j++)
+ {
+ READ_REGISTER_UCHAR(vidmem + offset);
+ WRITE_REGISTER_UCHAR(vidmem + offset, (*pb & 0xf0) >> 4);
+ offset += 80;
+ pb += Source_lDelta;
+ }
+ }
+ else
+ {
+ for (j = y; j < y2; j++)
+ {
+ READ_REGISTER_UCHAR(vidmem + offset);
+ WRITE_REGISTER_UCHAR(vidmem + offset, *pb & 0x0f);
+ offset += 80;
+ pb += Source_lDelta;
+ }
+ }
+
+ if (StartMod != ((i - x) % 2))
+ opb++;
+ }
+}
+
+
+/* DIB blt to the VGA. */
+void DIB_BltToVGAWithXlate(int x, int y, int w, int h, void *b, int Source_lDelta, XLATEOBJ* Xlate)
+{
+ PUCHAR pb, opb = b;
+ ULONG i, j;
+ ULONG x2 = x + w;
+ ULONG y2 = y + h;
+ ULONG offset;
+
+ for (i = x; i < x2; i++)
+ {
+ pb = opb;
+ offset = xconv[i] + y80[y];
+
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08); // set the mask
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, maskbit[i]);
+
+ if (0 == ((i - x) % 2))
+ {
+ for (j = y; j < y2; j++)
+ {
+ READ_REGISTER_UCHAR(vidmem + offset);
+ WRITE_REGISTER_UCHAR(vidmem + offset, XLATEOBJ_iXlate(Xlate, (*pb & 0xf0) >> 4));
+ offset += 80;
+ pb += Source_lDelta;
+ }
+ }
+ else
+ {
+ for (j = y; j < y2; j++)
+ {
+ READ_REGISTER_UCHAR(vidmem + offset);
+ WRITE_REGISTER_UCHAR(vidmem + offset, XLATEOBJ_iXlate(Xlate, *pb & 0x0f));
+ offset += 80;
+ pb += Source_lDelta;
+ }
+ }
+
+ if (0 != ((i - x) % 2))
+ opb++;
+ }
+}
+
+/* DIB blt to the VGA.
+ * For now we just do slow writes -- pixel by pixel,
+ * packing each one into the correct 4BPP format. */
+void DIB_TransparentBltToVGA(int x, int y, int w, int h, void *b, int Source_lDelta, ULONG trans)
+
+{
+ PUCHAR pb = b, opb = b;
+ BOOLEAN edgePixel = FALSE;
+ ULONG i, j;
+ ULONG x2 = x + w;
+ ULONG y2 = y + h;
+ UCHAR b1, b2;
+
+ /* Check if the width is odd */
+ if(mod2(w) > 0)
+ {
+ edgePixel = TRUE;
+ x2 -= 1;
+ }
+
+ for (j=y; j<y2; j++)
+ {
+ for (i=x; i<x2; i+=2)
+ {
+ b1 = (*pb & 0xf0) >> 4;
+ b2 = *pb & 0x0f;
+ if(b1 != trans) vgaPutPixel(i, j, b1);
+ if(b2 != trans) vgaPutPixel(i+1, j, b2);
+ pb++;
+ }
+
++ if (edgePixel)
+ {
+ b1 = *pb;
+ if(b1 != trans) vgaPutPixel(x2, j, b1);
+ pb++;
+ }
+
+ opb += Source_lDelta;
+ pb = opb; // new test code
+ }
+}
+
+// This algorithm goes from left to right, storing each 4BPP pixel
+// in an entire byte.
+void FASTCALL
+vgaReadScan( int x, int y, int w, void *b )
+{
+ unsigned char *vp, *vpP;
+ unsigned char data, mask, maskP;
+ unsigned char *bp;
+ unsigned char plane_mask;
+ int plane, i;
+
+ ASSIGNVP4(x, y, vpP)
+ ASSIGNMK4(x, y, maskP)
+ get_masks(x, w);
+ WRITE_PORT_USHORT((PUSHORT)GRA_I, 0x0005); // read mode 0
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x04); // read map select
+
+ memset ( b, 0, w );
+
+ for ( plane=0, plane_mask=1; plane < 4; plane++, plane_mask<<=1 )
+ {
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, plane); // read map select
+
+ vp = vpP;
+ bp = b;
+ if ( leftMask )
+ {
+ mask = maskP;
+ data = *vp++;
+ do
+ {
+ if (data & mask)
+ *bp |= plane_mask;
+ bp++;
+ mask >>= 1;
+ } while (mask & leftMask);
+ }
+ if (byteCounter)
+ {
+ for (i=byteCounter; i>0; i--)
+ {
+ data = *vp++;
+ if (data & 0x80) *bp |= plane_mask;
+ bp++;
+
+ if (data & 0x40) *bp |= plane_mask;
+ bp++;
+ if (data & 0x20) *bp |= plane_mask;
+ bp++;
+ if (data & 0x10) *bp |= plane_mask;
+ bp++;
+ if (data & 0x08) *bp |= plane_mask;
+ bp++;
+ if (data & 0x04) *bp |= plane_mask;
+ bp++;
+ if (data & 0x02) *bp |= plane_mask;
+ bp++;
+ if (data & 0x01) *bp |= plane_mask;
+ bp++;
+ }
+ }
+ if (rightMask)
+ {
+ mask = 0x80;
+ data = *vp;
+ do
+ {
+ if (data & mask)
+ *bp |= plane_mask;
+ bp++;
+ mask >>= 1;
+ } while (mask & rightMask);
+ }
+ }
+}
+
+/* This algorithm goes from left to right
+ * It stores each 4BPP pixel in an entire byte. */
+void FASTCALL
+vgaWriteScan ( int x, int y, int w, void *b )
+{
+ unsigned char *bp;
+ unsigned char *vp;
+ //unsigned char init_mask;
+ volatile unsigned char dummy;
+ //int byte_per_line;
+ int i, j, off, init_off = x&7;
+
+ bp = b;
+ ASSIGNVP4(x, y, vp)
+ //ASSIGNMK4(x, y, init_mask)
+ //byte_per_line = SCREEN_X >> 3;
+
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05); // write mode 2
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03); // replace
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08); // bit mask
+
+ for ( j = 0; j < 8; j++)
+ {
+ unsigned int mask = 0x80 >> j;
+ WRITE_PORT_UCHAR ( (PUCHAR)GRA_D, (unsigned char)mask );
+ i = j - init_off;
+ off = 0;
+ if (j < init_off)
+ i += 8, off++;
+ while (i < w)
+ {
+ dummy = vp[off];
+ dummy = bp[i];
+ vp[off] = dummy;
+ i += 8;
+ off++;
+ }
+ }
+}
+
+/* This algorithm goes from left to right, and inside that loop, top to bottom.
+ * It also stores each 4BPP pixel in an entire byte. */
+void DFB_BltFromVGA(int x, int y, int w, int h, void *b, int bw)
+{
+ unsigned char *vp, *vpY, *vpP;
+ unsigned char data, mask, maskP;
+ unsigned char *bp, *bpY;
+ unsigned char plane_mask;
+ int byte_per_line = SCREEN_X >> 3;
+ int plane, i, j;
+
+ ASSIGNVP4(x, y, vpP)
+ ASSIGNMK4(x, y, maskP)
+ get_masks(x, w);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05); // read mode 0
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x04); // read map select
+
+ /* clear buffer */
+ bp = b;
+ for (j = h; j > 0; j--)
+ {
+ memset(bp, 0, w);
+ bp += bw;
+ }
+
+ for (plane = 0, plane_mask = 1; plane < 4; plane++, plane_mask <<= 1)
+ {
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, plane); // read map select
+ vpY = vpP;
+ bpY = b;
+ for (j = h; j > 0; j--)
+ {
+ vp = vpY;
+ bp = bpY;
+ if (leftMask)
+ {
+ mask = maskP;
+ data = *vp++;
+ do
+ {
+ if (data & mask)
+ *bp |= plane_mask;
+ bp++;
+ mask >>= 1;
+ } while (mask & leftMask);
+ }
+ if (byteCounter)
+ {
+ for (i=byteCounter; i>0; i--)
+ {
+ data = *vp++;
+ if (data & 0x80) *bp |= plane_mask;
+ bp++;
+ if (data & 0x40) *bp |= plane_mask;
+ bp++;
+ if (data & 0x20) *bp |= plane_mask;
+ bp++;
+ if (data & 0x10) *bp |= plane_mask;
+ bp++;
+ if (data & 0x08) *bp |= plane_mask;
+ bp++;
+ if (data & 0x04) *bp |= plane_mask;
+ bp++;
+ if (data & 0x02) *bp |= plane_mask;
+ bp++;
+ if (data & 0x01) *bp |= plane_mask;
+ bp++;
+ }
+ }
+ if (rightMask)
+ {
+ mask = 0x80;
+ data = *vp;
+ do
+ {
+ if (data & mask) *bp |= plane_mask;
+ bp++;
+ mask >>= 1;
+ } while (mask & rightMask);
+ }
+ bpY += bw;
+ vpY += byte_per_line;
+ }
+ }
+
+ // We don't need this if the next call is a DFB blt to VGA (as in the case of moving the mouse pointer)
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05); // write mode 2
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03); // replace
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
+}
+
+/* This algorithm goes from left to right, and inside that loop, top to bottom.
+ * It also stores each 4BPP pixel in an entire byte. */
+void DFB_BltToVGA(int x, int y, int w, int h, void *b, int bw)
+{
+ unsigned char *bp, *bpX;
+ unsigned char *vp, *vpX;
+ unsigned char mask;
+ //volatile unsigned char dummy;
+ int byte_per_line;
+ int i, j;
+
+ bpX = b;
+ ASSIGNVP4(x, y, vpX)
+ ASSIGNMK4(x, y, mask)
+ byte_per_line = SCREEN_X >> 3;
+
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05); // write mode 2
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03); // replace
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08); // bit mask
+
+ for (i=w; i>0; i--)
+ {
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, mask);
+ bp = bpX;
+ vp = vpX;
+ for (j = h; j > 0; j--)
+ {
+ //dummy = *vp;
+ *vp = *bp;
+ bp += bw;
+ vp += byte_per_line;
+ }
+ bpX++;
+ if ((mask >>= 1) == 0)
+ {
+ vpX++;
+ mask = 0x80;
+ }
+ }
+}
+
+/* This algorithm goes from goes from left to right, and inside that loop, top to bottom.
+ * It also stores each 4BPP pixel in an entire byte. */
+void DFB_BltToVGA_Transparent(int x, int y, int w, int h, void *b, int bw, char Trans)
+{
+ unsigned char *bp, *bpX;
+ unsigned char *vp, *vpX;
+ unsigned char mask;
+ //volatile unsigned char dummy;
+ int byte_per_line;
+ int i, j;
+
+ bpX = b;
+ ASSIGNVP4(x, y, vpX)
+ ASSIGNMK4(x, y, mask)
+ byte_per_line = SCREEN_X >> 3;
+
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05); // write mode 2
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03); // replace
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
+ WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08); // bit mask
+
+ for (i=w; i>0; i--)
+ {
+ WRITE_PORT_UCHAR((PUCHAR)GRA_D, mask);
+ bp = bpX;
+ vp = vpX;
+ for (j=h; j>0; j--)
+ {
+ if (*bp != Trans)
+ {
+ //dummy = *vp;
+ *vp = *bp;
+ }
+ bp += bw;
+ vp += byte_per_line;
+ }
+ bpX++;
+ if ((mask >>= 1) == 0)
+ {
+ vpX++;
+ mask = 0x80;
+ }
+ }
+}
+
+/* This algorithm converts a DFB into a DIB
+ * WARNING: This algorithm is buggy */
+void DFB_BltToDIB(int x, int y, int w, int h, void *b, int bw, void *bdib, int dibw)
+{
+ unsigned char *bp, *bpX, *dib, *dibTmp;
+ int i, j, dib_shift;
+
+ bpX = b;
+ dib = (unsigned char *)bdib + y * dibw + (x / 2);
+
+ for (i=w; i>0; i--)
+ {
+ /* determine the bit shift for the DIB pixel */
+ dib_shift = mod2(w-i);
+ if(dib_shift > 0)
+ dib_shift = 4;
+ dibTmp = dib;
+
+ bp = bpX;
+ for (j = h; j > 0; j--)
+ {
+ *dibTmp = *bp << dib_shift | *(bp + 1);
+ dibTmp += dibw;
+ bp += bw;
+ }
+ bpX++;
+ if(dib_shift == 0)
+ dib++;
+ }
+}
+
+/* This algorithm converts a DIB into a DFB */
+void DIB_BltToDFB(int x, int y, int w, int h, void *b, int bw, void *bdib, int dibw)
+{
+ unsigned char *bp, *bpX, *dib, *dibTmp;
+ int i, j, dib_shift, dib_and;
+
+ bpX = b;
+ dib = (unsigned char *)bdib + y * dibw + (x / 2);
+
+ for (i=w; i>0; i--)
+ {
+ /* determine the bit shift for the DIB pixel */
+ dib_shift = mod2(w-i);
+ if(dib_shift > 0)
+ {
+ dib_shift = 0;
+ dib_and = 0x0f;
+ }
+ else
+ {
+ dib_shift = 4;
+ dib_and = 0xf0;
+ }
+
+ dibTmp = dib;
+ bp = bpX;
+
+ for (j=h; j>0; j--)
+ {
+ *bp = (*dibTmp & dib_and) >> dib_shift;
+ dibTmp += dibw;
+ bp += bw;
+ }
+
+ bpX++;
+ if (dib_shift == 0)
+ dib++;
+ }
+}
--- /dev/null
- if (isSurf == TRUE &&
+/*
+* COPYRIGHT: See COPYING in the top level directory
+* PROJECT: ReactOS win32 subsystem
+* PURPOSE: Flood filling support
+* FILE: subsystems/win32/win32k/dib/floodfill.c
+* PROGRAMMER: Gregor Schneider, <grschneider AT gmail DOT com>
+*/
+
+#include <win32k.h>
+
+#define NDEBUG
+#include <debug.h>
+
+/*
+* This floodfill algorithm is an iterative four neighbors version. It works with an internal stack like data structure.
+* The stack is kept in an array, sized for the worst case scenario of having to add all pixels of the surface.
+* This avoids having to allocate and free memory blocks all the time. The stack grows from the end of the array towards the start.
+* All pixels are checked before being added, against belonging to the fill rule (FLOODFILLBORDER or FLOODFILLSURFACE)
+* and the position in respect to the clip region. This guarantees all pixels lying on the stack belong to the filled surface.
+* Further optimisations of the algorithm are possible.
+*/
+
+/* Floodfil helper structures and functions */
+typedef struct _floodItem
+{
+ ULONG x;
+ ULONG y;
+} FLOODITEM;
+
+typedef struct _floodInfo
+{
+ ULONG floodLen;
+ FLOODITEM *floodStart;
+ FLOODITEM *floodData;
+} FLOODINFO;
+
+static __inline BOOL initFlood(FLOODINFO *info, RECTL *DstRect)
+{
+ ULONG width = DstRect->right - DstRect->left;
+ ULONG height = DstRect->bottom - DstRect->top;
+ info->floodData = ExAllocatePoolWithTag(NonPagedPool, width * height * sizeof(FLOODITEM), TAG_DIB);
+ if (info->floodData == NULL)
+ {
+ return FALSE;
+ }
+ info->floodStart = info->floodData + (width * height);
+ DPRINT("Allocated flood stack from %p to %p\n", info->floodData, info->floodStart);
+ return TRUE;
+}
+static __inline VOID finalizeFlood(FLOODINFO *info)
+{
+ ExFreePoolWithTag(info->floodData, TAG_DIB);
+}
+static __inline VOID addItemFlood(FLOODINFO *info,
+ ULONG x,
+ ULONG y,
+ SURFOBJ *DstSurf,
+ RECTL *DstRect,
+ ULONG Color,
+ BOOL isSurf)
+{
+ if (RECTL_bPointInRect(DstRect,x,y))
+ {
++ if (isSurf &&
+ DibFunctionsForBitmapFormat[DstSurf->iBitmapFormat].DIB_GetPixel(DstSurf, x, y) != Color)
+ {
+ return;
+ }
+ else if (isSurf == FALSE &&
+ DibFunctionsForBitmapFormat[DstSurf->iBitmapFormat].DIB_GetPixel(DstSurf, x, y) == Color)
+ {
+ return;
+ }
+ info->floodStart--;
+ info->floodStart->x = x;
+ info->floodStart->y = y;
+ info->floodLen++;
+ }
+}
+static __inline VOID removeItemFlood(FLOODINFO *info)
+{
+ info->floodStart++;
+ info->floodLen--;
+}
+
+BOOLEAN DIB_XXBPP_FloodFillSolid(SURFOBJ *DstSurf,
+ BRUSHOBJ *Brush,
+ RECTL *DstRect,
+ POINTL *Origin,
+ ULONG ConvColor,
+ UINT FillType)
+{
+ ULONG x, y;
+ ULONG BrushColor;
+ FLOODINFO flood = {0, NULL, NULL};
+
+ BrushColor = Brush->iSolidColor;
+ x = Origin->x;
+ y = Origin->y;
+
+ if (FillType == FLOODFILLBORDER)
+ {
+ /* Check if the start pixel has the border color */
+ if (DibFunctionsForBitmapFormat[DstSurf->iBitmapFormat].DIB_GetPixel(DstSurf, x, y) == ConvColor)
+ {
+ return FALSE;
+ }
+
+ if (initFlood(&flood, DstRect) == FALSE)
+ {
+ return FALSE;
+ }
+ addItemFlood(&flood, x, y, DstSurf, DstRect, ConvColor, FALSE);
+ while (flood.floodLen != 0)
+ {
+ x = flood.floodStart->x;
+ y = flood.floodStart->y;
+ removeItemFlood(&flood);
+
+ DibFunctionsForBitmapFormat[DstSurf->iBitmapFormat].DIB_PutPixel(DstSurf, x, y, BrushColor);
+ if (flood.floodStart - 4 < flood.floodData)
+ {
+ DPRINT1("Can't finish flooding!\n");
+ finalizeFlood(&flood);
+ return FALSE;
+ }
+ addItemFlood(&flood, x, y + 1, DstSurf, DstRect, ConvColor, FALSE);
+ addItemFlood(&flood, x, y - 1, DstSurf, DstRect, ConvColor, FALSE);
+ addItemFlood(&flood, x + 1, y, DstSurf, DstRect, ConvColor, FALSE);
+ addItemFlood(&flood, x - 1, y, DstSurf, DstRect, ConvColor, FALSE);
+ }
+ finalizeFlood(&flood);
+ }
+ else if (FillType == FLOODFILLSURFACE)
+ {
+ /* Check if the start pixel has the surface color */
+ if (DibFunctionsForBitmapFormat[DstSurf->iBitmapFormat].DIB_GetPixel(DstSurf, x, y) != ConvColor)
+ {
+ return FALSE;
+ }
+
+ if (initFlood(&flood, DstRect) == FALSE)
+ {
+ return FALSE;
+ }
+ addItemFlood(&flood, x, y, DstSurf, DstRect, ConvColor, TRUE);
+ while (flood.floodLen != 0)
+ {
+ x = flood.floodStart->x;
+ y = flood.floodStart->y;
+ removeItemFlood(&flood);
+
+ DibFunctionsForBitmapFormat[DstSurf->iBitmapFormat].DIB_PutPixel(DstSurf, x, y, BrushColor);
+ if (flood.floodStart - 4 < flood.floodData)
+ {
+ DPRINT1("Can't finish flooding!\n");
+ finalizeFlood(&flood);
+ return FALSE;
+ }
+ addItemFlood(&flood, x, y + 1, DstSurf, DstRect, ConvColor, TRUE);
+ addItemFlood(&flood, x, y - 1, DstSurf, DstRect, ConvColor, TRUE);
+ addItemFlood(&flood, x + 1, y, DstSurf, DstRect, ConvColor, TRUE);
+ addItemFlood(&flood, x - 1, y, DstSurf, DstRect, ConvColor, TRUE);
+ }
+ finalizeFlood(&flood);
+ }
+ else
+ {
+ DPRINT1("Unsupported FloodFill type!\n");
+ return FALSE;
+ }
+ return TRUE;
+}
--- /dev/null
- if (Return == TRUE)
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS GDI32
+ * PURPOSE: GDI DirectX inteface
+ * FILE: lib/gdi32/misc/gdientry.c
+ * PROGRAMERS: Alex Ionescu (alex@relsoft.net)
+ * Magnus Olsen (magnus@greatlord.com)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <precomp.h>
+
+#include <stdio.h>
+#include <d3dhal.h>
+
+/* DATA **********************************************************************/
+
+HANDLE ghDirectDraw;
+ULONG gcDirectDraw;
+
+#define GetDdHandle(Handle) ((HANDLE)Handle ? (HANDLE)Handle : ghDirectDraw)
+
+
+
+/* CALLBACKS *****************************************************************/
+
+/*
+ * @implemented
+ *
+ * DdAddAttachedSurface
+ */
+DWORD
+WINAPI
+DdAddAttachedSurface(LPDDHAL_ADDATTACHEDSURFACEDATA Attach)
+{
+ /* Call win32k */
+ return NtGdiDdAddAttachedSurface((HANDLE)Attach->lpDDSurface->hDDSurface,
+ (HANDLE)Attach->lpSurfAttached->hDDSurface,
+ (PDD_ADDATTACHEDSURFACEDATA)Attach);
+}
+
+/*
+ * @implemented
+ *
+ * DdBlt
+ */
+DWORD
+WINAPI
+DdBlt(LPDDHAL_BLTDATA Blt)
+{
+ HANDLE Surface = 0;
+
+ /* Use the right surface */
+ if (Blt->lpDDSrcSurface)
+ {
+ Surface = (HANDLE)Blt->lpDDSrcSurface->hDDSurface;
+ }
+
+ /* Call win32k */
+ return NtGdiDdBlt((HANDLE)Blt->lpDDDestSurface->hDDSurface, Surface, (PDD_BLTDATA)Blt);
+}
+
+/*
+ * @implemented
+ *
+ * DdDestroySurface
+ */
+DWORD
+WINAPI
+DdDestroySurface(LPDDHAL_DESTROYSURFACEDATA pDestroySurface)
+{
+ DWORD Return = DDHAL_DRIVER_NOTHANDLED;
+ BOOL RealDestroy;
+
+ if (pDestroySurface->lpDDSurface->hDDSurface)
+ {
+ /* Check if we shoudl really destroy it */
+ RealDestroy = !(pDestroySurface->lpDDSurface->dwFlags & DDRAWISURF_DRIVERMANAGED) ||
+ !(pDestroySurface->lpDDSurface->dwFlags & DDRAWISURF_INVALID);
+
+ /* Call win32k */
+ Return = NtGdiDdDestroySurface((HANDLE)pDestroySurface->lpDDSurface->hDDSurface, RealDestroy);
+ }
+
+ return Return;
+}
+
+/*
+ * @implemented
+ *
+ * DdFlip
+ */
+DWORD
+WINAPI
+DdFlip(LPDDHAL_FLIPDATA Flip)
+{
+ /* Note :
+ * See http://msdn2.microsoft.com/en-us/library/ms794213.aspx and
+ * http://msdn2.microsoft.com/en-us/library/ms792675.aspx
+ */
+
+ HANDLE hSurfaceCurrentLeft = NULL;
+ HANDLE hSurfaceTargetLeft = NULL;
+
+ /* Auto flip off or on */
+ if (Flip->dwFlags & DDFLIP_STEREO )
+ {
+ if ( (Flip->lpSurfTargLeft) &&
+ (Flip->lpSurfCurrLeft))
+ {
+ /* Auto flip on */
+ hSurfaceTargetLeft = (HANDLE) Flip->lpSurfTargLeft->hDDSurface;
+ hSurfaceCurrentLeft = (HANDLE) Flip->lpSurfCurrLeft->hDDSurface;
+ }
+ }
+
+ /* Call win32k */
+ return NtGdiDdFlip( (HANDLE) Flip->lpSurfCurr->hDDSurface,
+ (HANDLE) Flip->lpSurfTarg->hDDSurface,
+ hSurfaceCurrentLeft,
+ hSurfaceTargetLeft,
+ (PDD_FLIPDATA) Flip);
+}
+
+/*
+ * @implemented
+ *
+ * DdLock
+ */
+DWORD
+WINAPI
+DdLock(LPDDHAL_LOCKDATA Lock)
+{
+
+ /* Call win32k */
+ return NtGdiDdLock((HANDLE)Lock->lpDDSurface->hDDSurface,
+ (PDD_LOCKDATA)Lock,
+ (HANDLE)Lock->lpDDSurface->hDC);
+}
+
+/*
+ * @implemented
+ *
+ * DdUnlock
+ */
+DWORD
+WINAPI
+DdUnlock(LPDDHAL_UNLOCKDATA Unlock)
+{
+ /* Call win32k */
+ return NtGdiDdUnlock((HANDLE)Unlock->lpDDSurface->hDDSurface,
+ (PDD_UNLOCKDATA)Unlock);
+}
+
+/*
+ * @implemented
+ *
+ * DdGetBltStatus
+ */
+DWORD
+WINAPI
+DdGetBltStatus(LPDDHAL_GETBLTSTATUSDATA GetBltStatus)
+{
+ /* Call win32k */
+ return NtGdiDdGetBltStatus((HANDLE)GetBltStatus->lpDDSurface->hDDSurface,
+ (PDD_GETBLTSTATUSDATA)GetBltStatus);
+}
+
+/*
+ * @implemented
+ *
+ * DdGetBltStatus
+ */
+DWORD
+WINAPI
+DdGetFlipStatus(LPDDHAL_GETFLIPSTATUSDATA GetFlipStatus)
+{
+ /* Call win32k */
+ return NtGdiDdGetFlipStatus((HANDLE)GetFlipStatus->lpDDSurface->hDDSurface,
+ (PDD_GETFLIPSTATUSDATA)GetFlipStatus);
+}
+
+/*
+ * @implemented
+ *
+ * DdUpdateOverlay
+ */
+DWORD
+WINAPI
+DdUpdateOverlay(LPDDHAL_UPDATEOVERLAYDATA UpdateOverlay)
+{
+
+ /* We have to handle this manually here */
+ if (UpdateOverlay->dwFlags & DDOVER_KEYDEST)
+ {
+ /* Use the override */
+ UpdateOverlay->dwFlags &= ~DDOVER_KEYDEST;
+ UpdateOverlay->dwFlags |= DDOVER_KEYDESTOVERRIDE;
+
+ /* Set the overlay */
+ UpdateOverlay->overlayFX.dckDestColorkey =
+ UpdateOverlay->lpDDDestSurface->ddckCKDestOverlay;
+ }
+ if (UpdateOverlay->dwFlags & DDOVER_KEYSRC)
+ {
+ /* Use the override */
+ UpdateOverlay->dwFlags &= ~DDOVER_KEYSRC;
+ UpdateOverlay->dwFlags |= DDOVER_KEYSRCOVERRIDE;
+
+ /* Set the overlay */
+ UpdateOverlay->overlayFX.dckSrcColorkey =
+ UpdateOverlay->lpDDSrcSurface->ddckCKSrcOverlay;
+ }
+
+ /* Call win32k */
+ return NtGdiDdUpdateOverlay((HANDLE)UpdateOverlay->lpDDDestSurface->hDDSurface,
+ (HANDLE)UpdateOverlay->lpDDSrcSurface->hDDSurface,
+ (PDD_UPDATEOVERLAYDATA)UpdateOverlay);
+}
+
+/*
+ * @implemented
+ *
+ * DdSetOverlayPosition
+ */
+DWORD
+WINAPI
+DdSetOverlayPosition(LPDDHAL_SETOVERLAYPOSITIONDATA SetOverlayPosition)
+{
+ /* Call win32k */
+ return NtGdiDdSetOverlayPosition( (HANDLE)SetOverlayPosition->lpDDSrcSurface->hDDSurface,
+ (HANDLE)SetOverlayPosition->lpDDDestSurface->hDDSurface,
+ (PDD_SETOVERLAYPOSITIONDATA) SetOverlayPosition);
+}
+
+/*
+ * @implemented
+ *
+ * DdWaitForVerticalBlank
+ */
+DWORD
+WINAPI
+DdWaitForVerticalBlank(LPDDHAL_WAITFORVERTICALBLANKDATA WaitForVerticalBlank)
+{
+ /* Call win32k */
+ return NtGdiDdWaitForVerticalBlank(GetDdHandle(
+ WaitForVerticalBlank->lpDD->hDD),
+ (PDD_WAITFORVERTICALBLANKDATA)
+ WaitForVerticalBlank);
+}
+
+/*
+ * @implemented
+ *
+ * DdCanCreateSurface
+ */
+DWORD
+WINAPI
+DdCanCreateSurface(LPDDHAL_CANCREATESURFACEDATA CanCreateSurface)
+{
+ /*
+ * Note : This functions are basic same, in win32k
+ * NtGdiDdCanCreateD3DBuffer and NtGdiDdCanCreateSurface are mergs
+ * toghter in win32k at end and retrurn same data, it is still sepreated
+ * at user mode but in kmode it is not.
+ */
+
+ /* Call win32k */
+ return NtGdiDdCanCreateSurface(GetDdHandle(CanCreateSurface->lpDD->hDD),
+ (PDD_CANCREATESURFACEDATA)CanCreateSurface);
+}
+
+/*
+ * @implemented
+ *
+ * DdCreateSurface
+ */
+DWORD
+WINAPI
+DdCreateSurface(LPDDHAL_CREATESURFACEDATA pCreateSurface)
+{
+ DWORD Return = DDHAL_DRIVER_NOTHANDLED;
+ ULONG SurfaceCount = pCreateSurface->dwSCnt;
+ DD_SURFACE_LOCAL DdSurfaceLocal;
+ DD_SURFACE_MORE DdSurfaceMore;
+ DD_SURFACE_GLOBAL DdSurfaceGlobal;
+
+ HANDLE hPrevSurface, hSurface;
+
+ PDD_SURFACE_LOCAL pDdSurfaceLocal = NULL;
+ PDD_SURFACE_MORE pDdSurfaceMore = NULL;
+ PDD_SURFACE_GLOBAL pDdSurfaceGlobal = NULL;
+
+ PDD_SURFACE_LOCAL ptmpDdSurfaceLocal = NULL;
+ PDD_SURFACE_MORE ptmpDdSurfaceMore = NULL;
+ PDD_SURFACE_GLOBAL ptmpDdSurfaceGlobal = NULL;
+ PHANDLE phSurface = NULL, puhSurface = NULL;
+ ULONG i;
+ LPDDSURFACEDESC pSurfaceDesc = NULL;
+
+ /* TODO: Optimize speed. Most games/dx apps/programs do not want one surface, they want at least two.
+ * So we need increase the stack to contain two surfaces instead of one. This will increase
+ * the speed of the apps when allocating buffers. How to increase the surface stack space:
+ * we need to create a struct for DD_SURFACE_LOCAL DdSurfaceLocal, DD_SURFACE_MORE DdSurfaceMore
+ * DD_SURFACE_GLOBAL DdSurfaceGlobal, HANDLE hPrevSurface, hSurface like
+ * struct { DD_SURFACE_LOCAL DdSurfaceLocal1, DD_SURFACE_LOCAL DdSurfaceLocal2 }
+ * in a way that it may contain two surfaces, maybe even four. We need to watch what is most common before
+ * we create the size. Activate this IF when you start doing the optimze and please also
+ * take reports from users which value they got here.
+ */
+#if 1
+ {
+ char buffer[1024];
+ \
+ sprintf ( buffer, "Function %s : Optimze max to %d Surface ? (%s:%d)\n", __FUNCTION__, (int)SurfaceCount,__FILE__,__LINE__ );
+ OutputDebugStringA(buffer);
+ }
+#endif
+
+ /* Check how many surfaces there are */
+ if (SurfaceCount != 1)
+ {
+ /* We got more than one surface, so we need to allocate memory for them */
+ pDdSurfaceLocal = (PDD_SURFACE_LOCAL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (sizeof(DD_SURFACE_LOCAL) * SurfaceCount ));
+ pDdSurfaceMore = (PDD_SURFACE_MORE) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (sizeof(DD_SURFACE_MORE) * SurfaceCount ));
+ pDdSurfaceGlobal = (PDD_SURFACE_GLOBAL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (sizeof(DD_SURFACE_GLOBAL) * SurfaceCount ));
+ phSurface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (sizeof(HANDLE) * SurfaceCount ));
+ puhSurface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (sizeof(HANDLE) * SurfaceCount ));
+
+ /* Check if we successfully allocated all memory we need */
+ if ((pDdSurfaceLocal == NULL) || (pDdSurfaceMore == NULL) || (pDdSurfaceGlobal == NULL) || (phSurface == NULL) || (puhSurface == NULL))
+ {
+ pCreateSurface->ddRVal = DDERR_OUTOFMEMORY;
+
+ if ( pDdSurfaceLocal != NULL )
+ {
+ HeapFree(GetProcessHeap(), 0, pDdSurfaceLocal);
+ }
+
+ if ( pDdSurfaceMore != NULL )
+ {
+ HeapFree(GetProcessHeap(), 0, pDdSurfaceMore);
+ }
+
+ if ( pDdSurfaceGlobal != NULL )
+ {
+ HeapFree(GetProcessHeap(), 0, pDdSurfaceGlobal);
+ }
+
+ if ( phSurface != NULL )
+ {
+ HeapFree(GetProcessHeap(), 0, phSurface);
+ }
+
+ if ( puhSurface != NULL )
+ {
+ HeapFree(GetProcessHeap(), 0, puhSurface);
+ }
+
+ return DDHAL_DRIVER_HANDLED;
+ }
+ }
+ else
+ {
+ /* We'll use what we have on the stack */
+ pDdSurfaceLocal = &DdSurfaceLocal;
+ pDdSurfaceMore = &DdSurfaceMore;
+ pDdSurfaceGlobal = &DdSurfaceGlobal;
+ phSurface = &hPrevSurface;
+ puhSurface = &hSurface;
+
+ /* Clear the structures */
+ RtlZeroMemory(&DdSurfaceLocal, sizeof(DdSurfaceLocal));
+ RtlZeroMemory(&DdSurfaceGlobal, sizeof(DdSurfaceGlobal));
+ RtlZeroMemory(&DdSurfaceMore, sizeof(DdSurfaceMore));
+ }
+
+ /* check if we got a surface or not */
+ if (SurfaceCount!=0)
+ {
+ /* Loop for each surface */
+ ptmpDdSurfaceGlobal = pDdSurfaceGlobal;
+ ptmpDdSurfaceLocal = pDdSurfaceLocal;
+ ptmpDdSurfaceMore = pDdSurfaceMore;
+ pSurfaceDesc = pCreateSurface->lpDDSurfaceDesc;
+
+ for (i = 0; i < SurfaceCount; i++)
+ {
+ LPDDRAWI_DDRAWSURFACE_LCL lcl = pCreateSurface->lplpSList[i];
+ LPDDRAWI_DDRAWSURFACE_GBL gpl = pCreateSurface->lplpSList[i]->lpGbl;
+
+ phSurface[i] = (HANDLE)lcl->hDDSurface;
+ ptmpDdSurfaceLocal->ddsCaps.dwCaps = lcl->ddsCaps.dwCaps;
+
+ ptmpDdSurfaceLocal->dwFlags = (ptmpDdSurfaceLocal->dwFlags &
+ (0xB0000000 | DDRAWISURF_INMASTERSPRITELIST |
+ DDRAWISURF_HELCB | DDRAWISURF_FRONTBUFFER |
+ DDRAWISURF_BACKBUFFER | DDRAWISURF_INVALID |
+ DDRAWISURF_DCIBUSY | DDRAWISURF_DCILOCK)) |
+ (lcl->dwFlags & DDRAWISURF_DRIVERMANAGED);
+
+ ptmpDdSurfaceGlobal->wWidth = gpl->wWidth;
+ ptmpDdSurfaceGlobal->wHeight = gpl->wHeight;
+ ptmpDdSurfaceGlobal->lPitch = gpl->lPitch;
+ ptmpDdSurfaceGlobal->fpVidMem = gpl->fpVidMem;
+ ptmpDdSurfaceGlobal->dwBlockSizeX = gpl->dwBlockSizeX;
+ ptmpDdSurfaceGlobal->dwBlockSizeY = gpl->dwBlockSizeY;
+
+ if (lcl->dwFlags & DDRAWISURF_HASPIXELFORMAT)
+ {
+ RtlCopyMemory( &ptmpDdSurfaceGlobal->ddpfSurface ,
+ &gpl->ddpfSurface,
+ sizeof(DDPIXELFORMAT));
+
+ ptmpDdSurfaceGlobal->ddpfSurface.dwSize = sizeof(DDPIXELFORMAT);
+ }
+ else
+ {
+ RtlCopyMemory( &ptmpDdSurfaceGlobal->ddpfSurface ,
+ &gpl->lpDD->vmiData.ddpfDisplay,
+ sizeof(DDPIXELFORMAT));
+ }
+
+ /* Note if lcl->lpSurfMore is NULL zero out
+ * ptmpDdSurfaceMore->ddsCapsEx.dwCaps2,
+ * dwCaps3, dwCaps4, ptmpDdSurfaceMore->dwSurfaceHandle
+ */
+ if (lcl->lpSurfMore)
+ {
+ ptmpDdSurfaceMore->ddsCapsEx.dwCaps2 = lcl->lpSurfMore->ddsCapsEx.dwCaps2;
+ ptmpDdSurfaceMore->ddsCapsEx.dwCaps3 = lcl->lpSurfMore->ddsCapsEx.dwCaps3;
+ ptmpDdSurfaceMore->ddsCapsEx.dwCaps4 = lcl->lpSurfMore->ddsCapsEx.dwCaps4;
+ ptmpDdSurfaceMore->dwSurfaceHandle = lcl->lpSurfMore->dwSurfaceHandle;
+ }
+
+
+ /* count to next SurfaceCount */
+ ptmpDdSurfaceGlobal = (PDD_SURFACE_GLOBAL) (((PBYTE) ((ULONG_PTR) ptmpDdSurfaceGlobal)) + sizeof(DD_SURFACE_GLOBAL));
+ ptmpDdSurfaceLocal = (PDD_SURFACE_LOCAL) (((PBYTE) ((ULONG_PTR) ptmpDdSurfaceLocal)) + sizeof(DD_SURFACE_LOCAL));
+ ptmpDdSurfaceMore = (PDD_SURFACE_MORE) (((PBYTE) ((ULONG_PTR) ptmpDdSurfaceMore)) + sizeof(DD_SURFACE_MORE));
+ }
+ }
+
+ /* Call win32k now */
+ pCreateSurface->ddRVal = DDERR_GENERIC;
+
+ Return = NtGdiDdCreateSurface(GetDdHandle(pCreateSurface->lpDD->hDD),
+ (HANDLE *)phSurface,
+ pSurfaceDesc,
+ pDdSurfaceGlobal,
+ pDdSurfaceLocal,
+ pDdSurfaceMore,
+ (PDD_CREATESURFACEDATA)pCreateSurface,
+ puhSurface);
+
+ if (SurfaceCount == 0)
+ {
+ pCreateSurface->ddRVal = DDERR_GENERIC;
+ }
+ else
+ {
+ ptmpDdSurfaceMore = pDdSurfaceMore;
+ ptmpDdSurfaceGlobal = pDdSurfaceGlobal;
+ ptmpDdSurfaceLocal = pDdSurfaceLocal;
+
+ for (i=0; i<SurfaceCount; i++)
+ {
+ LPDDRAWI_DDRAWSURFACE_LCL lcl = pCreateSurface->lplpSList[i];
+ LPDDRAWI_DDRAWSURFACE_GBL gpl = pCreateSurface->lplpSList[i]->lpGbl;
+
+ gpl->lPitch = ptmpDdSurfaceGlobal->lPitch;
+ gpl->fpVidMem = ptmpDdSurfaceGlobal->fpVidMem;
+ gpl->dwBlockSizeX = ptmpDdSurfaceGlobal->dwBlockSizeX;
+ gpl->dwBlockSizeY = ptmpDdSurfaceGlobal->dwBlockSizeY;
+
+ if (lcl->dwFlags & DDRAWISURF_HASPIXELFORMAT)
+ {
+ RtlCopyMemory( &gpl->ddpfSurface, &ptmpDdSurfaceGlobal->ddpfSurface , sizeof(DDPIXELFORMAT));
+ }
+
+ if (pCreateSurface->ddRVal != DD_OK)
+ {
+ gpl->fpVidMem = 0;
+ if (lcl->hDDSurface)
+ {
+ NtGdiDdDeleteSurfaceObject( (HANDLE)lcl->hDDSurface);
+ }
+ lcl->hDDSurface = 0;
+ }
+ else
+ {
+
+ lcl->hDDSurface = (ULONG_PTR) puhSurface[i];
+ }
+
+ lcl->ddsCaps.dwCaps = ptmpDdSurfaceLocal->ddsCaps.dwCaps;
+ if (lcl->lpSurfMore)
+ {
+ lcl->lpSurfMore->ddsCapsEx.dwCaps2 = ptmpDdSurfaceMore->ddsCapsEx.dwCaps2;
+ lcl->lpSurfMore->ddsCapsEx.dwCaps3 = ptmpDdSurfaceMore->ddsCapsEx.dwCaps3;
+ lcl->lpSurfMore->ddsCapsEx.dwCaps4 = ptmpDdSurfaceMore->ddsCapsEx.dwCaps4;
+ }
+
+ /* count to next SurfaceCount */
+ ptmpDdSurfaceGlobal = (PDD_SURFACE_GLOBAL) (((PBYTE) ((ULONG_PTR) ptmpDdSurfaceGlobal)) + sizeof(DD_SURFACE_GLOBAL));
+ ptmpDdSurfaceLocal = (PDD_SURFACE_LOCAL) (((PBYTE) ((ULONG_PTR) ptmpDdSurfaceLocal)) + sizeof(DD_SURFACE_LOCAL));
+ ptmpDdSurfaceMore = (PDD_SURFACE_MORE) (((PBYTE) ((ULONG_PTR) ptmpDdSurfaceMore)) + sizeof(DD_SURFACE_MORE));
+ }
+ }
+
+ /* Check if we have to free all our local allocations */
+ if (SurfaceCount > 1)
+ {
+ if ( pDdSurfaceLocal != NULL )
+ {
+ HeapFree(GetProcessHeap(), 0, pDdSurfaceLocal);
+ }
+
+ if ( pDdSurfaceMore != NULL )
+ {
+ HeapFree(GetProcessHeap(), 0, pDdSurfaceMore);
+ }
+
+ if ( pDdSurfaceGlobal != NULL )
+ {
+ HeapFree(GetProcessHeap(), 0, pDdSurfaceGlobal);
+ }
+
+ if ( phSurface != NULL )
+ {
+ HeapFree(GetProcessHeap(), 0, phSurface);
+ }
+
+ if ( puhSurface != NULL )
+ {
+ HeapFree(GetProcessHeap(), 0, puhSurface);
+ }
+ }
+
+ /* Return */
+ return Return;
+}
+
+/*
+ * @implemented
+ *
+ * DdSetColorKey
+ */
+DWORD
+WINAPI
+DdSetColorKey(LPDDHAL_SETCOLORKEYDATA pSetColorKey)
+{
+ /* Call win32k */
+ return NtGdiDdSetColorKey((HANDLE)pSetColorKey->lpDDSurface->hDDSurface,
+ (PDD_SETCOLORKEYDATA)pSetColorKey);
+}
+
+/*
+ * @implemented
+ *
+ * DdGetScanLine
+ */
+DWORD
+WINAPI
+DdGetScanLine(LPDDHAL_GETSCANLINEDATA pGetScanLine)
+{
+ /* Call win32k */
+ return NtGdiDdGetScanLine(GetDdHandle(pGetScanLine->lpDD->hDD),
+ (PDD_GETSCANLINEDATA)pGetScanLine);
+}
+
+
+/*
+ * @implemented
+ *
+ * DvpCreateVideoPort
+ */
+BOOL
+WINAPI
+DvpCreateVideoPort(LPDDHAL_CREATEVPORTDATA pDvdCreatePort)
+{
+ pDvdCreatePort->lpVideoPort->hDDVideoPort =
+ NtGdiDvpCreateVideoPort(GetDdHandle(pDvdCreatePort->lpDD->lpGbl->hDD),
+ (PDD_CREATEVPORTDATA) pDvdCreatePort);
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ *
+ * DvpCreateVideoPort
+ */
+DWORD
+WINAPI
+DvpDestroyVideoPort(LPDDHAL_DESTROYVPORTDATA pDvdDestoryPort)
+{
+ return NtGdiDvpDestroyVideoPort(pDvdDestoryPort->lpVideoPort->hDDVideoPort, (PDD_DESTROYVPORTDATA)pDvdDestoryPort);
+}
+
+/*
+ * @implemented
+ *
+ * DvpCreateVideoPort
+ */
+DWORD
+WINAPI
+DvpFlipVideoPort(LPDDHAL_FLIPVPORTDATA pDvdPortFlip)
+{
+ return NtGdiDvpFlipVideoPort(pDvdPortFlip->lpVideoPort->hDDVideoPort,
+ (HANDLE)pDvdPortFlip->lpSurfCurr->hDDSurface,
+ (HANDLE)pDvdPortFlip->lpSurfTarg->hDDSurface,
+ (PDD_FLIPVPORTDATA) pDvdPortFlip);
+}
+
+/*
+ * @implemented
+ *
+ * DvpGetVideoPortBandwidth
+ */
+DWORD
+WINAPI
+DvpGetVideoPortBandwidth(LPDDHAL_GETVPORTBANDWIDTHDATA pDvdPortBandWidth)
+{
+ return NtGdiDvpGetVideoPortBandwidth(pDvdPortBandWidth->lpVideoPort->hDDVideoPort, (PDD_GETVPORTBANDWIDTHDATA)pDvdPortBandWidth);
+}
+
+/*
+ * @implemented
+ *
+ * DvpColorControl
+ */
+DWORD
+WINAPI
+DvpColorControl(LPDDHAL_VPORTCOLORDATA pDvdPortColorControl)
+{
+ return NtGdiDvpColorControl(pDvdPortColorControl->lpVideoPort->hDDVideoPort, (PDD_VPORTCOLORDATA) pDvdPortColorControl);
+}
+
+/*
+ * @implemented
+ *
+ * DvpGetVideoSignalStatus
+ */
+DWORD
+WINAPI
+DvpGetVideoSignalStatus(LPDDHAL_GETVPORTSIGNALDATA pDvdPortVideoSignalStatus)
+{
+ return NtGdiDvpGetVideoSignalStatus(pDvdPortVideoSignalStatus->lpVideoPort->hDDVideoPort, (PDD_GETVPORTSIGNALDATA) pDvdPortVideoSignalStatus);
+}
+
+/*
+ * @implemented
+ *
+ * DvpGetVideoPortFlipStatus
+ */
+DWORD
+WINAPI
+DvpGetVideoPortFlipStatus(LPDDHAL_GETVPORTFLIPSTATUSDATA pDvdPortVideoPortFlipStatus)
+{
+ return NtGdiDvpGetVideoPortFlipStatus(GetDdHandle(pDvdPortVideoPortFlipStatus->lpDD->lpGbl->hDD), (PDD_GETVPORTFLIPSTATUSDATA) pDvdPortVideoPortFlipStatus);
+
+}
+
+/*
+ * @implemented
+ *
+ * DvpCanCreateVideoPort
+ */
+DWORD
+WINAPI
+DvpCanCreateVideoPort(LPDDHAL_CANCREATEVPORTDATA pDvdCanCreateVideoPort)
+{
+ return NtGdiDvpCanCreateVideoPort(GetDdHandle(pDvdCanCreateVideoPort->lpDD->lpGbl->hDD), (PDD_CANCREATEVPORTDATA) pDvdCanCreateVideoPort);
+}
+/*
+ * @implemented
+ *
+ * DvpWaitForVideoPortSync
+ */
+DWORD
+WINAPI
+DvpWaitForVideoPortSync(LPDDHAL_WAITFORVPORTSYNCDATA pDvdWaitForVideoPortSync)
+{
+ return NtGdiDvpWaitForVideoPortSync(pDvdWaitForVideoPortSync->lpVideoPort->hDDVideoPort, (PDD_WAITFORVPORTSYNCDATA) pDvdWaitForVideoPortSync);
+}
+
+/*
+ * @implemented
+ *
+ * DvpUpdateVideoPort
+ */
+DWORD
+WINAPI
+DvpUpdateVideoPort(LPDDHAL_UPDATEVPORTDATA pDvdUpdateVideoPort)
+{
+ /*
+ * Windows XP limit to max 10 handles of videoport surface and Vbi
+ * ReactOS doing same to keep compatible, if it is more that 10
+ * videoport surface or vbi the stack will be curpted in windows xp
+ * ReactOS safe guard againts that
+ *
+ */
+
+ HANDLE phSurfaceVideo[10];
+ HANDLE phSurfaceVbi[10];
+
+ if (pDvdUpdateVideoPort->dwFlags != DDRAWI_VPORTSTOP)
+ {
+ DWORD dwNumAutoflip;
+ DWORD dwNumVBIAutoflip;
+
+ /* Take copy of lplpDDSurface for the handle value will be modify in dxg */
+ dwNumAutoflip = pDvdUpdateVideoPort->dwNumAutoflip;
+ if ((dwNumAutoflip == 0) &&
+ (pDvdUpdateVideoPort->lplpDDSurface == 0))
+ {
+ dwNumAutoflip++;
+ }
+
+ if (dwNumAutoflip != 0)
+ {
+ if (dwNumAutoflip>10)
+ {
+ dwNumAutoflip = 10;
+ }
+ memcpy(phSurfaceVideo,pDvdUpdateVideoPort->lplpDDSurface,dwNumAutoflip*sizeof(HANDLE));
+ }
+
+ /* Take copy of lplpDDVBISurface for the handle value will be modify in dxg */
+ dwNumVBIAutoflip = pDvdUpdateVideoPort->dwNumVBIAutoflip;
+ if ( (dwNumVBIAutoflip == 0) &&
+ (pDvdUpdateVideoPort->lplpDDVBISurface == 0) )
+ {
+ dwNumVBIAutoflip++;
+ }
+
+ if (dwNumVBIAutoflip != 0)
+ {
+ if (dwNumVBIAutoflip>10)
+ {
+ dwNumVBIAutoflip = 10;
+ }
+ memcpy(phSurfaceVbi,pDvdUpdateVideoPort->lplpDDVBISurface,dwNumVBIAutoflip*sizeof(HANDLE));
+ }
+ }
+
+ /* Call Win32k */
+ return NtGdiDvpUpdateVideoPort(pDvdUpdateVideoPort->lpVideoPort->hDDVideoPort,phSurfaceVideo,phSurfaceVbi, (PDD_UPDATEVPORTDATA)pDvdUpdateVideoPort);
+}
+
+/*
+ * @implemented
+ *
+ * DvpWaitForVideoPortSync
+ */
+DWORD
+WINAPI
+DvpGetVideoPortField(LPDDHAL_FLIPVPORTDATA pDvdGetVideoPortField)
+{
+ return NtGdiDvpGetVideoPortField(pDvdGetVideoPortField->lpVideoPort->hDDVideoPort, (PDD_GETVPORTFIELDDATA)pDvdGetVideoPortField);
+}
+
+/*
+ * @implemented
+ *
+ * DvpWaitForVideoPortSync
+ */
+DWORD
+WINAPI
+DvpGetVideoPortInputFormats(LPDDHAL_GETVPORTINPUTFORMATDATA pDvdGetVideoPortInputFormat)
+{
+ return NtGdiDvpGetVideoPortInputFormats(pDvdGetVideoPortInputFormat->lpVideoPort->hDDVideoPort, (PDD_GETVPORTINPUTFORMATDATA) pDvdGetVideoPortInputFormat);
+}
+
+/*
+ * @implemented
+ *
+ * DvpGetVideoPortLine
+ */
+DWORD
+WINAPI
+DvpGetVideoPortLine(LPDDHAL_GETVPORTLINEDATA pDvdGetVideoPortLine)
+{
+ return NtGdiDvpGetVideoPortLine(pDvdGetVideoPortLine->lpVideoPort->hDDVideoPort, (PDD_GETVPORTLINEDATA)pDvdGetVideoPortLine);
+}
+
+/*
+ * @implemented
+ *
+ * DvpGetVideoPortOutputFormats
+ */
+DWORD
+WINAPI
+DvpGetVideoPortOutputFormats(LPDDHAL_GETVPORTLINEDATA pDvdGetVideoPortOutputFormat)
+{
+ return NtGdiDvpGetVideoPortLine(pDvdGetVideoPortOutputFormat->lpVideoPort->hDDVideoPort, (PDD_GETVPORTLINEDATA)pDvdGetVideoPortOutputFormat);
+}
+
+/*
+ * @implemented
+ *
+ * DvpGetVideoPortConnectInfo
+ */
+DWORD
+WINAPI
+DvpGetVideoPortConnectInfo(LPDDHAL_GETVPORTCONNECTDATA pDvdGetVideoPortInfo)
+{
+ return NtGdiDvpGetVideoPortConnectInfo( GetDdHandle( pDvdGetVideoPortInfo->lpDD->lpGbl->hDD) , (PDD_GETVPORTCONNECTDATA) pDvdGetVideoPortInfo);
+}
+
+/*
+ * @implemented
+ *
+ * DdGetAvailDriverMemory
+ */
+DWORD
+WINAPI
+DdGetAvailDriverMemory(LPDDHAL_GETAVAILDRIVERMEMORYDATA pDdGetAvailDriverMemory)
+{
+ return NtGdiDdGetAvailDriverMemory(GetDdHandle( pDdGetAvailDriverMemory->lpDD->hDD), (PDD_GETAVAILDRIVERMEMORYDATA) pDdGetAvailDriverMemory);
+}
+
+/*
+ * @implemented
+ *
+ * DdAlphaBlt
+ */
+DWORD
+WINAPI
+DdAlphaBlt(LPDDHAL_BLTDATA pDdAlphaBlt)
+{
+ HANDLE hDDSrcSurface = 0;
+
+ if (pDdAlphaBlt->lpDDSrcSurface != 0)
+ {
+ hDDSrcSurface = (HANDLE) pDdAlphaBlt->lpDDSrcSurface->hDDSurface;
+ }
+
+ return NtGdiDdAlphaBlt((HANDLE)pDdAlphaBlt->lpDDDestSurface->hDDSurface, hDDSrcSurface, (PDD_BLTDATA)&pDdAlphaBlt);
+}
+
+/*
+ * @implemented
+ *
+ * DdCreateSurfaceEx
+ */
+DWORD
+WINAPI
+DdCreateSurfaceEx(LPDDHAL_CREATESURFACEEXDATA pDdCreateSurfaceEx)
+{
+ pDdCreateSurfaceEx->ddRVal = NtGdiDdCreateSurfaceEx( GetDdHandle(pDdCreateSurfaceEx->lpDDLcl->lpGbl->hDD),
+ (HANDLE)pDdCreateSurfaceEx->lpDDSLcl->hDDSurface,
+ pDdCreateSurfaceEx->lpDDSLcl->lpSurfMore->dwSurfaceHandle);
+ return TRUE;
+}
+
+/*
+ * @implemented
+ *
+ * DdColorControl
+ */
+DWORD
+WINAPI
+DdColorControl(LPDDHAL_COLORCONTROLDATA pDdColorControl)
+{
+ return NtGdiDdColorControl( (HANDLE) pDdColorControl->lpDDSurface->hDDSurface, (PDD_COLORCONTROLDATA) &pDdColorControl);
+}
+
+/*
+ * @implemented
+ *
+ * DdSetExclusiveMode
+ */
+DWORD
+WINAPI
+DdSetExclusiveMode(LPDDHAL_SETEXCLUSIVEMODEDATA pDdSetExclusiveMode)
+{
+ return NtGdiDdSetExclusiveMode( GetDdHandle(pDdSetExclusiveMode->lpDD->hDD), (PDD_SETEXCLUSIVEMODEDATA) &pDdSetExclusiveMode);
+}
+
+/*
+ * @implemented
+ *
+ * DdFlipToGDISurface
+ */
+DWORD
+WINAPI
+DdFlipToGDISurface(LPDDHAL_FLIPTOGDISURFACEDATA pDdFlipToGDISurface)
+{
+ return NtGdiDdFlipToGDISurface( GetDdHandle(pDdFlipToGDISurface->lpDD->hDD), (PDD_FLIPTOGDISURFACEDATA) &pDdFlipToGDISurface);
+}
+
+/* TODO */
+DWORD
+WINAPI
+DdGetDriverInfo(LPDDHAL_GETDRIVERINFODATA pData)
+{
+ DDHAL_GETDRIVERINFODATA pDrvInfoData;
+ DWORD retValue = DDHAL_DRIVER_NOTHANDLED;
+ HANDLE hDD;
+
+ /* FIXME add SEH around this functions */
+
+ RtlZeroMemory(&pDrvInfoData, sizeof (DDHAL_GETDRIVERINFODATA));
+ RtlCopyMemory(&pDrvInfoData.guidInfo, &pData->guidInfo, sizeof(GUID));
+
+ hDD = GetDdHandle(pData->dwContext);
+
+ pDrvInfoData.dwSize = sizeof (DDHAL_GETDRIVERINFODATA);
+ pDrvInfoData.ddRVal = DDERR_GENERIC;
+ pDrvInfoData.dwContext = (ULONG_PTR)hDD;
+
+
+ /* Videoport Callbacks check and setup for DirectX/ ReactX */
+ if (IsEqualGUID(&pData->guidInfo, &GUID_VideoPortCallbacks))
+ {
+ DDHAL_DDVIDEOPORTCALLBACKS pDvdPort;
+ DDHAL_DDVIDEOPORTCALLBACKS* pUserDvdPort = (DDHAL_DDVIDEOPORTCALLBACKS *)pData->lpvData;
+
+ /* Clear internal out buffer and set it up*/
+ RtlZeroMemory(&pDvdPort, DDVIDEOPORTCALLBACKSSIZE);
+ pDvdPort.dwSize = DDVIDEOPORTCALLBACKSSIZE;
+
+ /* set up internal buffer */
+ pDrvInfoData.lpvData = (PVOID)&pDvdPort;
+ pDrvInfoData.dwExpectedSize = DDVIDEOPORTCALLBACKSSIZE ;
+
+ /* Call win32k */
+ retValue = NtGdiDdGetDriverInfo(hDD, (PDD_GETDRIVERINFODATA)&pDrvInfoData);
+
+ /* Setup user out buffer and convert kmode callbacks to user mode */
+ pUserDvdPort->dwSize = DDVIDEOPORTCALLBACKSSIZE;
+ pUserDvdPort->dwFlags = pDrvInfoData.dwFlags = 0;
+
+ pUserDvdPort->dwFlags = (pDrvInfoData.dwFlags & ~(DDHAL_VPORT32_CREATEVIDEOPORT | DDHAL_VPORT32_FLIP |
+ DDHAL_VPORT32_DESTROY | DDHAL_VPORT32_UPDATE | DDHAL_VPORT32_WAITFORSYNC)) |
+ (DDHAL_VPORT32_CREATEVIDEOPORT | DDHAL_VPORT32_FLIP |
+ DDHAL_VPORT32_DESTROY | DDHAL_VPORT32_UPDATE);
+
+ pData->dwActualSize = DDVIDEOPORTCALLBACKSSIZE;
+ pUserDvdPort->CreateVideoPort = (LPDDHALVPORTCB_CREATEVIDEOPORT) DvpCreateVideoPort;
+ pUserDvdPort->FlipVideoPort = (LPDDHALVPORTCB_FLIP) DvpFlipVideoPort;
+ pUserDvdPort->DestroyVideoPort = (LPDDHALVPORTCB_DESTROYVPORT) DvpDestroyVideoPort;
+ pUserDvdPort->UpdateVideoPort = (LPDDHALVPORTCB_UPDATE) DvpUpdateVideoPort;
+
+ if (pDvdPort.CanCreateVideoPort)
+ {
+ pUserDvdPort->CanCreateVideoPort = (LPDDHALVPORTCB_CANCREATEVIDEOPORT) DvpCanCreateVideoPort;
+ }
+
+ if (pDvdPort.GetVideoPortBandwidth)
+ {
+ pUserDvdPort->GetVideoPortBandwidth = (LPDDHALVPORTCB_GETBANDWIDTH) DvpGetVideoPortBandwidth;
+ }
+
+ if (pDvdPort.GetVideoPortInputFormats)
+ {
+ pUserDvdPort->GetVideoPortInputFormats = (LPDDHALVPORTCB_GETINPUTFORMATS) DvpGetVideoPortInputFormats;
+ }
+
+ if (pDvdPort.GetVideoPortOutputFormats)
+ {
+ pUserDvdPort->GetVideoPortOutputFormats = (LPDDHALVPORTCB_GETOUTPUTFORMATS) DvpGetVideoPortOutputFormats;
+ }
+
+ if (pDvdPort.GetVideoPortField)
+ {
+ pUserDvdPort->GetVideoPortField = (LPDDHALVPORTCB_GETFIELD) DvpGetVideoPortField;
+ }
+
+ if (pDvdPort.GetVideoPortLine)
+ {
+ pUserDvdPort->GetVideoPortLine = (LPDDHALVPORTCB_GETLINE) DvpGetVideoPortLine;
+ }
+
+ if (pDvdPort.GetVideoPortConnectInfo)
+ {
+ pUserDvdPort->GetVideoPortConnectInfo = (LPDDHALVPORTCB_GETVPORTCONNECT) DvpGetVideoPortConnectInfo;
+ }
+
+ if (pDvdPort.GetVideoPortFlipStatus)
+ {
+ pUserDvdPort->GetVideoPortFlipStatus = (LPDDHALVPORTCB_GETFLIPSTATUS) DvpGetVideoPortFlipStatus;
+ }
+
+ if (pDvdPort.WaitForVideoPortSync)
+ {
+ pUserDvdPort->WaitForVideoPortSync = (LPDDHALVPORTCB_WAITFORSYNC) DvpWaitForVideoPortSync;
+ }
+
+ if (pDvdPort.GetVideoSignalStatus)
+ {
+ pUserDvdPort->GetVideoSignalStatus = (LPDDHALVPORTCB_GETSIGNALSTATUS) DvpGetVideoSignalStatus;
+ }
+
+ if (pDvdPort.ColorControl)
+ {
+ pUserDvdPort->ColorControl = (LPDDHALVPORTCB_COLORCONTROL) DvpColorControl;
+ }
+
+ /* Windows XP never repot back the true return value,
+ * it only report back if we have a driver or not
+ * ReactOS keep this behoir to be compatible with
+ * Windows XP
+ */
+ pData->ddRVal = retValue;
+ }
+
+ /* Color Control Callbacks check and setup for DirectX/ ReactX */
+ if (IsEqualGUID(&pData->guidInfo, &GUID_ColorControlCallbacks))
+ {
+ DDHAL_DDCOLORCONTROLCALLBACKS pColorControl;
+ DDHAL_DDCOLORCONTROLCALLBACKS* pUserColorControl = (DDHAL_DDCOLORCONTROLCALLBACKS *)pData->lpvData;
+
+ /* Clear internal out buffer and set it up*/
+ RtlZeroMemory(&pColorControl, DDCOLORCONTROLCALLBACKSSIZE);
+ pColorControl.dwSize = DDCOLORCONTROLCALLBACKSSIZE;
+
+ /* set up internal buffer */
+ pDrvInfoData.lpvData = (PVOID)&pColorControl;
+ pDrvInfoData.dwExpectedSize = DDCOLORCONTROLCALLBACKSSIZE ;
+
+ /* Call win32k */
+ retValue = NtGdiDdGetDriverInfo(hDD, (PDD_GETDRIVERINFODATA)&pDrvInfoData);
+
+ pData->dwActualSize = DDCOLORCONTROLCALLBACKSSIZE;
+ pData->dwFlags = pDrvInfoData.dwFlags;
+
+ pUserColorControl->dwSize = DDCOLORCONTROLCALLBACKSSIZE;
+ pUserColorControl->dwFlags = pColorControl.dwFlags;
+
+ if (pColorControl.ColorControl != NULL)
+ {
+ pUserColorControl->ColorControl = (LPDDHALCOLORCB_COLORCONTROL) DdColorControl;
+ }
+
+ /* Windows XP never repot back the true return value,
+ * it only report back if we have a driver or not
+ * ReactOS keep this behoir to be compatible with
+ * Windows XP
+ */
+ pData->ddRVal = retValue;
+ }
+
+ /* Misc Callbacks check and setup for DirectX/ ReactX */
+ else if (IsEqualGUID(&pData->guidInfo, &GUID_MiscellaneousCallbacks))
+ {
+ DDHAL_DDMISCELLANEOUSCALLBACKS pMisc;
+ DDHAL_DDMISCELLANEOUSCALLBACKS* pUserMisc = (DDHAL_DDMISCELLANEOUSCALLBACKS *)pData->lpvData;
+
+ /* Clear internal out buffer and set it up*/
+ RtlZeroMemory(&pMisc, DDMISCELLANEOUSCALLBACKSSIZE);
+ pMisc.dwSize = DDMISCELLANEOUSCALLBACKSSIZE;
+
+ /* set up internal buffer */
+ pDrvInfoData.lpvData = (PVOID)&pMisc;
+ pDrvInfoData.dwExpectedSize = DDMISCELLANEOUSCALLBACKSSIZE ;
+
+ /* Call win32k */
+ retValue = NtGdiDdGetDriverInfo(hDD, (PDD_GETDRIVERINFODATA)&pDrvInfoData);
+
+ pData->dwActualSize = DDMISCELLANEOUSCALLBACKSSIZE;
+
+ /* Only one callbacks are supported */
+ pUserMisc->dwFlags = pMisc.dwFlags & DDHAL_MISCCB32_GETAVAILDRIVERMEMORY;
+ pUserMisc->GetAvailDriverMemory = (LPDDHAL_GETAVAILDRIVERMEMORY) DdGetAvailDriverMemory;
+
+ /* This callbacks are only for win9x and theirfor it is not longer use in NT or ReactOS
+ * pUserMisc->UpdateNonLocalHeap;
+ * pUserMisc->GetHeapAlignment;
+ * pUserMisc->GetSysmemBltStatus; */
+
+ /* Windows XP never repot back the true return value,
+ * it only report back if we have a driver or not
+ * ReactOS keep this behoir to be compatible with
+ * Windows XP
+ */
+ pData->ddRVal = retValue;
+ }
+
+ /* Misc 2 Callbacks check and setup for DirectX/ ReactX */
+ else if (IsEqualGUID(&pData->guidInfo, &GUID_Miscellaneous2Callbacks))
+ {
+ DDHAL_DDMISCELLANEOUS2CALLBACKS pMisc;
+ DDHAL_DDMISCELLANEOUS2CALLBACKS* pUserMisc = (DDHAL_DDMISCELLANEOUS2CALLBACKS *)pData->lpvData;
+
+ /* Clear internal out buffer and set it up*/
+ RtlZeroMemory(&pMisc, DDMISCELLANEOUS2CALLBACKSSIZE);
+ pMisc.dwSize = DDMISCELLANEOUS2CALLBACKSSIZE;
+
+ /* set up internal buffer */
+ pDrvInfoData.lpvData = (PVOID)&pMisc;
+ pDrvInfoData.dwExpectedSize = DDMISCELLANEOUS2CALLBACKSSIZE ;
+
+ /* Call win32k */
+ retValue = NtGdiDdGetDriverInfo(hDD, (PDD_GETDRIVERINFODATA)&pDrvInfoData);
+
+ pData->dwActualSize = DDMISCELLANEOUS2CALLBACKSSIZE;
+
+ pUserMisc->dwFlags = pMisc.dwFlags;
+
+ /* This functions are not documneted in MSDN for this struct, here is directx/reactx alpha blend */
+ if ( pMisc.Reserved )
+ {
+ pUserMisc->Reserved = (LPVOID) DdAlphaBlt;
+ }
+
+ if ( pMisc.CreateSurfaceEx )
+ {
+ pUserMisc->CreateSurfaceEx = (LPDDHAL_CREATESURFACEEX) DdCreateSurfaceEx;
+ }
+
+ if ( pMisc.GetDriverState )
+ {
+ pUserMisc->GetDriverState = (LPDDHAL_GETDRIVERSTATE) NtGdiDdGetDriverState;
+ }
+
+ /* NOTE : pUserMisc->DestroyDDLocal is outdated and are not beign tuch */
+
+ /* Windows XP never repot back the true return value,
+ * it only report back if we have a driver or not
+ * ReactOS keep this behoir to be compatible with
+ * Windows XP
+ */
+ pData->ddRVal = retValue;
+ }
+
+ /* NT Callbacks check and setup for DirectX/ ReactX */
+ else if (IsEqualGUID(&pData->guidInfo, &GUID_NTCallbacks))
+ {
+ /* MS does not have DHAL_* version of this callbacks
+ * so we are force using PDD_* callbacks here
+ */
+ DD_NTCALLBACKS pNtKernel;
+ PDD_NTCALLBACKS pUserNtKernel = (PDD_NTCALLBACKS)pData->lpvData;
+
+ /* Clear internal out buffer and set it up*/
+ RtlZeroMemory(&pNtKernel, sizeof(DD_NTCALLBACKS));
+ pNtKernel.dwSize = sizeof(DD_NTCALLBACKS);
+
+ /* set up internal buffer */
+ pDrvInfoData.lpvData = (PVOID)&pNtKernel;
+ pDrvInfoData.dwExpectedSize = sizeof(DD_NTCALLBACKS) ;
+
+ /* Call win32k */
+ retValue = NtGdiDdGetDriverInfo(hDD, (PDD_GETDRIVERINFODATA)&pDrvInfoData);
+
+ pData->dwActualSize = sizeof(DD_NTCALLBACKS);
+
+ pUserNtKernel->dwSize = sizeof(DD_NTCALLBACKS);
+ pUserNtKernel->dwFlags = pNtKernel.dwFlags;
+ pUserNtKernel->FreeDriverMemory = 0;
+
+ if (pNtKernel.SetExclusiveMode)
+ {
+ pUserNtKernel->SetExclusiveMode = (PDD_SETEXCLUSIVEMODE) DdSetExclusiveMode;
+ }
+
+ if (pNtKernel.FlipToGDISurface)
+ {
+ pUserNtKernel->FlipToGDISurface = (PDD_FLIPTOGDISURFACE) DdFlipToGDISurface;
+ }
+
+ /* Windows XP never repot back the true return value,
+ * it only report back if we have a driver or not
+ * ReactOS keep this behoir to be compatible with
+ * Windows XP
+ */
+ pData->ddRVal = retValue;
+ }
+
+ /* D3D Callbacks version 2 check and setup for DirectX/ ReactX */
+ else if (IsEqualGUID(&pData->guidInfo, &GUID_D3DCallbacks2))
+ {
+ // FIXME GUID_D3DCallbacks2
+ }
+
+ /* D3D Callbacks version 3 check and setup for DirectX/ ReactX */
+ else if (IsEqualGUID(&pData->guidInfo, &GUID_D3DCallbacks3))
+ {
+ // FIXME GUID_D3DCallbacks3
+ }
+
+ /* D3DParseUnknownCommand Callbacks check and setup for DirectX/ ReactX */
+ else if (IsEqualGUID(&pData->guidInfo, &GUID_D3DParseUnknownCommandCallback))
+ {
+ // FIXME GUID_D3DParseUnknownCommandCallback
+ }
+
+ /* MotionComp Callbacks check and setup for DirectX/ ReactX */
+ else if (IsEqualGUID(&pData->guidInfo, &GUID_MotionCompCallbacks))
+ {
+ // FIXME GUID_MotionCompCallbacks
+ }
+
+ /* FIXME VPE2 Callbacks check and setup for DirectX/ ReactX */
+ //else if (IsEqualGUID(&pData->guidInfo, &GUID_VPE2Callbacks))
+ //{
+ // FIXME GUID_VPE2Callbacks
+ //}
+ else
+ {
+ /* set up internal buffer */
+ pDrvInfoData.dwExpectedSize = pData->dwExpectedSize;
+ pDrvInfoData.lpvData = pData->lpvData;
+
+ /* We do not cover all callbacks for user mode, they are only cover by kmode */
+ retValue = NtGdiDdGetDriverInfo(hDD, (PDD_GETDRIVERINFODATA)&pDrvInfoData);
+
+ /* Setup return data */
+ pData->dwActualSize = pDrvInfoData.dwActualSize;
+ pData->lpvData = pDrvInfoData.lpvData;
+ /* Windows XP never repot back the true return value,
+ * it only report back if we have a driver or not
+ * ReactOS keep this behoir to be compatible with
+ * Windows XP
+ */
+ pData->ddRVal = retValue;
+ }
+
+ return retValue;
+}
+
+
+/*
+ * @implemented
+ *
+ * D3dContextCreate
+ */
+BOOL
+WINAPI
+D3dContextCreate(LPD3DHAL_CONTEXTCREATEDATA pdcci)
+{
+ HANDLE hSurfZ = NULL;
+
+ if (pdcci->lpDDSZLcl)
+ {
+ hSurfZ = (HANDLE)pdcci->lpDDSZLcl->hDDSurface;
+ }
+
+ return NtGdiD3dContextCreate(GetDdHandle(pdcci->lpDDLcl->hDD),
+ (HANDLE)pdcci->lpDDSLcl->hDDSurface,
+ hSurfZ,
+ (D3DNTHAL_CONTEXTCREATEI *)pdcci);
+}
+
+/*
+ * @implemented
+ *
+ * DdCanCreateD3DBuffer
+ */
+DWORD
+WINAPI
+DdCanCreateD3DBuffer(LPDDHAL_CANCREATESURFACEDATA CanCreateD3DBuffer)
+{
+ /*
+ * Note : This functions are basic same, in win32k
+ * NtGdiDdCanCreateD3DBuffer and NtGdiDdCanCreateSurface are mergs
+ * toghter in win32k at end and retrurn same data, it is still sepreated
+ * at user mode but in kmode it is not.
+ */
+
+ /* Call win32k */
+ return NtGdiDdCanCreateD3DBuffer(GetDdHandle(CanCreateD3DBuffer->lpDD->hDD),
+ (PDD_CANCREATESURFACEDATA)CanCreateD3DBuffer);
+}
+
+
+/*
+ * @implemented
+ *
+ * DdCreateD3DBuffer
+ */
+DWORD
+WINAPI
+DdCreateD3DBuffer(LPDDHAL_CREATESURFACEDATA pCreateSurface)
+{
+ HANDLE puhSurface = 0;
+ DDRAWI_DDRAWSURFACE_GBL *pSurfGBL;
+ DDRAWI_DDRAWSURFACE_LCL *pSurfLcl;
+ DD_SURFACE_GLOBAL puSurfaceGlobalData;
+ DD_SURFACE_MORE puSurfaceMoreData;
+ DD_SURFACE_LOCAL puSurfaceLocalData;
+ DWORD retValue;
+
+ /* Zero all local memory pointer */
+ RtlZeroMemory(&puSurfaceGlobalData, sizeof(DD_SURFACE_GLOBAL) );
+ RtlZeroMemory(&puSurfaceMoreData, sizeof(DD_SURFACE_MORE) ) ;
+ RtlZeroMemory(&puSurfaceLocalData, sizeof(DD_SURFACE_LOCAL) );
+
+ pCreateSurface->dwSCnt = 1;
+ pSurfLcl = pCreateSurface->lplpSList[0];
+ pSurfGBL = pSurfLcl->lpGbl;
+
+ /* Convert DDRAWI_DDRAWSURFACE_GBL to DD_SURFACE_GLOBAL */
+ puSurfaceGlobalData.wWidth = pSurfGBL->wWidth;
+ puSurfaceGlobalData.wHeight = pSurfGBL->wHeight;
+ puSurfaceGlobalData.dwLinearSize = pSurfGBL->dwLinearSize;
+ puSurfaceGlobalData.fpVidMem = pSurfGBL->fpVidMem;
+ puSurfaceGlobalData.dwBlockSizeX = pSurfGBL->dwBlockSizeX;
+ puSurfaceGlobalData.dwBlockSizeY = pSurfGBL->dwBlockSizeY;
+
+ /* Convert DDRAWI_DDRAWSURFACE_MORE to DD_SURFACE_MORE */
+ puSurfaceMoreData.dwSurfaceHandle = pSurfLcl->lpSurfMore->dwSurfaceHandle;
+ puSurfaceMoreData.ddsCapsEx.dwCaps2 = pSurfLcl->lpSurfMore->ddsCapsEx.dwCaps2;
+ puSurfaceMoreData.ddsCapsEx.dwCaps3 = pSurfLcl->lpSurfMore->ddsCapsEx.dwCaps3;
+ puSurfaceMoreData.ddsCapsEx.dwCaps4 = pSurfLcl->lpSurfMore->ddsCapsEx.dwCaps4;
+
+ /* Convert DDRAWI_DDRAWSURFACE_LCL to DD_SURFACE_LOCAL */
+ puSurfaceLocalData.dwFlags = pSurfLcl->dwFlags;
+ puSurfaceLocalData.ddsCaps.dwCaps = pSurfLcl->ddsCaps.dwCaps;
+
+ /* Call win32k */
+ retValue = NtGdiDdCreateD3DBuffer( GetDdHandle(pCreateSurface->lpDD->hDD),
+ (HANDLE*)&pSurfLcl->hDDSurface,
+ pCreateSurface->lpDDSurfaceDesc,
+ &puSurfaceGlobalData,
+ &puSurfaceLocalData,
+ &puSurfaceMoreData,
+ (DD_CREATESURFACEDATA *) pCreateSurface,
+ &puhSurface);
+
+ /* Setup surface handle if we got one back */
+ if ( puhSurface != NULL )
+ {
+ pCreateSurface->lplpSList[0]->hDDSurface = (ULONG_PTR)puhSurface;
+ }
+
+ /* Convert DD_SURFACE_GLOBAL to DDRAWI_DDRAWSURFACE_GBL */
+ pSurfGBL->dwLinearSize = puSurfaceGlobalData.dwLinearSize;
+ pSurfGBL->fpVidMem = puSurfaceGlobalData.fpVidMem;
+ pSurfGBL->dwBlockSizeX = puSurfaceGlobalData.dwBlockSizeX;
+ pSurfGBL->dwBlockSizeY = puSurfaceGlobalData.dwBlockSizeY;
+
+ return retValue;
+}
+
+/*
+ * @implemented
+ *
+ * DdDestroyD3DBuffer
+ */
+DWORD
+WINAPI
+DdDestroyD3DBuffer(LPDDHAL_DESTROYSURFACEDATA pDestroySurface)
+{
+ DWORD retValue = 0;
+ if ( pDestroySurface->lpDDSurface->hDDSurface)
+ {
+ /* Call win32k */
+ retValue = NtGdiDdDestroyD3DBuffer((HANDLE)pDestroySurface->lpDDSurface->hDDSurface);
+ }
+
+ return retValue;
+}
+
+/*
+ * @implemented
+ *
+ * DdLockD3D
+ */
+DWORD
+WINAPI
+DdLockD3D(LPDDHAL_LOCKDATA Lock)
+{
+
+ /* Call win32k */
+ return NtGdiDdLockD3D((HANDLE)Lock->lpDDSurface->hDDSurface, (PDD_LOCKDATA)Lock);
+}
+
+/*
+ * @implemented
+ *
+ * DdUnlockD3D
+ */
+DWORD
+WINAPI
+DdUnlockD3D(LPDDHAL_UNLOCKDATA Unlock)
+{
+ /* Call win32k */
+ return NtGdiDdUnlock((HANDLE)Unlock->lpDDSurface->hDDSurface,
+ (PDD_UNLOCKDATA)Unlock);
+}
+
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+BOOL
+WINAPI
+bDDCreateSurface(LPDDRAWI_DDRAWSURFACE_LCL pSurface,
+ BOOL bComplete)
+{
+ DD_SURFACE_LOCAL SurfaceLocal;
+ DD_SURFACE_GLOBAL SurfaceGlobal;
+ DD_SURFACE_MORE SurfaceMore;
+
+ /* Zero struct */
+ RtlZeroMemory(&SurfaceLocal, sizeof(DD_SURFACE_LOCAL));
+ RtlZeroMemory(&SurfaceGlobal, sizeof(DD_SURFACE_GLOBAL));
+ RtlZeroMemory(&SurfaceMore, sizeof(DD_SURFACE_MORE));
+
+ /* Set up SurfaceLocal struct */
+ SurfaceLocal.ddsCaps.dwCaps = pSurface->ddsCaps.dwCaps;
+ SurfaceLocal.dwFlags = pSurface->dwFlags;
+
+ /* Set up SurfaceMore struct */
+ RtlMoveMemory(&SurfaceMore.ddsCapsEx,
+ &pSurface->ddckCKDestBlt,
+ sizeof(DDSCAPSEX));
+ SurfaceMore.dwSurfaceHandle = (DWORD)pSurface->dbnOverlayNode.object_int->lpVtbl;
+
+ /* Set up SurfaceGlobal struct */
+ SurfaceGlobal.fpVidMem = pSurface->lpGbl->fpVidMem;
+ SurfaceGlobal.dwLinearSize = pSurface->lpGbl->dwLinearSize;
+ SurfaceGlobal.wHeight = pSurface->lpGbl->wHeight;
+ SurfaceGlobal.wWidth = pSurface->lpGbl->wWidth;
+
+ /* Check if we have a pixel format */
+ if (pSurface->dwFlags & DDSD_PIXELFORMAT)
+ {
+ /* Use global one */
+ SurfaceGlobal.ddpfSurface = pSurface->lpGbl->lpDD->vmiData.ddpfDisplay;
+ SurfaceGlobal.ddpfSurface.dwSize = sizeof(DDPIXELFORMAT);
+ }
+ else
+ {
+ /* Use local one */
+ SurfaceGlobal.ddpfSurface = pSurface->lpGbl->lpDD->vmiData.ddpfDisplay;
+ }
+
+ /* Create the object */
+ pSurface->hDDSurface = (DWORD)NtGdiDdCreateSurfaceObject(GetDdHandle(pSurface->lpGbl->lpDD->hDD),
+ (HANDLE)pSurface->hDDSurface,
+ &SurfaceLocal,
+ &SurfaceMore,
+ &SurfaceGlobal,
+ bComplete);
+
+ /* Return status */
+ if (pSurface->hDDSurface) return TRUE;
+ return FALSE;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*
+ * @implemented
+ *
+ * GDIEntry 1
+ */
+BOOL
+WINAPI
+DdCreateDirectDrawObject(LPDDRAWI_DIRECTDRAW_GBL pDirectDrawGlobal,
+ HDC hdc)
+{
+ BOOL Return = FALSE;
+
+ /* Check if the global hDC (hdc == 0) is being used */
+ if (!hdc)
+ {
+ /* We'll only allow this if the global object doesn't exist yet */
+ if (!ghDirectDraw)
+ {
+ /* Create the DC */
+ if ((hdc = CreateDCW(L"Display", NULL, NULL, NULL)))
+ {
+ /* Create the DDraw Object */
+ ghDirectDraw = NtGdiDdCreateDirectDrawObject(hdc);
+
+ /* Delete our DC */
+ DeleteDC(hdc);
+ }
+ }
+
+ /* If we created the object, or had one ...*/
+ if (ghDirectDraw)
+ {
+ /* Increase count and set success */
+ gcDirectDraw++;
+ Return = TRUE;
+ }
+
+ /* Zero the handle */
+ pDirectDrawGlobal->hDD = 0;
+ }
+ else
+ {
+ /* Using the per-process object, so create it */
+ pDirectDrawGlobal->hDD = (ULONG_PTR)NtGdiDdCreateDirectDrawObject(hdc);
+
+ /* Set the return value */
+ Return = pDirectDrawGlobal->hDD ? TRUE : FALSE;
+ }
+
+ /* Return to caller */
+ return Return;
+}
+
+/*
+ * @implemented
+ *
+ * GDIEntry 2
+ */
+BOOL
+WINAPI
+DdQueryDirectDrawObject(LPDDRAWI_DIRECTDRAW_GBL pDirectDrawGlobal,
+ LPDDHALINFO pHalInfo,
+ LPDDHAL_DDCALLBACKS pDDCallbacks,
+ LPDDHAL_DDSURFACECALLBACKS pDDSurfaceCallbacks,
+ LPDDHAL_DDPALETTECALLBACKS pDDPaletteCallbacks,
+ LPD3DHAL_CALLBACKS pD3dCallbacks,
+ LPD3DHAL_GLOBALDRIVERDATA pD3dDriverData,
+ LPDDHAL_DDEXEBUFCALLBACKS pD3dBufferCallbacks,
+ LPDDSURFACEDESC pD3dTextureFormats,
+ LPDWORD pdwFourCC,
+ LPVIDMEM pvmList)
+{
+ PVIDEOMEMORY VidMemList = NULL;
+ DD_HALINFO HalInfo;
+ D3DNTHAL_CALLBACKS D3dCallbacks;
+ D3DNTHAL_GLOBALDRIVERDATA D3dDriverData;
+ DD_D3DBUFCALLBACKS D3dBufferCallbacks;
+ DWORD CallbackFlags[3];
+ DWORD dwNumHeaps=0, FourCCs=0;
+ DWORD Flags;
+ BOOL retVal = TRUE;
+
+ /* Clear the structures */
+ RtlZeroMemory(&HalInfo, sizeof(DD_HALINFO));
+ RtlZeroMemory(&D3dCallbacks, sizeof(D3DNTHAL_CALLBACKS));
+ RtlZeroMemory(&D3dDriverData, sizeof(D3DNTHAL_GLOBALDRIVERDATA));
+ RtlZeroMemory(&D3dBufferCallbacks, sizeof(DD_D3DBUFCALLBACKS));
+ RtlZeroMemory(CallbackFlags, sizeof(DWORD)*3);
+
+ /* Note : XP always alloc 24*sizeof(VIDEOMEMORY) of pvmlist so we change it to it */
+ if ( (pvmList != NULL) &&
+ (pHalInfo->vmiData.dwNumHeaps != 0) )
+ {
+ VidMemList = (PVIDEOMEMORY) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (sizeof(VIDEOMEMORY) * 24 ) * pHalInfo->vmiData.dwNumHeaps);
+ }
+
+
+ /* Do the query */
+ if (!NtGdiDdQueryDirectDrawObject(GetDdHandle(pDirectDrawGlobal->hDD),
+ &HalInfo,
+ CallbackFlags,
+ &D3dCallbacks,
+ &D3dDriverData,
+ &D3dBufferCallbacks,
+ pD3dTextureFormats,
+ &dwNumHeaps,
+ VidMemList,
+ &FourCCs,
+ pdwFourCC))
+ {
+ /* We failed, free the memory and return */
+ retVal = FALSE;
+ goto cleanup;
+ }
+
+ /* Clear the incoming pointer */
+ RtlZeroMemory(pHalInfo, sizeof(DDHALINFO));
+
+ /* Convert all the data */
+ pHalInfo->dwSize = sizeof(DDHALINFO);
+ pHalInfo->lpDDCallbacks = pDDCallbacks;
+ pHalInfo->lpDDSurfaceCallbacks = pDDSurfaceCallbacks;
+ pHalInfo->lpDDPaletteCallbacks = pDDPaletteCallbacks;
+
+ /* Check for NT5+ D3D Data */
+ if ( (D3dCallbacks.dwSize != 0) &&
+ (D3dDriverData.dwSize != 0) )
+ {
+ /* Write these down */
+ pHalInfo->lpD3DGlobalDriverData = (ULONG_PTR)pD3dDriverData;
+ pHalInfo->lpD3DHALCallbacks = (ULONG_PTR)pD3dCallbacks;
+
+ /* Check for Buffer Callbacks */
+ if (D3dBufferCallbacks.dwSize)
+ {
+ /* Write this one too */
+ pHalInfo->lpDDExeBufCallbacks = pD3dBufferCallbacks;
+ }
+ }
+
+ /* Continue converting the rest */
+ pHalInfo->vmiData.dwFlags = HalInfo.vmiData.dwFlags;
+ pHalInfo->vmiData.dwDisplayWidth = HalInfo.vmiData.dwDisplayWidth;
+ pHalInfo->vmiData.dwDisplayHeight = HalInfo.vmiData.dwDisplayHeight;
+ pHalInfo->vmiData.lDisplayPitch = HalInfo.vmiData.lDisplayPitch;
+ pHalInfo->vmiData.fpPrimary = 0;
+
+ RtlCopyMemory( &pHalInfo->vmiData.ddpfDisplay,
+ &HalInfo.vmiData.ddpfDisplay,
+ sizeof(DDPIXELFORMAT));
+
+ pHalInfo->vmiData.dwOffscreenAlign = HalInfo.vmiData.dwOffscreenAlign;
+ pHalInfo->vmiData.dwOverlayAlign = HalInfo.vmiData.dwOverlayAlign;
+ pHalInfo->vmiData.dwTextureAlign = HalInfo.vmiData.dwTextureAlign;
+ pHalInfo->vmiData.dwZBufferAlign = HalInfo.vmiData.dwZBufferAlign;
+ pHalInfo->vmiData.dwAlphaAlign = HalInfo.vmiData.dwAlphaAlign;
+
+ pHalInfo->vmiData.dwNumHeaps = dwNumHeaps;
+ pHalInfo->vmiData.pvmList = pvmList;
+
+ RtlCopyMemory( &pHalInfo->ddCaps,
+ &HalInfo.ddCaps,
+ sizeof(DDCORECAPS ));
+
+ pHalInfo->ddCaps.dwNumFourCCCodes = FourCCs;
+ pHalInfo->lpdwFourCC = pdwFourCC;
+
+ /* always force rope 0x1000 for hal it mean only source copy is supported */
+ pHalInfo->ddCaps.dwRops[6] = 0x1000;
+
+ /* Set the HAL flags what ReactX got from the driver
+ * Windows XP force setting DDHALINFO_GETDRIVERINFOSET if the driver does not set it
+ * and ReactX doing same to keep compatible with drivers, but the driver are
+ * force support DdGetDriverInfo acoriding MSDN but it seam some driver do not set
+ * this flag even it is being supported. that is mean. It is small hack to keep
+ * bad driver working, that trust this is always being setting by it self at end
+ */
+ pHalInfo->dwFlags = (HalInfo.dwFlags & ~DDHALINFO_GETDRIVERINFOSET) | DDHALINFO_GETDRIVERINFOSET;
+ pHalInfo->GetDriverInfo = (LPDDHAL_GETDRIVERINFO) DdGetDriverInfo;
+
+ /* Now check if we got any DD callbacks */
+ if (pDDCallbacks)
+ {
+ /* Zero the structure */
+ RtlZeroMemory(pDDCallbacks, sizeof(DDHAL_DDCALLBACKS));
+ pDDCallbacks->dwSize = sizeof(DDHAL_DDCALLBACKS);
+
+ /* Set the flags for this structure
+ * Windows XP force setting DDHAL_CB32_CREATESURFACE if the driver does not set it
+ * and ReactX doing same to keep compatible with drivers, but the driver are
+ * force support pDDCallbacks acoriding MSDN but it seam some driver do not set
+ * this flag even it is being supported. that is mean. It is small hack to keep
+ * bad driver working, that trust this is always being setting by it self at end
+ */
+ Flags = (CallbackFlags[0] & ~DDHAL_CB32_CREATESURFACE) | DDHAL_CB32_CREATESURFACE;
+ pDDCallbacks->dwFlags = Flags;
+
+ /* Write the always-on functions */
+ pDDCallbacks->CreateSurface = DdCreateSurface;
+
+ /* Now write the pointers, if applicable */
+ if (Flags & DDHAL_CB32_WAITFORVERTICALBLANK)
+ {
+ pDDCallbacks->WaitForVerticalBlank = DdWaitForVerticalBlank;
+ }
+ if (Flags & DDHAL_CB32_CANCREATESURFACE)
+ {
+ pDDCallbacks->CanCreateSurface = DdCanCreateSurface;
+ }
+ if (Flags & DDHAL_CB32_GETSCANLINE)
+ {
+ pDDCallbacks->GetScanLine = DdGetScanLine;
+ }
+ }
+
+ /* Check for DD Surface Callbacks */
+ if (pDDSurfaceCallbacks)
+ {
+ /* Zero the structures */
+ RtlZeroMemory(pDDSurfaceCallbacks, sizeof(DDHAL_DDSURFACECALLBACKS));
+ pDDSurfaceCallbacks->dwSize = sizeof(DDHAL_DDSURFACECALLBACKS);
+
+ /* Set the flags for this structure
+ * Windows XP force setting DDHAL_SURFCB32_LOCK, DDHAL_SURFCB32_UNLOCK,
+ * DDHAL_SURFCB32_SETCOLORKEY, DDHAL_SURFCB32_DESTROYSURFACE if the driver
+ * does not set it and ReactX doing same to keep compatible with drivers,
+ * but the driver are force support pDDSurfaceCallbacks acoriding MSDN but it seam
+ * some driver do not set this flag even it is being supported. that is mean.
+ * It is small hack to keep bad driver working, that trust this is always being
+ * setting by it self at end
+ */
+
+ Flags = (CallbackFlags[1] & ~(DDHAL_SURFCB32_LOCK | DDHAL_SURFCB32_UNLOCK |
+ DDHAL_SURFCB32_SETCOLORKEY | DDHAL_SURFCB32_DESTROYSURFACE)) |
+ (DDHAL_SURFCB32_LOCK | DDHAL_SURFCB32_UNLOCK |
+ DDHAL_SURFCB32_SETCOLORKEY | DDHAL_SURFCB32_DESTROYSURFACE);
+
+ pDDSurfaceCallbacks->dwFlags = Flags;
+
+ /* Write the always-on functions */
+ pDDSurfaceCallbacks->Lock = DdLock;
+ pDDSurfaceCallbacks->Unlock = DdUnlock;
+ pDDSurfaceCallbacks->SetColorKey = DdSetColorKey;
+ pDDSurfaceCallbacks->DestroySurface = DdDestroySurface;
+
+ /* Write the optional ones */
+ if (Flags & DDHAL_SURFCB32_FLIP)
+ {
+ pDDSurfaceCallbacks->Flip = DdFlip;
+ }
+ if (Flags & DDHAL_SURFCB32_BLT)
+ {
+ pDDSurfaceCallbacks->Blt = DdBlt;
+ }
+ if (Flags & DDHAL_SURFCB32_GETBLTSTATUS)
+ {
+ pDDSurfaceCallbacks->GetBltStatus = DdGetBltStatus;
+ }
+ if (Flags & DDHAL_SURFCB32_GETFLIPSTATUS)
+ {
+ pDDSurfaceCallbacks->GetFlipStatus = DdGetFlipStatus;
+ }
+ if (Flags & DDHAL_SURFCB32_UPDATEOVERLAY)
+ {
+ pDDSurfaceCallbacks->UpdateOverlay = DdUpdateOverlay;
+ }
+ if (Flags & DDHAL_SURFCB32_SETOVERLAYPOSITION)
+ {
+ pDDSurfaceCallbacks->SetOverlayPosition = DdSetOverlayPosition;
+ }
+ if (Flags & DDHAL_SURFCB32_ADDATTACHEDSURFACE)
+ {
+ pDDSurfaceCallbacks->AddAttachedSurface = DdAddAttachedSurface;
+ }
+ }
+
+ /* Check for DD Palette Callbacks, This interface are dead for user mode,
+ * only what it can support are being report back.
+ */
+ if (pDDPaletteCallbacks)
+ {
+ /* Zero the struct */
+ RtlZeroMemory(pDDPaletteCallbacks, sizeof(DDHAL_DDPALETTECALLBACKS));
+
+ /* Write the header */
+ pDDPaletteCallbacks->dwSize = sizeof(DDHAL_DDPALETTECALLBACKS);
+ pDDPaletteCallbacks->dwFlags = CallbackFlags[2];
+ }
+
+ if (pD3dCallbacks)
+ {
+ /* Zero the struct */
+ RtlZeroMemory(pD3dCallbacks, sizeof(DDHAL_DDEXEBUFCALLBACKS));
+
+ /* Check if we have one */
+ if (D3dCallbacks.dwSize)
+ {
+ /* Write the header */
+ pD3dCallbacks->dwSize = sizeof(DDHAL_DDEXEBUFCALLBACKS);
+
+ /* Now check for each callback */
+ if (D3dCallbacks.ContextCreate)
+ {
+ pD3dCallbacks->ContextCreate = (LPD3DHAL_CONTEXTCREATECB) D3dContextCreate;
+ }
+ if (D3dCallbacks.ContextDestroy)
+ {
+ pD3dCallbacks->ContextDestroy = (LPD3DHAL_CONTEXTDESTROYCB) NtGdiD3dContextDestroy;
+ }
+ if (D3dCallbacks.ContextDestroyAll)
+ {
+ pD3dCallbacks->ContextDestroyAll = (LPD3DHAL_CONTEXTDESTROYALLCB) NtGdiD3dContextDestroyAll;
+ }
+ }
+ }
+
+ /* Check for D3D Driver Data */
+ if (pD3dDriverData)
+ {
+ /* Copy the struct */
+ RtlMoveMemory(pD3dDriverData, &D3dDriverData, sizeof(D3DHAL_GLOBALDRIVERDATA));
+
+ /* Write the pointer to the texture formats */
+ pD3dDriverData->lpTextureFormats = pD3dTextureFormats;
+ }
+
+ /* Check for D3D Buffer Callbacks */
+ if (pD3dBufferCallbacks)
+ {
+ /* Zero the struct */
+ RtlZeroMemory(pD3dBufferCallbacks, sizeof(DDHAL_DDEXEBUFCALLBACKS));
+
+ if ( D3dBufferCallbacks.dwSize)
+ {
+ pD3dBufferCallbacks->dwSize = D3dBufferCallbacks.dwSize;
+
+ pD3dBufferCallbacks->dwFlags = D3dBufferCallbacks.dwFlags;
+ if ( D3dBufferCallbacks.CanCreateD3DBuffer)
+ {
+ pD3dBufferCallbacks->CanCreateExecuteBuffer = (LPDDHALEXEBUFCB_CANCREATEEXEBUF)DdCanCreateD3DBuffer;
+ }
+
+ if (D3dBufferCallbacks.CreateD3DBuffer)
+ {
+ pD3dBufferCallbacks->CreateExecuteBuffer = (LPDDHALEXEBUFCB_CREATEEXEBUF) DdCreateD3DBuffer;
+ }
+
+ if ( D3dBufferCallbacks.DestroyD3DBuffer )
+ {
+ pD3dBufferCallbacks->DestroyExecuteBuffer = (LPDDHALEXEBUFCB_DESTROYEXEBUF) DdDestroyD3DBuffer;
+ }
+
+ if ( D3dBufferCallbacks.LockD3DBuffer )
+ {
+ pD3dBufferCallbacks->LockExecuteBuffer = (LPDDHALEXEBUFCB_LOCKEXEBUF) DdLockD3D;
+ }
+
+ if ( D3dBufferCallbacks.UnlockD3DBuffer )
+ {
+ pD3dBufferCallbacks->UnlockExecuteBuffer = (LPDDHALEXEBUFCB_UNLOCKEXEBUF) DdUnlockD3D;
+ }
+
+ }
+ }
+
+ /* FIXME VidMemList */
+
+cleanup:
+ if (VidMemList)
+ {
+ HeapFree(GetProcessHeap(), 0, VidMemList);
+ }
+
+ return retVal;
+}
+
+/*
+ * @implemented
+ *
+ * GDIEntry 3
+ */
+BOOL
+WINAPI
+DdDeleteDirectDrawObject(LPDDRAWI_DIRECTDRAW_GBL pDirectDrawGlobal)
+{
+ BOOL Return = FALSE;
+
+ /* If this is the global object */
+ if(pDirectDrawGlobal->hDD)
+ {
+ /* Free it */
+ Return = NtGdiDdDeleteDirectDrawObject((HANDLE)pDirectDrawGlobal->hDD);
- if (Return == TRUE)
++ if (Return)
+ {
+ pDirectDrawGlobal->hDD = 0;
+ }
+ }
+ else if (ghDirectDraw)
+ {
+ /* Always success here */
+ Return = TRUE;
+
+ /* Make sure this is the last instance */
+ if (!(--gcDirectDraw))
+ {
+ /* Delete the object */
+ Return = NtGdiDdDeleteDirectDrawObject(ghDirectDraw);
++ if (Return)
+ {
+ ghDirectDraw = 0;
+ }
+ }
+ }
+
+ /* Return */
+ return Return;
+}
+
+/*
+ * @implemented
+ *
+ * GDIEntry 4
+ */
+BOOL
+WINAPI
+DdCreateSurfaceObject( LPDDRAWI_DDRAWSURFACE_LCL pSurfaceLocal,
+ BOOL bPrimarySurface)
+{
+ return bDDCreateSurface(pSurfaceLocal, TRUE);
+}
+
+
+/*
+ * @implemented
+ *
+ * GDIEntry 5
+ */
+BOOL
+WINAPI
+DdDeleteSurfaceObject(LPDDRAWI_DDRAWSURFACE_LCL pSurfaceLocal)
+{
+ BOOL Return = FALSE;
+
+ /* Make sure there is one */
+ if (pSurfaceLocal->hDDSurface)
+ {
+ /* Delete it */
+ Return = NtGdiDdDeleteSurfaceObject((HANDLE)pSurfaceLocal->hDDSurface);
+ pSurfaceLocal->hDDSurface = 0;
+ }
+
+ return Return;
+}
+
+/*
+ * @implemented
+ *
+ * GDIEntry 6
+ */
+BOOL
+WINAPI
+DdResetVisrgn(LPDDRAWI_DDRAWSURFACE_LCL pSurfaceLocal,
+ HWND hWnd)
+{
+ /* Call win32k directly */
+ return NtGdiDdResetVisrgn((HANDLE) pSurfaceLocal->hDDSurface, hWnd);
+}
+
+/*
+ * @implemented
+ *
+ * GDIEntry 7
+ */
+HDC
+WINAPI
+DdGetDC(LPDDRAWI_DDRAWSURFACE_LCL pSurfaceLocal,
+ LPPALETTEENTRY pColorTable)
+{
+ /* Call win32k directly */
+ return NtGdiDdGetDC(pColorTable, (HANDLE) pSurfaceLocal->hDDSurface);
+}
+
+/*
+ * @implemented
+ *
+ * GDIEntry 8
+ */
+BOOL
+WINAPI
+DdReleaseDC(LPDDRAWI_DDRAWSURFACE_LCL pSurfaceLocal)
+{
+ /* Call win32k directly */
+ return NtGdiDdReleaseDC((HANDLE) pSurfaceLocal->hDDSurface);
+}
+
+/*
+ * @unimplemented
+ * GDIEntry 9
+ */
+HBITMAP
+WINAPI
+DdCreateDIBSection(HDC hdc,
+ CONST BITMAPINFO *pbmi,
+ UINT iUsage,
+ VOID **ppvBits,
+ HANDLE hSectionApp,
+ DWORD dwOffset)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return 0;
+}
+
+/*
+ * @implemented
+ *
+ * GDIEntry 10
+ */
+BOOL
+WINAPI
+DdReenableDirectDrawObject(LPDDRAWI_DIRECTDRAW_GBL pDirectDrawGlobal,
+ BOOL *pbNewMode)
+{
+ /* Call win32k directly */
+ return NtGdiDdReenableDirectDrawObject(GetDdHandle(pDirectDrawGlobal->hDD),
+ pbNewMode);
+}
+
+
+/*
+ * @implemented
+ *
+ * GDIEntry 11
+ */
+BOOL
+WINAPI
+DdAttachSurface( LPDDRAWI_DDRAWSURFACE_LCL pSurfaceFrom,
+ LPDDRAWI_DDRAWSURFACE_LCL pSurfaceTo)
+{
+ /* Create Surface if it does not exits one */
+ if (!pSurfaceFrom->hDDSurface)
+ {
+ if (!bDDCreateSurface(pSurfaceFrom, FALSE))
+ {
+ return FALSE;
+ }
+ }
+
+ /* Create Surface if it does not exits one */
+ if (!pSurfaceTo->hDDSurface)
+ {
+ if (!bDDCreateSurface(pSurfaceTo, FALSE))
+ {
+ return FALSE;
+ }
+ }
+
+ /* Call win32k */
+ return NtGdiDdAttachSurface((HANDLE)pSurfaceFrom->hDDSurface,
+ (HANDLE)pSurfaceTo->hDDSurface);
+}
+
+/*
+ * @implemented
+ *
+ * GDIEntry 12
+ */
+VOID
+WINAPI
+DdUnattachSurface(LPDDRAWI_DDRAWSURFACE_LCL pSurface,
+ LPDDRAWI_DDRAWSURFACE_LCL pSurfaceAttached)
+{
+ /* Call win32k */
+ NtGdiDdUnattachSurface((HANDLE)pSurface->hDDSurface,
+ (HANDLE)pSurfaceAttached->hDDSurface);
+}
+
+/*
+ * @implemented
+ *
+ * GDIEntry 13
+ */
+ULONG
+WINAPI
+DdQueryDisplaySettingsUniqueness()
+{
+ return GdiSharedHandleTable->flDeviceUniq;
+}
+
+/*
+ * @implemented
+ *
+ * GDIEntry 14
+ */
+HANDLE
+WINAPI
+DdGetDxHandle(LPDDRAWI_DIRECTDRAW_LCL pDDraw,
+ LPDDRAWI_DDRAWSURFACE_LCL pSurface,
+ BOOL bRelease)
+{
+ HANDLE hDD = NULL;
+ HANDLE hSurface = NULL;
+
+ /* Check if we already have a surface */
+ if (!pSurface)
+ {
+ /* We don't have one, use the DirectDraw Object handle instead */
+ hDD = GetDdHandle(pDDraw->lpGbl->hDD);
+ }
+ else
+ {
+ hSurface = (HANDLE)pSurface->hDDSurface;
+ }
+
+ /* Call the API */
+ return (HANDLE)NtGdiDdGetDxHandle(hDD, hSurface, bRelease);
+}
+
+/*
+ * @implemented
+ *
+ * GDIEntry 15
+ */
+BOOL
+WINAPI
+DdSetGammaRamp(LPDDRAWI_DIRECTDRAW_LCL pDDraw,
+ HDC hdc,
+ LPVOID lpGammaRamp)
+{
+ /* Call win32k directly */
+ return NtGdiDdSetGammaRamp(GetDdHandle(pDDraw->lpGbl->hDD),
+ hdc,
+ lpGammaRamp);
+}
+
+
+
+
+
--- /dev/null
- #define FIX2LONG(x) ((x) >> 4)
+/*
+ * PROJECT: ReactOS win32 kernel mode subsystem
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: win32ss/gdi/ntgdi/xformobj.c
+ * PURPOSE: XFORMOBJ API
+ * PROGRAMMER: Timo Kreuzer
+ */
+
+/** Includes ******************************************************************/
+
+#include <win32k.h>
+#define NDEBUG
+#include <debug.h>
+
+C_ASSERT(sizeof(FIX) == sizeof(LONG));
++#define FIX2LONG(x) (((x) + 8) >> 4)
+#define LONG2FIX(x) ((x) << 4)
+
+#define FLOATOBJ_Equal _FLOATOBJ_Equal
+#define FLOATOBJ_GetLong _FLOATOBJ_GetLong
+#define FLOATOBJ_GetFix _FLOATOBJ_GetFix
+#define FLOATOBJ_IsLong _FLOATOBJ_IsLong
+#define FLOATOBJ_Equal0 _FLOATOBJ_Equal0
+#define FLOATOBJ_Equal1 _FLOATOBJ_Equal1
+
+/** Inline helper functions ***************************************************/
+
+/*
+ * Inline helper to calculate pfo1 * pfo2 + pfo3 * pfo4
+ */
+FORCEINLINE
+VOID
+MulAdd(
+ PFLOATOBJ pfoDest,
+ PFLOATOBJ pfo1,
+ PFLOATOBJ pfo2,
+ PFLOATOBJ pfo3,
+ PFLOATOBJ pfo4)
+{
+ FLOATOBJ foTmp;
+
+ *pfoDest = *pfo1;
+ FLOATOBJ_Mul(pfoDest, pfo2);
+ foTmp = *pfo3;
+ FLOATOBJ_Mul(&foTmp, pfo4);
+ FLOATOBJ_Add(pfoDest, &foTmp);
+}
+
+/*
+ * Inline helper to calculate pfo1 * l2 + pfo3 * l4
+ */
+FORCEINLINE
+VOID
+MulAddLong(
+ PFLOATOBJ pfoDest,
+ PFLOATOBJ pfo1,
+ LONG l2,
+ PFLOATOBJ pfo3,
+ LONG l4)
+{
+ FLOATOBJ foTmp;
+
+ *pfoDest = *pfo1;
+ FLOATOBJ_MulLong(pfoDest, l2);
+ foTmp = *pfo3;
+ FLOATOBJ_MulLong(&foTmp, l4);
+ FLOATOBJ_Add(pfoDest, &foTmp);
+}
+
+/*
+ * Inline helper to calculate pfo1 * pfo2 - pfo3 * pfo4
+ */
+FORCEINLINE
+VOID
+MulSub(
+ PFLOATOBJ pfoDest,
+ PFLOATOBJ pfo1,
+ PFLOATOBJ pfo2,
+ PFLOATOBJ pfo3,
+ PFLOATOBJ pfo4)
+{
+ FLOATOBJ foTmp;
+
+ *pfoDest = *pfo1;
+ FLOATOBJ_Mul(pfoDest, pfo2);
+ foTmp = *pfo3;
+ FLOATOBJ_Mul(&foTmp, pfo4);
+ FLOATOBJ_Sub(pfoDest, &foTmp);
+}
+
+/*
+ * Inline helper to get the complexity hint from flAccel
+ */
+FORCEINLINE
+ULONG
+HintFromAccel(ULONG flAccel)
+{
+ switch (flAccel & (XFORM_SCALE|XFORM_UNITY|XFORM_NO_TRANSLATION))
+ {
+ case (XFORM_SCALE|XFORM_UNITY|XFORM_NO_TRANSLATION):
+ return GX_IDENTITY;
+ case (XFORM_SCALE|XFORM_UNITY):
+ return GX_OFFSET;
+ case XFORM_SCALE:
+ return GX_SCALE;
+ default:
+ return GX_GENERAL;
+ }
+}
+
+/** Internal functions ********************************************************/
+
+ULONG
+NTAPI
+XFORMOBJ_UpdateAccel(
+ IN XFORMOBJ *pxo)
+{
+ PMATRIX pmx = XFORMOBJ_pmx(pxo);
+
+ /* Copy Dx and Dy to FIX format */
+ pmx->fxDx = FLOATOBJ_GetFix(&pmx->efDx);
+ pmx->fxDy = FLOATOBJ_GetFix(&pmx->efDy);
+
+ pmx->flAccel = 0;
+
+ if (FLOATOBJ_Equal0(&pmx->efDx) &&
+ FLOATOBJ_Equal0(&pmx->efDy))
+ {
+ pmx->flAccel |= XFORM_NO_TRANSLATION;
+ }
+
+ if (FLOATOBJ_Equal0(&pmx->efM12) &&
+ FLOATOBJ_Equal0(&pmx->efM21))
+ {
+ pmx->flAccel |= XFORM_SCALE;
+ }
+
+ if (FLOATOBJ_Equal1(&pmx->efM11) &&
+ FLOATOBJ_Equal1(&pmx->efM22))
+ {
+ pmx->flAccel |= XFORM_UNITY;
+ }
+
+ if (FLOATOBJ_IsLong(&pmx->efM11) && FLOATOBJ_IsLong(&pmx->efM12) &&
+ FLOATOBJ_IsLong(&pmx->efM21) && FLOATOBJ_IsLong(&pmx->efM22))
+ {
+ pmx->flAccel |= XFORM_INTEGER;
+ }
+
+ return HintFromAccel(pmx->flAccel);
+}
+
+
+ULONG
+NTAPI
+XFORMOBJ_iSetXform(
+ OUT XFORMOBJ *pxo,
+ IN const XFORML *pxform)
+{
+ PMATRIX pmx = XFORMOBJ_pmx(pxo);
+
+ /* Check parameters */
+ if (!pxo || !pxform) return DDI_ERROR;
+
+ /* Check if the xform is valid */
+ if ((pxform->eM11 == 0) || (pxform->eM22 == 0)) return DDI_ERROR;
+
+ /* Copy members */
+ FLOATOBJ_SetFloat(&pmx->efM11, pxform->eM11);
+ FLOATOBJ_SetFloat(&pmx->efM12, pxform->eM12);
+ FLOATOBJ_SetFloat(&pmx->efM21, pxform->eM21);
+ FLOATOBJ_SetFloat(&pmx->efM22, pxform->eM22);
+ FLOATOBJ_SetFloat(&pmx->efDx, pxform->eDx);
+ FLOATOBJ_SetFloat(&pmx->efDy, pxform->eDy);
+
+ /* Update accelerators and return complexity */
+ return XFORMOBJ_UpdateAccel(pxo);
+}
+
+
+/*
+ * Multiplies pxo1 with pxo2 and stores the result in pxo.
+ * returns complexity hint
+ * | efM11 efM12 0 |
+ * | efM21 efM22 0 |
+ * | efDx efDy 1 |
+ */
+ULONG
+NTAPI
+XFORMOBJ_iCombine(
+ IN XFORMOBJ *pxo,
+ IN XFORMOBJ *pxo1,
+ IN XFORMOBJ *pxo2)
+{
+ MATRIX mx;
+ PMATRIX pmx, pmx1, pmx2;
+
+ /* Get the source matrices */
+ pmx1 = XFORMOBJ_pmx(pxo1);
+ pmx2 = XFORMOBJ_pmx(pxo2);
+
+ /* Do a 3 x 3 matrix multiplication with mx as destinantion */
+ MulAdd(&mx.efM11, &pmx1->efM11, &pmx2->efM11, &pmx1->efM12, &pmx2->efM21);
+ MulAdd(&mx.efM12, &pmx1->efM11, &pmx2->efM12, &pmx1->efM12, &pmx2->efM22);
+ MulAdd(&mx.efM21, &pmx1->efM21, &pmx2->efM11, &pmx1->efM22, &pmx2->efM21);
+ MulAdd(&mx.efM22, &pmx1->efM21, &pmx2->efM12, &pmx1->efM22, &pmx2->efM22);
+ MulAdd(&mx.efDx, &pmx1->efDx, &pmx2->efM11, &pmx1->efDy, &pmx2->efM21);
+ FLOATOBJ_Add(&mx.efDx, &pmx2->efDx);
+ MulAdd(&mx.efDy, &pmx1->efDx, &pmx2->efM12, &pmx1->efDy, &pmx2->efM22);
+ FLOATOBJ_Add(&mx.efDy, &pmx2->efDy);
+
+ /* Copy back */
+ pmx = XFORMOBJ_pmx(pxo);
+ *pmx = mx;
+
+ /* Update accelerators and return complexity */
+ return XFORMOBJ_UpdateAccel(pxo);
+}
+
+
+ULONG
+NTAPI
+XFORMOBJ_iCombineXform(
+ IN XFORMOBJ *pxo,
+ IN XFORMOBJ *pxo1,
+ IN XFORML *pxform,
+ IN BOOL bLeftMultiply)
+{
+ MATRIX mx;
+ XFORMOBJ xo2;
+
+ XFORMOBJ_vInit(&xo2, &mx);
+ XFORMOBJ_iSetXform(&xo2, pxform);
+
+ if (bLeftMultiply)
+ {
+ return XFORMOBJ_iCombine(pxo, &xo2, pxo1);
+ }
+ else
+ {
+ return XFORMOBJ_iCombine(pxo, pxo1, &xo2);
+ }
+}
+
+/*
+ * A^-1 = adj(A) / det(AT)
+ * A^-1 = 1/(a*d - b*c) * (a22,-a12,a21,-a11)
+ */
+ULONG
+NTAPI
+XFORMOBJ_iInverse(
+ OUT XFORMOBJ *pxoDst,
+ IN XFORMOBJ *pxoSrc)
+{
+ PMATRIX pmxDst, pmxSrc;
+ FLOATOBJ foDet;
+ XFORM xformSrc;
+
+ pmxDst = XFORMOBJ_pmx(pxoDst);
+ pmxSrc = XFORMOBJ_pmx(pxoSrc);
+
+ XFORMOBJ_iGetXform(pxoSrc, (XFORML*)&xformSrc);
+
+ /* det = M11 * M22 - M12 * M21 */
+ MulSub(&foDet, &pmxSrc->efM11, &pmxSrc->efM22, &pmxSrc->efM12, &pmxSrc->efM21);
+
+ if (FLOATOBJ_Equal0(&foDet))
+ {
+ /* Determinant is 0! */
+ return DDI_ERROR;
+ }
+
+ /* Calculate adj(A) / det(A) */
+ pmxDst->efM11 = pmxSrc->efM22;
+ FLOATOBJ_Div(&pmxDst->efM11, &foDet);
+ pmxDst->efM22 = pmxSrc->efM11;
+ FLOATOBJ_Div(&pmxDst->efM22, &foDet);
+
+ /* The other 2 are negative, negate foDet for that */
+ FLOATOBJ_Neg(&foDet);
+ pmxDst->efM12 = pmxSrc->efM12;
+ FLOATOBJ_Div(&pmxDst->efM12, &foDet);
+ pmxDst->efM21 = pmxSrc->efM21;
+ FLOATOBJ_Div(&pmxDst->efM21, &foDet);
+
+ /* Calculate the inverted x shift: Dx' = -Dx * M11' - Dy * M21' */
+ pmxDst->efDx = pmxSrc->efDx;
+ FLOATOBJ_Neg(&pmxDst->efDx);
+ MulSub(&pmxDst->efDx, &pmxDst->efDx, &pmxDst->efM11, &pmxSrc->efDy, &pmxDst->efM21);
+
+ /* Calculate the inverted y shift: Dy' = -Dy * M22' - Dx * M12' */
+ pmxDst->efDy = pmxSrc->efDy;
+ FLOATOBJ_Neg(&pmxDst->efDy);
+ MulSub(&pmxDst->efDy, &pmxDst->efDy, &pmxDst->efM22, &pmxSrc->efDx, &pmxDst->efM12);
+
+ /* Update accelerators and return complexity */
+ return XFORMOBJ_UpdateAccel(pxoDst);
+}
+
+
+BOOL
+NTAPI
+XFORMOBJ_bXformFixPoints(
+ IN XFORMOBJ *pxo,
+ IN ULONG cPoints,
+ IN PPOINTL pptIn,
+ OUT PPOINTL pptOut)
+{
+ PMATRIX pmx;
+ INT i;
+ FLOATOBJ fo1, fo2;
+ FLONG flAccel;
+
+ pmx = XFORMOBJ_pmx(pxo);
+ flAccel = pmx->flAccel;
+
+ if ((flAccel & (XFORM_SCALE|XFORM_UNITY)) == (XFORM_SCALE|XFORM_UNITY))
+ {
+ /* Identity transformation, nothing todo */
+ }
+ else if (flAccel & XFORM_INTEGER)
+ {
+ if (flAccel & XFORM_UNITY)
+ {
+ /* 1-scale integer transform */
+ LONG lM12 = FLOATOBJ_GetLong(&pmx->efM12);
+ LONG lM21 = FLOATOBJ_GetLong(&pmx->efM21);
+
+ i = cPoints - 1;
+ do
+ {
+ LONG x = pptIn[i].x + pptIn[i].y * lM21;
+ LONG y = pptIn[i].y + pptIn[i].x * lM12;
+ pptOut[i].y = y;
+ pptOut[i].x = x;
+ }
+ while (--i >= 0);
+ }
+ else if (flAccel & XFORM_SCALE)
+ {
+ /* Diagonal integer transform */
+ LONG lM11 = FLOATOBJ_GetLong(&pmx->efM11);
+ LONG lM22 = FLOATOBJ_GetLong(&pmx->efM22);
+
+ i = cPoints - 1;
+ do
+ {
+ pptOut[i].x = pptIn[i].x * lM11;
+ pptOut[i].y = pptIn[i].y * lM22;
+ }
+ while (--i >= 0);
+ }
+ else
+ {
+ /* Full integer transform */
+ LONG lM11 = FLOATOBJ_GetLong(&pmx->efM11);
+ LONG lM12 = FLOATOBJ_GetLong(&pmx->efM12);
+ LONG lM21 = FLOATOBJ_GetLong(&pmx->efM21);
+ LONG lM22 = FLOATOBJ_GetLong(&pmx->efM22);
+
+ i = cPoints - 1;
+ do
+ {
+ LONG x;
+ x = pptIn[i].x * lM11;
+ x += pptIn[i].y * lM21;
+ pptOut[i].y = pptIn[i].y * lM22;
+ pptOut[i].y += pptIn[i].x * lM12;
+ pptOut[i].x = x;
+ }
+ while (--i >= 0);
+ }
+ }
+ else if (flAccel & XFORM_UNITY)
+ {
+ /* 1-scale transform */
+ i = cPoints - 1;
+ do
+ {
+ fo1 = pmx->efM21;
+ FLOATOBJ_MulLong(&fo1, pptIn[i].y);
+ fo2 = pmx->efM12;
+ FLOATOBJ_MulLong(&fo2, pptIn[i].x);
+ pptOut[i].x = pptIn[i].x + FLOATOBJ_GetLong(&fo1);
+ pptOut[i].y = pptIn[i].y + FLOATOBJ_GetLong(&fo2);
+ }
+ while (--i >= 0);
+ }
+ else if (flAccel & XFORM_SCALE)
+ {
+ /* Diagonal float transform */
+ i = cPoints - 1;
+ do
+ {
+ fo1 = pmx->efM11;
+ FLOATOBJ_MulLong(&fo1, pptIn[i].x);
+ pptOut[i].x = FLOATOBJ_GetLong(&fo1);
+ fo2 = pmx->efM22;
+ FLOATOBJ_MulLong(&fo2, pptIn[i].y);
+ pptOut[i].y = FLOATOBJ_GetLong(&fo2);
+ }
+ while (--i >= 0);
+ }
+ else
+ {
+ /* Full float transform */
+ i = cPoints - 1;
+ do
+ {
+ MulAddLong(&fo1, &pmx->efM11, pptIn[i].x, &pmx->efM21, pptIn[i].y);
+ MulAddLong(&fo2, &pmx->efM12, pptIn[i].x, &pmx->efM22, pptIn[i].y);
+ pptOut[i].x = FLOATOBJ_GetLong(&fo1);
+ pptOut[i].y = FLOATOBJ_GetLong(&fo2);
+ }
+ while (--i >= 0);
+ }
+
+ if (!(pmx->flAccel & XFORM_NO_TRANSLATION))
+ {
+ /* Translate points */
+ i = cPoints - 1;
+ do
+ {
+ pptOut[i].x += pmx->fxDx;
+ pptOut[i].y += pmx->fxDy;
+ }
+ while (--i >= 0);
+ }
+
+ return TRUE;
+}
+
+/** Public functions **********************************************************/
+
+// www.osr.com/ddk/graphics/gdifncs_0s2v.htm
+ULONG
+APIENTRY
+XFORMOBJ_iGetXform(
+ IN XFORMOBJ *pxo,
+ OUT XFORML *pxform)
+{
+ PMATRIX pmx = XFORMOBJ_pmx(pxo);
+
+ /* Check parameters */
+ if (!pxo || !pxform)
+ {
+ return DDI_ERROR;
+ }
+
+ /* Copy members */
+ pxform->eM11 = FLOATOBJ_GetFloat(&pmx->efM11);
+ pxform->eM12 = FLOATOBJ_GetFloat(&pmx->efM12);
+ pxform->eM21 = FLOATOBJ_GetFloat(&pmx->efM21);
+ pxform->eM22 = FLOATOBJ_GetFloat(&pmx->efM22);
+ pxform->eDx = FLOATOBJ_GetFloat(&pmx->efDx);
+ pxform->eDy = FLOATOBJ_GetFloat(&pmx->efDy);
+
+ /* Return complexity hint */
+ return HintFromAccel(pmx->flAccel);
+}
+
+
+// www.osr.com/ddk/graphics/gdifncs_5ig7.htm
+ULONG
+APIENTRY
+XFORMOBJ_iGetFloatObjXform(
+ IN XFORMOBJ *pxo,
+ OUT FLOATOBJ_XFORM *pxfo)
+{
+ PMATRIX pmx = XFORMOBJ_pmx(pxo);
+
+ /* Check parameters */
+ if (!pxo || !pxfo)
+ {
+ return DDI_ERROR;
+ }
+
+ /* Copy members */
+ pxfo->eM11 = pmx->efM11;
+ pxfo->eM12 = pmx->efM12;
+ pxfo->eM21 = pmx->efM21;
+ pxfo->eM22 = pmx->efM22;
+ pxfo->eDx = pmx->efDx;
+ pxfo->eDy = pmx->efDy;
+
+ /* Return complexity hint */
+ return HintFromAccel(pmx->flAccel);
+}
+
+
+// www.osr.com/ddk/graphics/gdifncs_027b.htm
+BOOL
+APIENTRY
+XFORMOBJ_bApplyXform(
+ IN XFORMOBJ *pxo,
+ IN ULONG iMode,
+ IN ULONG cPoints,
+ IN PVOID pvIn,
+ OUT PVOID pvOut)
+{
+ MATRIX mx;
+ XFORMOBJ xoInv;
+ POINTL *pptl;
+ INT i;
+
+ /* Check parameters */
+ if (!pxo || !pvIn || !pvOut || cPoints < 1)
+ {
+ return FALSE;
+ }
+
+ /* Use inverse xform? */
+ if (iMode == XF_INV_FXTOL || iMode == XF_INV_LTOL)
+ {
+ XFORMOBJ_vInit(&xoInv, &mx);
+ if (XFORMOBJ_iInverse(&xoInv, pxo) == DDI_ERROR)
+ {
+ return FALSE;
+ }
+ pxo = &xoInv;
+ }
+
+ /* Convert POINTL to POINTFIX? */
+ if (iMode == XF_LTOFX || iMode == XF_LTOL || iMode == XF_INV_LTOL)
+ {
+ pptl = pvIn;
+ for (i = cPoints - 1; i >= 0; i--)
+ {
+ pptl[i].x = LONG2FIX(pptl[i].x);
+ pptl[i].y = LONG2FIX(pptl[i].y);
+ }
+ }
+
+ /* Do the actual fixpoint transformation */
+ if (!XFORMOBJ_bXformFixPoints(pxo, cPoints, pvIn, pvOut))
+ {
+ return FALSE;
+ }
+
+ /* Convert POINTFIX to POINTL? */
+ if (iMode == XF_INV_FXTOL || iMode == XF_INV_LTOL || iMode == XF_LTOL)
+ {
+ pptl = pvOut;
+ for (i = cPoints - 1; i >= 0; i--)
+ {
+ pptl[i].x = FIX2LONG(pptl[i].x);
+ pptl[i].y = FIX2LONG(pptl[i].y);
+ }
+ }
+
+ return TRUE;
+}
+
+/* EOF */
--- /dev/null
- if (pHotKey->id == IDHK_WINKEY && bWinHotkeyActive == TRUE)
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Win32k subsystem
+ * PURPOSE: HotKey support
+ * FILE: win32ss/user/ntuser/hotkey.c
+ * PROGRAMER: Eric Kohl
+ */
+
+/*
+ * FIXME: Hotkey notifications are triggered by keyboard input (physical or programatically)
+ * and since only desktops on WinSta0 can receive input in seems very wrong to allow
+ * windows/threads on destops not belonging to WinSta0 to set hotkeys (receive notifications).
+ * -- Gunnar
+ */
+
+#include <win32k.h>
+DBG_DEFAULT_CHANNEL(UserHotkey);
+
+/* GLOBALS *******************************************************************/
+
+/*
+ * Hardcoded hotkeys. See http://ivanlef0u.fr/repo/windoz/VI20051005.html
+ * or http://repo.meh.or.id/Windows/VI20051005.html .
+ *
+ * NOTE: The (Shift-)F12 keys are used only for the "UserDebuggerHotKey" setting
+ * which enables setting a key shortcut which, when pressed, establishes a
+ * breakpoint in the code being debugged:
+ * see http://technet.microsoft.com/en-us/library/cc786263(v=ws.10).aspx
+ * and http://flylib.com/books/en/4.441.1.33/1/ for more details.
+ * By default the key is VK-F12 on a 101-key keyboard, and is VK_SUBTRACT
+ * (hyphen / substract sign) on a 82-key keyboard.
+ */
+/* pti pwnd modifiers vk id next */
+// HOT_KEY hkF12 = {NULL, 1, 0, VK_F12, IDHK_F12, NULL};
+// HOT_KEY hkShiftF12 = {NULL, 1, MOD_SHIFT, VK_F12, IDHK_SHIFTF12, &hkF12};
+// HOT_KEY hkWinKey = {NULL, 1, MOD_WIN, 0, IDHK_WINKEY, &hkShiftF12};
+
+PHOT_KEY gphkFirst = NULL;
+BOOL bWinHotkeyActive = FALSE;
+
+/* FUNCTIONS *****************************************************************/
+
+VOID FASTCALL
+StartDebugHotKeys(VOID)
+{
+ UINT vk = VK_F12;
+ UserUnregisterHotKey(PWND_BOTTOM, IDHK_F12);
+ UserUnregisterHotKey(PWND_BOTTOM, IDHK_SHIFTF12);
+ if (!ENHANCED_KEYBOARD(gKeyboardInfo.KeyboardIdentifier))
+ {
+ vk = VK_SUBTRACT;
+ }
+ UserRegisterHotKey(PWND_BOTTOM, IDHK_SHIFTF12, MOD_SHIFT, vk);
+ UserRegisterHotKey(PWND_BOTTOM, IDHK_F12, 0, vk);
+ TRACE("Start up the debugger hotkeys!! If you see this you eneabled debugprints. Congrats!\n");
+}
+
+/*
+ * IntGetModifiers
+ *
+ * Returns a value that indicates if the key is a modifier key, and
+ * which one.
+ */
+static
+UINT FASTCALL
+IntGetModifiers(PBYTE pKeyState)
+{
+ UINT fModifiers = 0;
+
+ if (IS_KEY_DOWN(pKeyState, VK_SHIFT))
+ fModifiers |= MOD_SHIFT;
+
+ if (IS_KEY_DOWN(pKeyState, VK_CONTROL))
+ fModifiers |= MOD_CONTROL;
+
+ if (IS_KEY_DOWN(pKeyState, VK_MENU))
+ fModifiers |= MOD_ALT;
+
+ if (IS_KEY_DOWN(pKeyState, VK_LWIN) || IS_KEY_DOWN(pKeyState, VK_RWIN))
+ fModifiers |= MOD_WIN;
+
+ return fModifiers;
+}
+
+/*
+ * UnregisterWindowHotKeys
+ *
+ * Removes hotkeys registered by specified window on its cleanup
+ */
+VOID FASTCALL
+UnregisterWindowHotKeys(PWND pWnd)
+{
+ PHOT_KEY pHotKey = gphkFirst, phkNext, *pLink = &gphkFirst;
+
+ while (pHotKey)
+ {
+ /* Save next ptr for later use */
+ phkNext = pHotKey->pNext;
+
+ /* Should we delete this hotkey? */
+ if (pHotKey->pWnd == pWnd)
+ {
+ /* Update next ptr for previous hotkey and free memory */
+ *pLink = phkNext;
+ ExFreePoolWithTag(pHotKey, USERTAG_HOTKEY);
+ }
+ else /* This hotkey will stay, use its next ptr */
+ pLink = &pHotKey->pNext;
+
+ /* Move to the next entry */
+ pHotKey = phkNext;
+ }
+}
+
+/*
+ * UnregisterThreadHotKeys
+ *
+ * Removes hotkeys registered by specified thread on its cleanup
+ */
+VOID FASTCALL
+UnregisterThreadHotKeys(PTHREADINFO pti)
+{
+ PHOT_KEY pHotKey = gphkFirst, phkNext, *pLink = &gphkFirst;
+
+ while (pHotKey)
+ {
+ /* Save next ptr for later use */
+ phkNext = pHotKey->pNext;
+
+ /* Should we delete this hotkey? */
+ if (pHotKey->pti == pti)
+ {
+ /* Update next ptr for previous hotkey and free memory */
+ *pLink = phkNext;
+ ExFreePoolWithTag(pHotKey, USERTAG_HOTKEY);
+ }
+ else /* This hotkey will stay, use its next ptr */
+ pLink = &pHotKey->pNext;
+
+ /* Move to the next entry */
+ pHotKey = phkNext;
+ }
+}
+
+/*
+ * IsHotKey
+ *
+ * Checks if given key and modificators have corresponding hotkey
+ */
+static PHOT_KEY FASTCALL
+IsHotKey(UINT fsModifiers, WORD wVk)
+{
+ PHOT_KEY pHotKey = gphkFirst;
+
+ while (pHotKey)
+ {
+ if (pHotKey->fsModifiers == fsModifiers &&
+ pHotKey->vk == wVk)
+ {
+ /* We have found it */
+ return pHotKey;
+ }
+
+ /* Move to the next entry */
+ pHotKey = pHotKey->pNext;
+ }
+
+ return NULL;
+}
+
+/*
+ * co_UserProcessHotKeys
+ *
+ * Sends WM_HOTKEY message if given keys are hotkey
+ */
+BOOL NTAPI
+co_UserProcessHotKeys(WORD wVk, BOOL bIsDown)
+{
+ UINT fModifiers;
+ PHOT_KEY pHotKey;
+ PWND pWnd;
+ BOOL DoNotPostMsg = FALSE;
+
+ if (wVk == VK_SHIFT || wVk == VK_CONTROL || wVk == VK_MENU ||
+ wVk == VK_LWIN || wVk == VK_RWIN)
+ {
+ /* Those keys are specified by modifiers */
+ wVk = 0;
+ }
+
+ fModifiers = IntGetModifiers(gafAsyncKeyState);
+
+ /* Check if it is a hotkey */
+ pHotKey = IsHotKey(fModifiers, wVk);
+
+ if (pHotKey)
+ {
+ TRACE("Hot key pressed (pWnd %p, id %d)\n", pHotKey->pWnd, pHotKey->id);
+
+ /* FIXME: See comment about "UserDebuggerHotKey" on top of this file. */
+ if (pHotKey->id == IDHK_SHIFTF12 || pHotKey->id == IDHK_F12)
+ {
+ if (bIsDown)
+ {
+ ERR("Hot key pressed for Debug Activation! ShiftF12 = %d or F12 = %d\n",pHotKey->id == IDHK_SHIFTF12 , pHotKey->id == IDHK_F12);
+ //DoNotPostMsg = co_ActivateDebugger(); // FIXME
+ }
+ return DoNotPostMsg;
+ }
+
+ /* Process hotkey if it is key up event */
+ if (!bIsDown)
+ {
+ /* WIN and F12 keys are not hardcoded here. See comments on top of this file. */
++ if (pHotKey->id == IDHK_WINKEY && bWinHotkeyActive)
+ {
+ pWnd = ValidateHwndNoErr(InputWindowStation->ShellWindow);
+ if (pWnd)
+ {
+ TRACE("System Hot key Id %d Key %d\n",pHotKey->id, wVk );
+ UserPostMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_TASKLIST, 0);
+ co_IntShellHookNotify(HSHELL_TASKMAN, 0, 0);
+ bWinHotkeyActive = FALSE;
+ return FALSE;
+ }
+ }
+ }
+ else
+ { /* The user pressed the win key */
+ if (pHotKey->id == IDHK_WINKEY)
+ {
+ bWinHotkeyActive = TRUE;
+ return FALSE;
+ }
+ }
+
+ if (bIsDown)
+ {
+ if (!pHotKey->pWnd)
+ {
+ TRACE("UPTM Hot key Id %d Key %d\n",pHotKey->id, wVk );
+ UserPostThreadMessage(pHotKey->pti, WM_HOTKEY, pHotKey->id, MAKELONG(fModifiers, wVk));
+ //ptiLastInput = pHotKey->pti;
+ return TRUE; /* Don't send any message */
+ }
+ else
+ {
+ if (pHotKey->pWnd == PWND_BOTTOM)
+ {
+ if (gpqForeground != NULL)
+ {
+ pWnd = gpqForeground->spwndFocus;
+ }
+ else
+ return FALSE;
+ }
+ else
+ {
+ pWnd = pHotKey->pWnd;
+ }
+ if (pWnd)
+ { // pWnd->head.rpdesk->pDeskInfo->spwndShell needs testing.
+ if (pWnd == ValidateHwndNoErr(InputWindowStation->ShellWindow) && pHotKey->id == SC_TASKLIST)
+ {
+ ERR("Sending to shell window w/o IDHK_WINKEY..\n");
+ UserPostMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_TASKLIST, 0);
+ }
+ else
+ {
+ TRACE("UPM Hot key Id %d Key %d\n",pHotKey->id, wVk );
+ UserPostMessage(UserHMGetHandle(pWnd), WM_HOTKEY, pHotKey->id, MAKELONG(fModifiers, wVk));
+ }
+ //ptiLastInput = pWnd->head.pti;
+ return TRUE; /* Don't send any message */
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+ * DefWndGetHotKey
+ *
+ * GetHotKey message support
+ */
+UINT FASTCALL
+DefWndGetHotKey(PWND pWnd)
+{
+ PHOT_KEY pHotKey = gphkFirst;
+
+ WARN("DefWndGetHotKey\n");
+
+ while (pHotKey)
+ {
+ if (pHotKey->pWnd == pWnd && pHotKey->id == IDHK_REACTOS)
+ {
+ /* We have found it */
+ return MAKELONG(pHotKey->vk, pHotKey->fsModifiers);
+ }
+
+ /* Move to the next entry */
+ pHotKey = pHotKey->pNext;
+ }
+
+ return 0;
+}
+
+/*
+ * DefWndSetHotKey
+ *
+ * SetHotKey message support
+ */
+INT FASTCALL
+DefWndSetHotKey(PWND pWnd, WPARAM wParam)
+{
+ UINT fsModifiers, vk;
+ PHOT_KEY pHotKey, *pLink;
+ INT iRet = 1;
+
+ WARN("DefWndSetHotKey wParam 0x%x\n", wParam);
+
+ // A hot key cannot be associated with a child window.
+ if (pWnd->style & WS_CHILD)
+ return 0;
+
+ // VK_ESCAPE, VK_SPACE, and VK_TAB are invalid hot keys.
+ if (LOWORD(wParam) == VK_ESCAPE ||
+ LOWORD(wParam) == VK_SPACE ||
+ LOWORD(wParam) == VK_TAB)
+ {
+ return -1;
+ }
+
+ vk = LOWORD(wParam);
+ fsModifiers = HIWORD(wParam);
+
+ if (wParam)
+ {
+ pHotKey = gphkFirst;
+ while (pHotKey)
+ {
+ if (pHotKey->fsModifiers == fsModifiers &&
+ pHotKey->vk == vk &&
+ pHotKey->id == IDHK_REACTOS)
+ {
+ if (pHotKey->pWnd != pWnd)
+ iRet = 2; // Another window already has the same hot key.
+ break;
+ }
+
+ /* Move to the next entry */
+ pHotKey = pHotKey->pNext;
+ }
+ }
+
+ pHotKey = gphkFirst;
+ pLink = &gphkFirst;
+ while (pHotKey)
+ {
+ if (pHotKey->pWnd == pWnd &&
+ pHotKey->id == IDHK_REACTOS)
+ {
+ /* This window has already hotkey registered */
+ break;
+ }
+
+ /* Move to the next entry */
+ pLink = &pHotKey->pNext;
+ pHotKey = pHotKey->pNext;
+ }
+
+ if (wParam)
+ {
+ if (!pHotKey)
+ {
+ /* Create new hotkey */
+ pHotKey = ExAllocatePoolWithTag(PagedPool, sizeof(HOT_KEY), USERTAG_HOTKEY);
+ if (pHotKey == NULL)
+ return 0;
+
+ pHotKey->pWnd = pWnd;
+ pHotKey->id = IDHK_REACTOS; // Don't care, these hot keys are unrelated to the hot keys set by RegisterHotKey
+ pHotKey->pNext = gphkFirst;
+ gphkFirst = pHotKey;
+ }
+
+ /* A window can only have one hot key. If the window already has a
+ hot key associated with it, the new hot key replaces the old one. */
+ pHotKey->pti = NULL;
+ pHotKey->fsModifiers = fsModifiers;
+ pHotKey->vk = vk;
+ }
+ else if (pHotKey)
+ {
+ /* Remove hotkey */
+ *pLink = pHotKey->pNext;
+ ExFreePoolWithTag(pHotKey, USERTAG_HOTKEY);
+ }
+
+ return iRet;
+}
+
+
+BOOL FASTCALL
+UserRegisterHotKey(PWND pWnd,
+ int id,
+ UINT fsModifiers,
+ UINT vk)
+{
+ PHOT_KEY pHotKey;
+ PTHREADINFO pHotKeyThread;
+
+ /* Find hotkey thread */
+ if (pWnd == NULL || pWnd == PWND_BOTTOM)
+ {
+ pHotKeyThread = PsGetCurrentThreadWin32Thread();
+ }
+ else
+ {
+ pHotKeyThread = pWnd->head.pti;
+ }
+
+ /* Check for existing hotkey */
+ if (IsHotKey(fsModifiers, vk))
+ {
+ EngSetLastError(ERROR_HOTKEY_ALREADY_REGISTERED);
+ WARN("Hotkey already exists\n");
+ return FALSE;
+ }
+
+ /* Create new hotkey */
+ pHotKey = ExAllocatePoolWithTag(PagedPool, sizeof(HOT_KEY), USERTAG_HOTKEY);
+ if (pHotKey == NULL)
+ {
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ pHotKey->pti = pHotKeyThread;
+ pHotKey->pWnd = pWnd;
+ pHotKey->fsModifiers = fsModifiers;
+ pHotKey->vk = vk;
+ pHotKey->id = id;
+
+ /* Insert hotkey to the global list */
+ pHotKey->pNext = gphkFirst;
+ gphkFirst = pHotKey;
+
+ return TRUE;
+}
+
+BOOL FASTCALL
+UserUnregisterHotKey(PWND pWnd, int id)
+{
+ PHOT_KEY pHotKey = gphkFirst, phkNext, *pLink = &gphkFirst;
+ BOOL bRet = FALSE;
+
+ while (pHotKey)
+ {
+ /* Save next ptr for later use */
+ phkNext = pHotKey->pNext;
+
+ /* Should we delete this hotkey? */
+ if (pHotKey->pWnd == pWnd && pHotKey->id == id)
+ {
+ /* Update next ptr for previous hotkey and free memory */
+ *pLink = phkNext;
+ ExFreePoolWithTag(pHotKey, USERTAG_HOTKEY);
+
+ bRet = TRUE;
+ }
+ else /* This hotkey will stay, use its next ptr */
+ pLink = &pHotKey->pNext;
+
+ /* Move to the next entry */
+ pHotKey = phkNext;
+ }
+ return bRet;
+}
+
+
+/* SYSCALLS *****************************************************************/
+
+
+BOOL APIENTRY
+NtUserRegisterHotKey(HWND hWnd,
+ int id,
+ UINT fsModifiers,
+ UINT vk)
+{
+ PHOT_KEY pHotKey;
+ PWND pWnd = NULL;
+ PTHREADINFO pHotKeyThread;
+ BOOL bRet = FALSE;
+
+ TRACE("Enter NtUserRegisterHotKey\n");
+
+ if (fsModifiers & ~(MOD_ALT|MOD_CONTROL|MOD_SHIFT|MOD_WIN)) // FIXME: Does Win2k3 support MOD_NOREPEAT?
+ {
+ WARN("Invalid modifiers: %x\n", fsModifiers);
+ EngSetLastError(ERROR_INVALID_FLAGS);
+ return 0;
+ }
+
+ UserEnterExclusive();
+
+ /* Find hotkey thread */
+ if (hWnd == NULL)
+ {
+ pHotKeyThread = gptiCurrent;
+ }
+ else
+ {
+ pWnd = UserGetWindowObject(hWnd);
+ if (!pWnd)
+ goto cleanup;
+
+ pHotKeyThread = pWnd->head.pti;
+
+ /* Fix wine msg "Window on another thread" test_hotkey */
+ if (pWnd->head.pti != gptiCurrent)
+ {
+ EngSetLastError(ERROR_WINDOW_OF_OTHER_THREAD);
+ WARN("Must be from the same Thread.\n");
+ goto cleanup;
+ }
+ }
+
+ /* Check for existing hotkey */
+ if (IsHotKey(fsModifiers, vk))
+ {
+ EngSetLastError(ERROR_HOTKEY_ALREADY_REGISTERED);
+ WARN("Hotkey already exists\n");
+ goto cleanup;
+ }
+
+ /* Create new hotkey */
+ pHotKey = ExAllocatePoolWithTag(PagedPool, sizeof(HOT_KEY), USERTAG_HOTKEY);
+ if (pHotKey == NULL)
+ {
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto cleanup;
+ }
+
+ pHotKey->pti = pHotKeyThread;
+ pHotKey->pWnd = pWnd;
+ pHotKey->fsModifiers = fsModifiers;
+ pHotKey->vk = vk;
+ pHotKey->id = id;
+
+ /* Insert hotkey to the global list */
+ pHotKey->pNext = gphkFirst;
+ gphkFirst = pHotKey;
+
+ bRet = TRUE;
+
+cleanup:
+ TRACE("Leave NtUserRegisterHotKey, ret=%i\n", bRet);
+ UserLeave();
+ return bRet;
+}
+
+
+BOOL APIENTRY
+NtUserUnregisterHotKey(HWND hWnd, int id)
+{
+ PHOT_KEY pHotKey = gphkFirst, phkNext, *pLink = &gphkFirst;
+ BOOL bRet = FALSE;
+ PWND pWnd = NULL;
+
+ TRACE("Enter NtUserUnregisterHotKey\n");
+ UserEnterExclusive();
+
+ /* Fail if given window is invalid */
+ if (hWnd && !(pWnd = UserGetWindowObject(hWnd)))
+ goto cleanup;
+
+ while (pHotKey)
+ {
+ /* Save next ptr for later use */
+ phkNext = pHotKey->pNext;
+
+ /* Should we delete this hotkey? */
+ if (pHotKey->pWnd == pWnd && pHotKey->id == id)
+ {
+ /* Update next ptr for previous hotkey and free memory */
+ *pLink = phkNext;
+ ExFreePoolWithTag(pHotKey, USERTAG_HOTKEY);
+
+ bRet = TRUE;
+ }
+ else /* This hotkey will stay, use its next ptr */
+ pLink = &pHotKey->pNext;
+
+ /* Move to the next entry */
+ pHotKey = phkNext;
+ }
+
+cleanup:
+ TRACE("Leave NtUserUnregisterHotKey, ret=%i\n", bRet);
+ UserLeave();
+ return bRet;
+}
+
+/* EOF */
--- /dev/null
- if (Ret == TRUE)
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Win32k subsystem
+ * PURPOSE: Messages
+ * FILE: subsystems/win32/win32k/ntuser/message.c
+ * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ */
+
+#include <win32k.h>
+
+#include <dde.h>
+
+DBG_DEFAULT_CHANNEL(UserMsg);
+
+#define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE)
+
+/* FUNCTIONS *****************************************************************/
+
+NTSTATUS FASTCALL
+IntInitMessageImpl(VOID)
+{
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS FASTCALL
+IntCleanupMessageImpl(VOID)
+{
+ return STATUS_SUCCESS;
+}
+
+/* From wine: */
+/* flag for messages that contain pointers */
+/* 32 messages per entry, messages 0..31 map to bits 0..31 */
+
+#define SET(msg) (1 << ((msg) & 31))
+
+static const unsigned int message_pointer_flags[] =
+{
+ /* 0x00 - 0x1f */
+ SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) |
+ SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
+ /* 0x20 - 0x3f */
+ SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM) |
+ SET(WM_COMPAREITEM),
+ /* 0x40 - 0x5f */
+ SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) |
+ SET(WM_COPYGLOBALDATA) | SET(WM_NOTIFY) | SET(WM_HELP),
+ /* 0x60 - 0x7f */
+ SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED),
+ /* 0x80 - 0x9f */
+ SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE),
+ /* 0xa0 - 0xbf */
+ SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP),
+ /* 0xc0 - 0xdf */
+ SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS),
+ /* 0xe0 - 0xff */
+ SET(SBM_GETRANGE) | SET(SBM_SETSCROLLINFO) | SET(SBM_GETSCROLLINFO) | SET(SBM_GETSCROLLBARINFO),
+ /* 0x100 - 0x11f */
+ 0,
+ /* 0x120 - 0x13f */
+ 0,
+ /* 0x140 - 0x15f */
+ SET(CB_GETEDITSEL) | SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) |
+ SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) |
+ SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT),
+ /* 0x160 - 0x17f */
+ 0,
+ /* 0x180 - 0x19f */
+ SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) |
+ SET(LB_DIR) | SET(LB_FINDSTRING) |
+ SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT),
+ /* 0x1a0 - 0x1bf */
+ SET(LB_FINDSTRINGEXACT),
+ /* 0x1c0 - 0x1df */
+ 0,
+ /* 0x1e0 - 0x1ff */
+ 0,
+ /* 0x200 - 0x21f */
+ SET(WM_NEXTMENU) | SET(WM_SIZING) | SET(WM_MOVING) | SET(WM_DEVICECHANGE),
+ /* 0x220 - 0x23f */
+ SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) |
+ SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGLOOP) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE),
+ /* 0x240 - 0x25f */
+ 0,
+ /* 0x260 - 0x27f */
+ 0,
+ /* 0x280 - 0x29f */
+ 0,
+ /* 0x2a0 - 0x2bf */
+ 0,
+ /* 0x2c0 - 0x2df */
+ 0,
+ /* 0x2e0 - 0x2ff */
+ 0,
+ /* 0x300 - 0x31f */
+ SET(WM_ASKCBFORMATNAME)
+};
+
+/* check whether a given message type includes pointers */
+static inline int is_pointer_message( UINT message )
+{
+ if (message >= 8*sizeof(message_pointer_flags)) return FALSE;
+ return (message_pointer_flags[message / 32] & SET(message)) != 0;
+}
+#undef SET
+
+#define MMS_SIZE_WPARAM -1
+#define MMS_SIZE_WPARAMWCHAR -2
+#define MMS_SIZE_LPARAMSZ -3
+#define MMS_SIZE_SPECIAL -4
+#define MMS_FLAG_READ 0x01
+#define MMS_FLAG_WRITE 0x02
+#define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
+typedef struct tagMSGMEMORY
+{
+ UINT Message;
+ UINT Size;
+ INT Flags;
+}
+MSGMEMORY, *PMSGMEMORY;
+
+static MSGMEMORY g_MsgMemory[] =
+{
+ { WM_CREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
+ { WM_DDE_ACK, sizeof(KMDDELPARAM), MMS_FLAG_READ },
+ { WM_DDE_EXECUTE, MMS_SIZE_WPARAM, MMS_FLAG_READ },
+ { WM_GETMINMAXINFO, sizeof(MINMAXINFO), MMS_FLAG_READWRITE },
+ { WM_GETTEXT, MMS_SIZE_WPARAMWCHAR, MMS_FLAG_WRITE },
+ { WM_NCCALCSIZE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
+ { WM_NCCREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
+ { WM_SETTEXT, MMS_SIZE_LPARAMSZ, MMS_FLAG_READ },
+ { WM_STYLECHANGED, sizeof(STYLESTRUCT), MMS_FLAG_READ },
+ { WM_STYLECHANGING, sizeof(STYLESTRUCT), MMS_FLAG_READWRITE },
+ { WM_SETTINGCHANGE, MMS_SIZE_LPARAMSZ, MMS_FLAG_READ },
+ { WM_COPYDATA, MMS_SIZE_SPECIAL, MMS_FLAG_READ },
+ { WM_COPYGLOBALDATA, MMS_SIZE_WPARAM, MMS_FLAG_READ },
+ { WM_WINDOWPOSCHANGED, sizeof(WINDOWPOS), MMS_FLAG_READWRITE },
+ { WM_WINDOWPOSCHANGING, sizeof(WINDOWPOS), MMS_FLAG_READWRITE },
+ { WM_SIZING, sizeof(RECT), MMS_FLAG_READWRITE },
+ { WM_MOVING, sizeof(RECT), MMS_FLAG_READWRITE },
+};
+
+static PMSGMEMORY FASTCALL
+FindMsgMemory(UINT Msg)
+{
+ PMSGMEMORY MsgMemoryEntry;
+
+ /* See if this message type is present in the table */
+ for (MsgMemoryEntry = g_MsgMemory;
+ MsgMemoryEntry < g_MsgMemory + sizeof(g_MsgMemory) / sizeof(MSGMEMORY);
+ MsgMemoryEntry++)
+ {
+ if (Msg == MsgMemoryEntry->Message)
+ {
+ return MsgMemoryEntry;
+ }
+ }
+
+ return NULL;
+}
+
+static UINT FASTCALL
+MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
+{
+ CREATESTRUCTW *Cs;
+ PUNICODE_STRING WindowName;
+ PUNICODE_STRING ClassName;
+ UINT Size = 0;
+
+ _SEH2_TRY
+ {
+ if (MMS_SIZE_WPARAM == MsgMemoryEntry->Size)
+ {
+ Size = (UINT)wParam;
+ }
+ else if (MMS_SIZE_WPARAMWCHAR == MsgMemoryEntry->Size)
+ {
+ Size = (UINT) (wParam * sizeof(WCHAR));
+ }
+ else if (MMS_SIZE_LPARAMSZ == MsgMemoryEntry->Size)
+ {
+ // WM_SETTEXT and WM_SETTINGCHANGE can be null!
+ if (!lParam)
+ {
+ TRACE("lParam is NULL!\n");
+ Size = 0;
+ }
+ else
+ Size = (UINT) ((wcslen((PWSTR) lParam) + 1) * sizeof(WCHAR));
+ }
+ else if (MMS_SIZE_SPECIAL == MsgMemoryEntry->Size)
+ {
+ switch(MsgMemoryEntry->Message)
+ {
+ case WM_CREATE:
+ case WM_NCCREATE:
+ Cs = (CREATESTRUCTW *) lParam;
+ WindowName = (PUNICODE_STRING) Cs->lpszName;
+ ClassName = (PUNICODE_STRING) Cs->lpszClass;
+ Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
+ if (IS_ATOM(ClassName->Buffer))
+ {
+ Size += sizeof(WCHAR) + sizeof(ATOM);
+ }
+ else
+ {
+ Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
+ }
+ break;
+
+ case WM_NCCALCSIZE:
+ Size = wParam ? sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS) : sizeof(RECT);
+ break;
+
+ case WM_COPYDATA:
+ Size = sizeof(COPYDATASTRUCT) + ((PCOPYDATASTRUCT)lParam)->cbData;
+ break;
+
+ default:
+ ASSERT(FALSE);
+ Size = 0;
+ break;
+ }
+ }
+ else
+ {
+ Size = MsgMemoryEntry->Size;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ERR("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH2_GetExceptionCode());
+ Size = 0;
+ }
+ _SEH2_END;
+ return Size;
+}
+
+UINT lParamMemorySize(UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ PMSGMEMORY MsgMemoryEntry = FindMsgMemory(Msg);
+ if(MsgMemoryEntry == NULL) return 0;
+ return MsgMemorySize(MsgMemoryEntry, wParam, lParam);
+}
+
+static NTSTATUS
+PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL NonPagedPoolNeeded)
+{
+ NCCALCSIZE_PARAMS *UnpackedNcCalcsize;
+ NCCALCSIZE_PARAMS *PackedNcCalcsize;
+ CREATESTRUCTW *UnpackedCs;
+ CREATESTRUCTW *PackedCs;
+ PLARGE_STRING WindowName;
+ PUNICODE_STRING ClassName;
+ POOL_TYPE PoolType;
+ UINT Size;
+ PCHAR CsData;
+
+ *lParamPacked = lParam;
+
+ if (NonPagedPoolNeeded)
+ PoolType = NonPagedPool;
+ else
+ PoolType = PagedPool;
+
+ if (WM_NCCALCSIZE == Msg && wParam)
+ {
+
+ UnpackedNcCalcsize = (NCCALCSIZE_PARAMS *) lParam;
+ PackedNcCalcsize = ExAllocatePoolWithTag(PoolType,
+ sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS),
+ TAG_MSG);
+
+ if (NULL == PackedNcCalcsize)
+ {
+ ERR("Not enough memory to pack lParam\n");
+ return STATUS_NO_MEMORY;
+ }
+ RtlCopyMemory(PackedNcCalcsize, UnpackedNcCalcsize, sizeof(NCCALCSIZE_PARAMS));
+ PackedNcCalcsize->lppos = (PWINDOWPOS) (PackedNcCalcsize + 1);
+ RtlCopyMemory(PackedNcCalcsize->lppos, UnpackedNcCalcsize->lppos, sizeof(WINDOWPOS));
+ *lParamPacked = (LPARAM) PackedNcCalcsize;
+ }
+ else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
+ {
+ UnpackedCs = (CREATESTRUCTW *) lParam;
+ WindowName = (PLARGE_STRING) UnpackedCs->lpszName;
+ ClassName = (PUNICODE_STRING) UnpackedCs->lpszClass;
+ Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
+ if (IS_ATOM(ClassName->Buffer))
+ {
+ Size += sizeof(WCHAR) + sizeof(ATOM);
+ }
+ else
+ {
+ Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
+ }
+ PackedCs = ExAllocatePoolWithTag(PoolType, Size, TAG_MSG);
+ if (NULL == PackedCs)
+ {
+ ERR("Not enough memory to pack lParam\n");
+ return STATUS_NO_MEMORY;
+ }
+ RtlCopyMemory(PackedCs, UnpackedCs, sizeof(CREATESTRUCTW));
+ CsData = (PCHAR) (PackedCs + 1);
+ PackedCs->lpszName = (LPCWSTR) (CsData - (PCHAR) PackedCs);
+ RtlCopyMemory(CsData, WindowName->Buffer, WindowName->Length);
+ CsData += WindowName->Length;
+ *((WCHAR *) CsData) = L'\0';
+ CsData += sizeof(WCHAR);
+ PackedCs->lpszClass = (LPCWSTR) (CsData - (PCHAR) PackedCs);
+ if (IS_ATOM(ClassName->Buffer))
+ {
+ *((WCHAR *) CsData) = L'A';
+ CsData += sizeof(WCHAR);
+ *((ATOM *) CsData) = (ATOM)(DWORD_PTR) ClassName->Buffer;
+ CsData += sizeof(ATOM);
+ }
+ else
+ {
+ *((WCHAR *) CsData) = L'S';
+ CsData += sizeof(WCHAR);
+ RtlCopyMemory(CsData, ClassName->Buffer, ClassName->Length);
+ CsData += ClassName->Length;
+ *((WCHAR *) CsData) = L'\0';
+ CsData += sizeof(WCHAR);
+ }
+ ASSERT(CsData == (PCHAR) PackedCs + Size);
+ *lParamPacked = (LPARAM) PackedCs;
+ }
+ else if (PoolType == NonPagedPool)
+ {
+ PMSGMEMORY MsgMemoryEntry;
+ PVOID PackedData;
+ SIZE_T size;
+
+ MsgMemoryEntry = FindMsgMemory(Msg);
+
+ if (!MsgMemoryEntry)
+ {
+ /* Keep previous behavior */
+ return STATUS_SUCCESS;
+ }
+ size = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
+ if (!size)
+ {
+ ERR("No size for lParamPacked\n");
+ return STATUS_SUCCESS;
+ }
+ PackedData = ExAllocatePoolWithTag(NonPagedPool, size, TAG_MSG);
+ if (PackedData == NULL)
+ {
+ ERR("Not enough memory to pack lParam\n");
+ return STATUS_NO_MEMORY;
+ }
+ RtlCopyMemory(PackedData, (PVOID)lParam, MsgMemorySize(MsgMemoryEntry, wParam, lParam));
+ *lParamPacked = (LPARAM)PackedData;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL NonPagedPoolUsed)
+{
+ NCCALCSIZE_PARAMS *UnpackedParams;
+ NCCALCSIZE_PARAMS *PackedParams;
+ PWINDOWPOS UnpackedWindowPos;
+
+ if (lParamPacked == lParam)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ if (WM_NCCALCSIZE == Msg && wParam)
+ {
+ PackedParams = (NCCALCSIZE_PARAMS *) lParamPacked;
+ UnpackedParams = (NCCALCSIZE_PARAMS *) lParam;
+ UnpackedWindowPos = UnpackedParams->lppos;
+ RtlCopyMemory(UnpackedParams, PackedParams, sizeof(NCCALCSIZE_PARAMS));
+ UnpackedParams->lppos = UnpackedWindowPos;
+ RtlCopyMemory(UnpackedWindowPos, PackedParams + 1, sizeof(WINDOWPOS));
+ ExFreePool((PVOID) lParamPacked);
+
+ return STATUS_SUCCESS;
+ }
+ else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
+ {
+ ExFreePool((PVOID) lParamPacked);
+
+ return STATUS_SUCCESS;
+ }
+ else if (NonPagedPoolUsed)
+ {
+ PMSGMEMORY MsgMemoryEntry;
+ MsgMemoryEntry = FindMsgMemory(Msg);
+ ASSERT(MsgMemoryEntry);
+
+ if (MsgMemoryEntry->Flags == MMS_FLAG_READWRITE)
+ {
+ //RtlCopyMemory((PVOID)lParam, (PVOID)lParamPacked, MsgMemoryEntry->Size);
+ }
+ ExFreePool((PVOID) lParamPacked);
+ return STATUS_SUCCESS;
+ }
+
+ ASSERT(FALSE);
+
+ return STATUS_INVALID_PARAMETER;
+}
+
+static NTSTATUS FASTCALL
+CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
+{
+ NTSTATUS Status;
+
+ PVOID KernelMem;
+ UINT Size;
+
+ *KernelModeMsg = *UserModeMsg;
+
+ /* See if this message type is present in the table */
+ if (NULL == MsgMemoryEntry)
+ {
+ /* Not present, no copying needed */
+ return STATUS_SUCCESS;
+ }
+
+ /* Determine required size */
+ Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
+
+ if (0 != Size)
+ {
+ /* Allocate kernel mem */
+ KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
+ if (NULL == KernelMem)
+ {
+ ERR("Not enough memory to copy message to kernel mem\n");
+ return STATUS_NO_MEMORY;
+ }
+ KernelModeMsg->lParam = (LPARAM) KernelMem;
+
+ /* Copy data if required */
+ if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
+ {
+ TRACE("Copy Message %d from usermode buffer\n", KernelModeMsg->message);
+ Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
+ if (! NT_SUCCESS(Status))
+ {
+ ERR("Failed to copy message to kernel: invalid usermode lParam buffer\n");
+ ExFreePoolWithTag(KernelMem, TAG_MSG);
+ return Status;
+ }
+ }
+ else
+ {
+ /* Make sure we don't pass any secrets to usermode */
+ RtlZeroMemory(KernelMem, Size);
+ }
+ }
+ else
+ {
+ KernelModeMsg->lParam = 0;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS FASTCALL
+CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
+{
+ NTSTATUS Status;
+ PMSGMEMORY MsgMemoryEntry;
+ UINT Size;
+
+ /* See if this message type is present in the table */
+ MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
+ if (NULL == MsgMemoryEntry)
+ {
+ /* Not present, no copying needed */
+ return STATUS_SUCCESS;
+ }
+
+ /* Determine required size */
+ Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
+
+ if (0 != Size)
+ {
+ /* Copy data if required */
+ if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
+ {
+ Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
+ if (! NT_SUCCESS(Status))
+ {
+ ERR("Failed to copy message from kernel: invalid usermode lParam buffer\n");
+ ExFreePool((PVOID) KernelModeMsg->lParam);
+ return Status;
+ }
+ }
+
+ ExFreePool((PVOID) KernelModeMsg->lParam);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//
+// Wakeup any thread/process waiting on idle input.
+//
+VOID FASTCALL
+IdlePing(VOID)
+{
+ PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
+ PTHREADINFO pti;
+
+ pti = PsGetCurrentThreadWin32Thread();
+
+ if ( pti )
+ {
+ pti->pClientInfo->cSpins = 0; // Reset spins.
+
+ if ( pti->pDeskInfo && pti == gptiForeground )
+ {
+ if ( pti->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) ||
+ pti->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) )
+ {
+ co_HOOK_CallHooks(WH_FOREGROUNDIDLE,HC_ACTION,0,0);
+ }
+ }
+ }
+
+ TRACE("IdlePing ppi %p\n", ppi);
+ if ( ppi && ppi->InputIdleEvent )
+ {
+ TRACE("InputIdleEvent\n");
+ KeSetEvent( ppi->InputIdleEvent, IO_NO_INCREMENT, FALSE);
+ }
+}
+
+VOID FASTCALL
+IdlePong(VOID)
+{
+ PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
+
+ TRACE("IdlePong ppi %p\n", ppi);
+ if ( ppi && ppi->InputIdleEvent )
+ {
+ KeClearEvent(ppi->InputIdleEvent);
+ }
+}
+
+UINT FASTCALL
+GetWakeMask(UINT first, UINT last )
+{
+ UINT mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */
+
+ if (first || last)
+ {
+ if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
+ if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
+ ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
+ if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
+ if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
+ if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
+ }
+ else mask = QS_ALLINPUT;
+
+ return mask;
+}
+
+static VOID FASTCALL
+IntCallWndProc( PWND Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL SameThread = FALSE;
+ CWPSTRUCT CWP;
+
+ if (Window->head.pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
+ SameThread = TRUE;
+
+ CWP.hwnd = hWnd;
+ CWP.message = Msg;
+ CWP.wParam = wParam;
+ CWP.lParam = lParam;
+ co_HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, SameThread, (LPARAM)&CWP );
+}
+
+static VOID FASTCALL
+IntCallWndProcRet ( PWND Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *uResult)
+{
+ BOOL SameThread = FALSE;
+ CWPRETSTRUCT CWPR;
+
+ if (Window->head.pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
+ SameThread = TRUE;
+
+ CWPR.hwnd = hWnd;
+ CWPR.message = Msg;
+ CWPR.wParam = wParam;
+ CWPR.lParam = lParam;
+ CWPR.lResult = uResult ? (*uResult) : 0;
+ co_HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, SameThread, (LPARAM)&CWPR );
+}
+
+static LRESULT handle_internal_message( PWND pWnd, UINT msg, WPARAM wparam, LPARAM lparam )
+{
+ LRESULT lRes;
+ USER_REFERENCE_ENTRY Ref;
+// PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+
+ if (!pWnd ||
+ pWnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
+ pWnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
+ return 0;
+
+ TRACE("Internal Event Msg %p hWnd 0x%x\n",msg,pWnd->head.h);
+
+ switch(msg)
+ {
+ case WM_ASYNC_SHOWWINDOW:
+ return co_WinPosShowWindow( pWnd, wparam );
+ case WM_ASYNC_SETWINDOWPOS:
+ {
+ PWINDOWPOS winpos = (PWINDOWPOS)lparam;
+ if (!winpos) return 0;
+ lRes = co_WinPosSetWindowPos( pWnd,
+ winpos->hwndInsertAfter,
+ winpos->x,
+ winpos->y,
+ winpos->cx,
+ winpos->cy,
+ winpos->flags);
+ ExFreePoolWithTag(winpos, USERTAG_SWP);
+ return lRes;
+ }
+ case WM_ASYNC_SETACTIVEWINDOW:
+ {
+ PWND Window = (PWND)wparam;
+ if (wparam) UserRefObjectCo(Window, &Ref);
+ lRes = (LRESULT)co_IntSetActiveWindow(Window,(BOOL)lparam,TRUE,TRUE);
+ if (wparam) UserDerefObjectCo(Window);
+ return lRes;
+ }
+ }
+ return 0;
+}
+
+LRESULT FASTCALL
+IntDispatchMessage(PMSG pMsg)
+{
+ LARGE_INTEGER TickCount;
+ LONG Time;
+ LRESULT retval = 0;
+ PTHREADINFO pti;
+ PWND Window = NULL;
+ BOOL DoCallBack = TRUE;
+
+ if (pMsg->hwnd)
+ {
+ Window = UserGetWindowObject(pMsg->hwnd);
+ if (!Window) return 0;
+ }
+
+ pti = PsGetCurrentThreadWin32Thread();
+
+ if ( Window && Window->head.pti != pti)
+ {
+ EngSetLastError( ERROR_MESSAGE_SYNC_ONLY );
+ return 0;
+ }
+
+ if (((pMsg->message == WM_SYSTIMER) ||
+ (pMsg->message == WM_TIMER)) &&
+ (pMsg->lParam) )
+ {
+ if (pMsg->message == WM_TIMER)
+ {
+ if (ValidateTimerCallback(pti,pMsg->lParam))
+ {
+ KeQueryTickCount(&TickCount);
+ Time = MsqCalculateMessageTime(&TickCount);
+ retval = co_IntCallWindowProc((WNDPROC)pMsg->lParam,
+ TRUE,
+ pMsg->hwnd,
+ WM_TIMER,
+ pMsg->wParam,
+ (LPARAM)Time,
+ -1);
+ }
+ return retval;
+ }
+ else
+ {
+ PTIMER pTimer = FindSystemTimer(pMsg);
+ if (pTimer && pTimer->pfn)
+ {
+ KeQueryTickCount(&TickCount);
+ Time = MsqCalculateMessageTime(&TickCount);
+ pTimer->pfn(pMsg->hwnd, WM_SYSTIMER, (UINT)pMsg->wParam, Time);
+ }
+ return 0;
+ }
+ }
+ // Need a window!
+ if ( !Window ) return 0;
+
+ if (pMsg->message == WM_PAINT) Window->state |= WNDS_PAINTNOTPROCESSED;
+
+ if ( Window->state & WNDS_SERVERSIDEWINDOWPROC )
+ {
+ TRACE("Dispatch: Server Side Window Procedure\n");
+ switch(Window->fnid)
+ {
+ case FNID_DESKTOP:
+ DoCallBack = !DesktopWindowProc( Window,
+ pMsg->message,
+ pMsg->wParam,
+ pMsg->lParam,
+ &retval);
+ break;
+ case FNID_MESSAGEWND:
+ DoCallBack = !UserMessageWindowProc( Window,
+ pMsg->message,
+ pMsg->wParam,
+ pMsg->lParam,
+ &retval);
+ break;
+ }
+ }
+
+ /* Since we are doing a callback on the same thread right away, there is
+ no need to copy the lparam to kernel mode and then back to usermode.
+ We just pretend it isn't a pointer */
+
+ if (DoCallBack)
+ retval = co_IntCallWindowProc( Window->lpfnWndProc,
+ !Window->Unicode,
+ pMsg->hwnd,
+ pMsg->message,
+ pMsg->wParam,
+ pMsg->lParam,
+ -1);
+
+ if (pMsg->message == WM_PAINT)
+ {
+ PREGION Rgn;
+ Window->state2 &= ~WNDS2_WMPAINTSENT;
+ /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
+ Rgn = IntSysCreateRectpRgn( 0, 0, 0, 0 );
+ co_UserGetUpdateRgn( Window, Rgn, TRUE );
+ REGION_Delete(Rgn);
+ }
+
+ return retval;
+}
+
+/*
+ * Internal version of PeekMessage() doing all the work
+ *
+ * MSDN:
+ * Sent messages
+ * Posted messages
+ * Input (hardware) messages and system internal events
+ * Sent messages (again)
+ * WM_PAINT messages
+ * WM_TIMER messages
+ */
+BOOL FASTCALL
+co_IntPeekMessage( PMSG Msg,
+ PWND Window,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax,
+ UINT RemoveMsg,
+ BOOL bGMSG )
+{
+ PTHREADINFO pti;
+ LARGE_INTEGER LargeTickCount;
+ BOOL RemoveMessages;
+ UINT ProcessMask;
+ BOOL Hit = FALSE;
+
+ pti = PsGetCurrentThreadWin32Thread();
+
+ RemoveMessages = RemoveMsg & PM_REMOVE;
+ ProcessMask = HIWORD(RemoveMsg);
+
+ /* Hint, "If wMsgFilterMin and wMsgFilterMax are both zero, PeekMessage returns
+ all available messages (that is, no range filtering is performed)". */
+ if (!ProcessMask) ProcessMask = (QS_ALLPOSTMESSAGE|QS_ALLINPUT);
+
+ IdlePong();
+
+ do
+ {
+ KeQueryTickCount(&LargeTickCount);
+ pti->timeLast = LargeTickCount.u.LowPart;
+ pti->pcti->tickLastMsgChecked = LargeTickCount.u.LowPart;
+
+ /* Dispatch sent messages here. */
+ while ( co_MsqDispatchOneSentMessage(pti) )
+ {
+ /* if some PM_QS* flags were specified, only handle sent messages from now on */
+ if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE; // wine does this; ProcessMask = QS_SENDMESSAGE;
+ }
+ if (Hit) return FALSE;
+
+ /* Clear changed bits so we can wait on them if we don't find a message */
+ if (ProcessMask & QS_POSTMESSAGE)
+ {
+ pti->pcti->fsChangeBits &= ~(QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER);
+ if (MsgFilterMin == 0 && MsgFilterMax == 0) // Wine hack does this; ~0U)
+ {
+ pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
+ }
+ }
+
+ if (ProcessMask & QS_INPUT)
+ {
+ pti->pcti->fsChangeBits &= ~QS_INPUT;
+ }
+
+ /* Now check for normal messages. */
+ if (( (ProcessMask & QS_POSTMESSAGE) ||
+ (ProcessMask & QS_HOTKEY) ) &&
+ MsqPeekMessage( pti,
+ RemoveMessages,
+ Window,
+ MsgFilterMin,
+ MsgFilterMax,
+ ProcessMask,
+ Msg ))
+ {
+ return TRUE;
+ }
+
+ /* Now look for a quit message. */
+ if (pti->QuitPosted)
+ {
+ /* According to the PSDK, WM_QUIT messages are always returned, regardless
+ of the filter specified */
+ Msg->hwnd = NULL;
+ Msg->message = WM_QUIT;
+ Msg->wParam = pti->exitCode;
+ Msg->lParam = 0;
+ if (RemoveMessages)
+ {
+ pti->QuitPosted = FALSE;
+ ClearMsgBitsMask(pti, QS_POSTMESSAGE);
+ pti->pcti->fsWakeBits &= ~QS_ALLPOSTMESSAGE;
+ pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
+ }
+ return TRUE;
+ }
+
+ if ((ProcessMask & QS_MOUSE) &&
+ co_MsqPeekMouseMove( pti,
+ RemoveMessages,
+ Window,
+ MsgFilterMin,
+ MsgFilterMax,
+ Msg ))
+ {
+ return TRUE;
+ }
+
+ /* Check for hardware events. */
+ if ((ProcessMask & QS_INPUT) &&
+ co_MsqPeekHardwareMessage( pti,
+ RemoveMessages,
+ Window,
+ MsgFilterMin,
+ MsgFilterMax,
+ ProcessMask,
+ Msg))
+ {
+ return TRUE;
+ }
+
+ /* Check for sent messages again. */
+ while ( co_MsqDispatchOneSentMessage(pti) )
+ {
+ if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE;
+ }
+ if (Hit) return FALSE;
+
+ /* Check for paint messages. */
+ if ((ProcessMask & QS_PAINT) &&
+ pti->cPaintsReady &&
+ IntGetPaintMessage( Window,
+ MsgFilterMin,
+ MsgFilterMax,
+ pti,
+ Msg,
+ RemoveMessages))
+ {
+ return TRUE;
+ }
+
+ /* This is correct, check for the current threads timers waiting to be
+ posted to this threads message queue. If any we loop again.
+ */
+ if ((ProcessMask & QS_TIMER) &&
+ PostTimerMessages(Window))
+ {
+ continue;
+ }
+
+ return FALSE;
+ }
+ while (TRUE);
+
+ return TRUE;
+}
+
+static BOOL FASTCALL
+co_IntWaitMessage( PWND Window,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax )
+{
+ PTHREADINFO pti;
+ NTSTATUS Status = STATUS_SUCCESS;
+ MSG Msg;
+
+ pti = PsGetCurrentThreadWin32Thread();
+
+ do
+ {
+ if ( co_IntPeekMessage( &Msg, // Dont reenter!
+ Window,
+ MsgFilterMin,
+ MsgFilterMax,
+ MAKELONG( PM_NOREMOVE, GetWakeMask( MsgFilterMin, MsgFilterMax)),
+ TRUE ) ) // act like GetMessage.
+ {
+ return TRUE;
+ }
+
+ /* Nothing found. Wait for new messages. */
+ Status = co_MsqWaitForNewMessages( pti,
+ Window,
+ MsgFilterMin,
+ MsgFilterMax);
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ ERR("Exit co_IntWaitMessage on error!\n");
+ return FALSE;
+ }
+ if (Status == STATUS_USER_APC || Status == STATUS_TIMEOUT)
+ {
+ return FALSE;
+ }
+ }
+ while ( TRUE );
+
+ return FALSE;
+}
+
+BOOL FASTCALL
+co_IntGetPeekMessage( PMSG pMsg,
+ HWND hWnd,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax,
+ UINT RemoveMsg,
+ BOOL bGMSG )
+{
+ PWND Window;
+ PTHREADINFO pti;
+ BOOL Present = FALSE;
+ NTSTATUS Status;
+
+ if ( hWnd == HWND_TOPMOST || hWnd == HWND_BROADCAST )
+ hWnd = HWND_BOTTOM;
+
+ /* Validate input */
+ if (hWnd && hWnd != HWND_BOTTOM)
+ {
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ if (bGMSG)
+ return -1;
+ else
+ return FALSE;
+ }
+ }
+ else
+ {
+ Window = (PWND)hWnd;
+ }
+
+ if (MsgFilterMax < MsgFilterMin)
+ {
+ MsgFilterMin = 0;
+ MsgFilterMax = 0;
+ }
+
+ if (bGMSG)
+ {
+ RemoveMsg |= ((GetWakeMask( MsgFilterMin, MsgFilterMax ))<< 16);
+ }
+
+ pti = PsGetCurrentThreadWin32Thread();
+ pti->pClientInfo->cSpins++; // Bump up the spin count.
+
+ do
+ {
+ Present = co_IntPeekMessage( pMsg,
+ Window,
+ MsgFilterMin,
+ MsgFilterMax,
+ RemoveMsg,
+ bGMSG );
+ if (Present)
+ {
+ /* GetMessage or PostMessage must never get messages that contain pointers */
+ ASSERT(FindMsgMemory(pMsg->message) == NULL);
+
+ if (pMsg->message != WM_PAINT && pMsg->message != WM_QUIT)
+ {
+ pti->timeLast = pMsg->time;
+ pti->ptLast = pMsg->pt;
+ }
+
+ // The WH_GETMESSAGE hook enables an application to monitor messages about to
+ // be returned by the GetMessage or PeekMessage function.
+
+ co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)pMsg);
+
+ if ( bGMSG ) break;
+ }
+
+ if ( bGMSG )
+ {
+ Status = co_MsqWaitForNewMessages( pti,
+ Window,
+ MsgFilterMin,
+ MsgFilterMax);
+ if ( !NT_SUCCESS(Status) ||
+ Status == STATUS_USER_APC ||
+ Status == STATUS_TIMEOUT )
+ {
+ Present = -1;
+ break;
+ }
+ }
+ else
+ {
+ if (!(RemoveMsg & PM_NOYIELD))
+ {
+ IdlePing();
+ // Yield this thread!
+ UserLeave();
+ ZwYieldExecution();
+ UserEnterExclusive();
+ // Fall through to exit.
+ IdlePong();
+ }
+ break;
+ }
+ }
+ while( bGMSG && !Present );
+
+ // Been spinning, time to swap vinyl...
+ if (pti->pClientInfo->cSpins >= 100)
+ {
+ // Clear the spin cycle to fix the mix.
+ pti->pClientInfo->cSpins = 0;
+ //if (!(pti->TIF_flags & TIF_SPINNING)) // FIXME: Need to swap vinyl...
+ }
+ return Present;
+}
+
+BOOL FASTCALL
+UserPostThreadMessage( PTHREADINFO pti,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam )
+{
+ MSG Message;
+ LARGE_INTEGER LargeTickCount;
+
+ if (is_pointer_message(Msg))
+ {
+ EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
+ return FALSE;
+ }
+ Message.hwnd = NULL;
+ Message.message = Msg;
+ Message.wParam = wParam;
+ Message.lParam = lParam;
+ Message.pt = gpsi->ptCursor;
+
+ KeQueryTickCount(&LargeTickCount);
+ Message.time = MsqCalculateMessageTime(&LargeTickCount);
+ MsqPostMessage(pti, &Message, FALSE, QS_POSTMESSAGE, 0);
+ return TRUE;
+}
+
+PTHREADINFO FASTCALL
+IntSendTo(PWND Window, PTHREADINFO ptiCur, UINT Msg)
+{
+ if ( ptiCur )
+ {
+ if (!Window ||
+ Window->head.pti->MessageQueue == ptiCur->MessageQueue )
+ {
+ return NULL;
+ }
+ }
+ return Window ? Window->head.pti : NULL;
+}
+
+BOOL FASTCALL
+UserPostMessage( HWND Wnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam )
+{
+ PTHREADINFO pti;
+ MSG Message, KernelModeMsg;
+ LARGE_INTEGER LargeTickCount;
+
+ Message.hwnd = Wnd;
+ Message.message = Msg;
+ Message.wParam = wParam;
+ Message.lParam = lParam;
+ Message.pt = gpsi->ptCursor;
+ KeQueryTickCount(&LargeTickCount);
+ Message.time = MsqCalculateMessageTime(&LargeTickCount);
+
+ if (is_pointer_message(Message.message))
+ {
+ EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
+ return FALSE;
+ }
+
+ if( Msg >= WM_DDE_FIRST && Msg <= WM_DDE_LAST )
+ {
+ NTSTATUS Status;
+ PMSGMEMORY MsgMemoryEntry;
+
+ MsgMemoryEntry = FindMsgMemory(Message.message);
+
+ Status = CopyMsgToKernelMem(&KernelModeMsg, &Message, MsgMemoryEntry);
+ if (! NT_SUCCESS(Status))
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ co_IntSendMessageNoWait(KernelModeMsg.hwnd,
+ KernelModeMsg.message,
+ KernelModeMsg.wParam,
+ KernelModeMsg.lParam);
+
+ if (MsgMemoryEntry && KernelModeMsg.lParam)
+ ExFreePool((PVOID) KernelModeMsg.lParam);
+
+ return TRUE;
+ }
+
+ if (!Wnd)
+ {
+ pti = PsGetCurrentThreadWin32Thread();
+ return UserPostThreadMessage( pti,
+ Msg,
+ wParam,
+ lParam);
+ }
+ if (Wnd == HWND_BROADCAST)
+ {
+ HWND *List;
+ PWND DesktopWindow;
+ ULONG i;
+
+ DesktopWindow = UserGetDesktopWindow();
+ List = IntWinListChildren(DesktopWindow);
+
+ if (List != NULL)
+ {
+ UserPostMessage(DesktopWindow->head.h, Msg, wParam, lParam);
+ for (i = 0; List[i]; i++)
+ {
+ PWND pwnd = UserGetWindowObject(List[i]);
+ if (!pwnd) continue;
+
+ if ( pwnd->fnid == FNID_MENU || // Also need pwnd->pcls->atomClassName == gaOleMainThreadWndClass
+ pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
+ continue;
+
+ UserPostMessage(List[i], Msg, wParam, lParam);
+ }
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ }
+ }
+ else
+ {
+ PWND Window;
+
+ Window = UserGetWindowObject(Wnd);
+ if ( !Window )
+ {
+ ERR("UserPostMessage: Invalid handle 0x%p Msg %d!\n",Wnd,Msg);
+ return FALSE;
+ }
+
+ pti = Window->head.pti;
+ if ( pti->TIF_flags & TIF_INCLEANUP )
+ {
+ ERR("Attempted to post message to window %p when the thread is in cleanup!\n", Wnd);
+ return FALSE;
+ }
+
+ if ( Window->state & WNDS_DESTROYED )
+ {
+ ERR("Attempted to post message to window %p that is being destroyed!\n", Wnd);
+ /* FIXME: Last error code? */
+ return FALSE;
+ }
+
+ if (WM_QUIT == Msg)
+ {
+ MsqPostQuitMessage(pti, wParam);
+ }
+ else
+ {
+ MsqPostMessage(pti, &Message, FALSE, QS_POSTMESSAGE, 0);
+ }
+ }
+ return TRUE;
+}
+
+LRESULT FASTCALL
+co_IntSendMessage( HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam )
+{
+ ULONG_PTR Result = 0;
+ if(co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
+ {
+ return (LRESULT)Result;
+ }
+ return 0;
+}
+
+static LRESULT FASTCALL
+co_IntSendMessageTimeoutSingle( HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ UINT uFlags,
+ UINT uTimeout,
+ ULONG_PTR *uResult )
+{
+ NTSTATUS Status;
+ PWND Window = NULL;
+ PMSGMEMORY MsgMemoryEntry;
+ INT lParamBufferSize;
+ LPARAM lParamPacked;
+ PTHREADINFO Win32Thread, ptiSendTo = NULL;
+ ULONG_PTR Hi, Lo, Result = 0;
+ DECLARE_RETURN(LRESULT);
+ USER_REFERENCE_ENTRY Ref;
+ BOOL DoCallBack = TRUE;
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ TRACE("SendMessageTimeoutSingle: Invalid handle 0x%p!\n",hWnd);
+ RETURN( FALSE);
+ }
+
+ UserRefObjectCo(Window, &Ref);
+
+ Win32Thread = PsGetCurrentThreadWin32Thread();
+
+ ptiSendTo = IntSendTo(Window, Win32Thread, Msg);
+
+ if ( !ptiSendTo )
+ {
+ if (Win32Thread->TIF_flags & TIF_INCLEANUP)
+ {
+ /* Never send messages to exiting threads */
+ RETURN( FALSE);
+ }
+
+ if (Msg & 0x80000000)
+ {
+ TRACE("SMTS: Internal Message!\n");
+ Result = (ULONG_PTR)handle_internal_message( Window, Msg, wParam, lParam );
+ if (uResult) *uResult = Result;
+ RETURN( TRUE);
+ }
+
+ // Only happens when calling the client!
+ IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
+
+ if ( Window->state & WNDS_SERVERSIDEWINDOWPROC )
+ {
+ TRACE("SMT: Server Side Window Procedure\n");
+ IoGetStackLimits(&Lo, &Hi);
+ // Handle it here. Safeguard against excessive recursions.
+ if (((ULONG_PTR)&uResult - Lo) < 4096 )
+ {
+ ERR("Server Callback Exceeded Stack!\n");
+ RETURN( FALSE);
+ }
+ /* Return after server side call, IntCallWndProcRet will not be called. */
+ switch(Window->fnid)
+ {
+ case FNID_DESKTOP:
+ DoCallBack = !DesktopWindowProc(Window, Msg, wParam, lParam,(LRESULT*)&Result);
+ break;
+ case FNID_MESSAGEWND:
+ DoCallBack = !UserMessageWindowProc(Window, Msg, wParam, lParam,(LRESULT*)&Result);
+ break;
+ }
+ if (!DoCallBack)
+ {
+ if (uResult) *uResult = Result;
+ RETURN( TRUE);
+ }
+ }
+ /* See if this message type is present in the table */
+ MsgMemoryEntry = FindMsgMemory(Msg);
+ if (NULL == MsgMemoryEntry)
+ {
+ lParamBufferSize = -1;
+ }
+ else
+ {
+ lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
+ // If zero, do not allow callback on client side to allocate a buffer!!!!! See CORE-7695.
+ if (!lParamBufferSize) lParamBufferSize = -1;
+ }
+
+ if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, FALSE)))
+ {
+ ERR("Failed to pack message parameters\n");
+ RETURN( FALSE);
+ }
+
+ Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
+ !Window->Unicode,
+ hWnd,
+ Msg,
+ wParam,
+ lParamPacked,
+ lParamBufferSize );
+ if(uResult)
+ {
+ *uResult = Result;
+ }
+
+ if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
+ {
+ ERR("Failed to unpack message parameters\n");
+ RETURN( TRUE);
+ }
+
+ // Only happens when calling the client!
+ IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
+
+ RETURN( TRUE);
+ }
+
+ if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(ptiSendTo))
+ {
+ // FIXME: Set window hung and add to a list.
+ /* FIXME: Set a LastError? */
+ RETURN( FALSE);
+ }
+
+ if (Window->state & WNDS_DESTROYED)
+ {
+ /* FIXME: Last error? */
+ ERR("Attempted to send message to window %p that is being destroyed!\n", hWnd);
+ RETURN( FALSE);
+ }
+
+ do
+ {
+ Status = co_MsqSendMessage( ptiSendTo,
+ hWnd,
+ Msg,
+ wParam,
+ lParam,
+ uTimeout,
+ (uFlags & SMTO_BLOCK),
+ MSQ_NORMAL,
+ uResult );
+ }
+ while ((STATUS_TIMEOUT == Status) &&
+ (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
+ !MsqIsHung(ptiSendTo)); // FIXME: Set window hung and add to a list.
+
+ if (STATUS_TIMEOUT == Status)
+ {
+/*
+ * MSDN says:
+ * Microsoft Windows 2000: If GetLastError returns zero, then the function
+ * timed out.
+ * XP+ : If the function fails or times out, the return value is zero.
+ * To get extended error information, call GetLastError. If GetLastError
+ * returns ERROR_TIMEOUT, then the function timed out.
+ */
+ EngSetLastError(ERROR_TIMEOUT);
+ RETURN( FALSE);
+ }
+ else if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( FALSE);
+ }
+
+ RETURN( TRUE);
+
+CLEANUP:
+ if (Window) UserDerefObjectCo(Window);
+ END_CLEANUP;
+}
+
+LRESULT FASTCALL
+co_IntSendMessageTimeout( HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ UINT uFlags,
+ UINT uTimeout,
+ ULONG_PTR *uResult )
+{
+ PWND DesktopWindow;
+ HWND *Children;
+ HWND *Child;
+
+ if (hWnd != HWND_BROADCAST && hWnd != HWND_TOPMOST)
+ {
+ return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
+ }
+
+ DesktopWindow = UserGetDesktopWindow();
+ if (NULL == DesktopWindow)
+ {
+ EngSetLastError(ERROR_INTERNAL_ERROR);
+ return 0;
+ }
+
+ if (hWnd != HWND_TOPMOST)
+ {
+ /* Send message to the desktop window too! */
+ co_IntSendMessageTimeoutSingle(DesktopWindow->head.h, Msg, wParam, lParam, uFlags, uTimeout, uResult);
+ }
+
+ Children = IntWinListChildren(DesktopWindow);
+ if (NULL == Children)
+ {
+ return 0;
+ }
+
+ for (Child = Children; NULL != *Child; Child++)
+ {
+ if (hWnd == HWND_TOPMOST)
+ {
+ DesktopWindow = UserGetWindowObject(*Child);
+ if (DesktopWindow && DesktopWindow->ExStyle & WS_EX_TOPMOST)
+ {
+ ERR("HWND_TOPMOST Found\n");
+ co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
+ }
+ }
+ else
+ {
+ PWND pwnd = UserGetWindowObject(*Child);
+ if (!pwnd) continue;
+
+ if ( pwnd->fnid == FNID_MENU ||
+ pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
+ continue;
+
+ co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
+ }
+ }
+
+ ExFreePool(Children);
+
+ return (LRESULT) TRUE;
+}
+
+LRESULT FASTCALL
+co_IntSendMessageNoWait(HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ ULONG_PTR Result = 0;
+ return co_IntSendMessageWithCallBack( hWnd,
+ Msg,
+ wParam,
+ lParam,
+ NULL,
+ 0,
+ &Result);
+}
+/* MSDN:
+ If you send a message in the range below WM_USER to the asynchronous message
+ functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its
+ message parameters cannot include pointers. Otherwise, the operation will fail.
+ The functions will return before the receiving thread has had a chance to
+ process the message and the sender will free the memory before it is used.
+*/
+LRESULT FASTCALL
+co_IntSendMessageWithCallBack( HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ SENDASYNCPROC CompletionCallback,
+ ULONG_PTR CompletionCallbackContext,
+ ULONG_PTR *uResult)
+{
+ ULONG_PTR Result;
+ PWND Window = NULL;
+ PMSGMEMORY MsgMemoryEntry;
+ INT lParamBufferSize;
+ LPARAM lParamPacked;
+ PTHREADINFO Win32Thread, ptiSendTo = NULL;
+ DECLARE_RETURN(LRESULT);
+ USER_REFERENCE_ENTRY Ref;
+ PUSER_SENT_MESSAGE Message;
+ BOOL DoCallBack = TRUE;
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ TRACE("SendMessageWithCallBack: Invalid handle 0x%p!\n",hWnd);
+ RETURN(FALSE);
+ }
+
+ UserRefObjectCo(Window, &Ref);
+
+ if (Window->state & WNDS_DESTROYED)
+ {
+ /* FIXME: last error? */
+ ERR("Attempted to send message to window %p that is being destroyed!\n", hWnd);
+ RETURN(FALSE);
+ }
+
+ Win32Thread = PsGetCurrentThreadWin32Thread();
+
+ if (Win32Thread == NULL ||
+ Win32Thread->TIF_flags & TIF_INCLEANUP)
+ {
+ RETURN(FALSE);
+ }
+
+ ptiSendTo = IntSendTo(Window, Win32Thread, Msg);
+
+ if (Msg & 0x80000000 &&
+ !ptiSendTo)
+ {
+ if (Win32Thread->TIF_flags & TIF_INCLEANUP) RETURN( FALSE);
+
+ TRACE("SMWCB: Internal Message!\n");
+ Result = (ULONG_PTR)handle_internal_message( Window, Msg, wParam, lParam );
+ if (uResult) *uResult = Result;
+ RETURN( TRUE);
+ }
+
+ /* See if this message type is present in the table */
+ MsgMemoryEntry = FindMsgMemory(Msg);
+ if (NULL == MsgMemoryEntry)
+ {
+ lParamBufferSize = -1;
+ }
+ else
+ {
+ lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
+ if (!lParamBufferSize) lParamBufferSize = -1;
+ }
+
+ if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, !!ptiSendTo)))
+ {
+ ERR("Failed to pack message parameters\n");
+ RETURN( FALSE);
+ }
+
+ /* If it can be sent now, then send it. */
+ if ( !ptiSendTo )
+ {
+ if (Win32Thread->TIF_flags & TIF_INCLEANUP)
+ {
+ UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE);
+ /* Never send messages to exiting threads */
+ RETURN(FALSE);
+ }
+
+ IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
+
+ if ( Window->state & WNDS_SERVERSIDEWINDOWPROC )
+ {
+ TRACE("SMWCB: Server Side Window Procedure\n");
+ switch(Window->fnid)
+ {
+ case FNID_DESKTOP:
+ DoCallBack = !DesktopWindowProc(Window, Msg, wParam, lParamPacked, (LRESULT*)&Result);
+ break;
+ case FNID_MESSAGEWND:
+ DoCallBack = !UserMessageWindowProc(Window, Msg, wParam, lParam,(LRESULT*)&Result);
+ break;
+ }
+ }
+
+ if (DoCallBack)
+ Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
+ !Window->Unicode,
+ hWnd,
+ Msg,
+ wParam,
+ lParamPacked,
+ lParamBufferSize );
+ if(uResult)
+ {
+ *uResult = Result;
+ }
+
+ IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
+
+ if (CompletionCallback)
+ {
+ co_IntCallSentMessageCallback(CompletionCallback,
+ hWnd,
+ Msg,
+ CompletionCallbackContext,
+ Result);
+ }
+ }
+
+ if ( !ptiSendTo)
+ {
+ if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
+ {
+ ERR("Failed to unpack message parameters\n");
+ }
+ RETURN(TRUE);
+ }
+
+ if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
+ {
+ ERR("MsqSendMessage(): Not enough memory to allocate a message");
+ RETURN( FALSE);
+ }
+
+ Message->Msg.hwnd = hWnd;
+ Message->Msg.message = Msg;
+ Message->Msg.wParam = wParam;
+ Message->Msg.lParam = lParamPacked;
+ Message->CompletionEvent = NULL;
+ Message->Result = 0;
+ Message->lResult = 0;
+ Message->QS_Flags = 0;
+ Message->ptiReceiver = ptiSendTo;
+ Message->ptiSender = NULL; // mjmartin, you are right! This is null.
+ Message->ptiCallBackSender = Win32Thread;
+ Message->DispatchingListEntry.Flink = NULL;
+ Message->CompletionCallback = CompletionCallback;
+ Message->CompletionCallbackContext = CompletionCallbackContext;
+ Message->HookMessage = MSQ_NORMAL;
+ Message->HasPackedLParam = (lParamBufferSize > 0);
+ Message->QS_Flags = QS_SENDMESSAGE;
+
+ if (Msg & 0x80000000) // Higher priority event message!
+ InsertHeadList(&ptiSendTo->SentMessagesListHead, &Message->ListEntry);
+ else
+ InsertTailList(&ptiSendTo->SentMessagesListHead, &Message->ListEntry);
+ MsqWakeQueue(ptiSendTo, QS_SENDMESSAGE, TRUE);
+
+ RETURN(TRUE);
+
+CLEANUP:
+ if (Window) UserDerefObjectCo(Window);
+ END_CLEANUP;
+}
+
+
+/*
+ This HACK function posts a message if the destination's message queue belongs to
+ another thread, otherwise it sends the message. It does not support broadcast
+ messages!
+*/
+LRESULT FASTCALL
+co_IntPostOrSendMessage( HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam )
+{
+ ULONG_PTR Result;
+ PTHREADINFO pti;
+ PWND Window;
+
+ if ( hWnd == HWND_BROADCAST )
+ {
+ return 0;
+ }
+
+ if(!(Window = UserGetWindowObject(hWnd)))
+ {
+ TRACE("PostOrSendMessage: Invalid handle 0x%p!\n",hWnd);
+ return 0;
+ }
+
+ pti = PsGetCurrentThreadWin32Thread();
+
+ if ( IntSendTo(Window, pti, Msg) &&
+ FindMsgMemory(Msg) == 0 )
+ {
+ Result = UserPostMessage(hWnd, Msg, wParam, lParam);
+ }
+ else
+ {
+ if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
+ {
+ Result = 0;
+ }
+ }
+
+ return (LRESULT)Result;
+}
+
+static LRESULT FASTCALL
+co_IntDoSendMessage( HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ PDOSENDMESSAGE dsm)
+{
+ LRESULT Result = TRUE;
+ NTSTATUS Status;
+ PWND Window = NULL;
+ MSG UserModeMsg, KernelModeMsg;
+ PMSGMEMORY MsgMemoryEntry;
+ PTHREADINFO ptiSendTo;
+
+ if (hWnd != HWND_BROADCAST && hWnd != HWND_TOPMOST)
+ {
+ Window = UserGetWindowObject(hWnd);
+ if ( !Window )
+ {
+ return 0;
+ }
+ }
+
+ /* Check for an exiting window. */
+ if (Window && Window->state & WNDS_DESTROYED)
+ {
+ ERR("co_IntDoSendMessage Window Exiting!\n");
+ }
+
+ /* See if the current thread can handle this message */
+ ptiSendTo = IntSendTo(Window, gptiCurrent, Msg);
+
+ // If broadcasting or sending to another thread, save the users data.
+ if (!Window || ptiSendTo )
+ {
+ UserModeMsg.hwnd = hWnd;
+ UserModeMsg.message = Msg;
+ UserModeMsg.wParam = wParam;
+ UserModeMsg.lParam = lParam;
+ MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
+ Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
+ if (!NT_SUCCESS(Status))
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ return (dsm ? 0 : -1);
+ }
+ }
+ else
+ {
+ KernelModeMsg.hwnd = hWnd;
+ KernelModeMsg.message = Msg;
+ KernelModeMsg.wParam = wParam;
+ KernelModeMsg.lParam = lParam;
+ }
+
+ if (!dsm)
+ {
+ Result = co_IntSendMessage( KernelModeMsg.hwnd,
+ KernelModeMsg.message,
+ KernelModeMsg.wParam,
+ KernelModeMsg.lParam );
+ }
+ else
+ {
+ Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
+ KernelModeMsg.message,
+ KernelModeMsg.wParam,
+ KernelModeMsg.lParam,
+ dsm->uFlags,
+ dsm->uTimeout,
+ &dsm->Result );
+ }
+
+ if (!Window || ptiSendTo )
+ {
+ Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
+ if (!NT_SUCCESS(Status))
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ return(dsm ? 0 : -1);
+ }
+ }
+
+ return (LRESULT)Result;
+}
+
+BOOL FASTCALL
+UserSendNotifyMessage( HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam )
+{
+ BOOL Ret = TRUE;
+
+ if (is_pointer_message(Msg))
+ {
+ EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
+ return FALSE;
+ }
+
+ // Basicly the same as IntPostOrSendMessage
+ if (hWnd == HWND_BROADCAST) // Handle Broadcast
+ {
+ HWND *List;
+ PWND DesktopWindow;
+ ULONG i;
+
+ DesktopWindow = UserGetDesktopWindow();
+ List = IntWinListChildren(DesktopWindow);
+
+ if (List != NULL)
+ {
+ UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam);
+ for (i = 0; List[i]; i++)
+ {
+ PWND pwnd = UserGetWindowObject(List[i]);
+ if (!pwnd) continue;
+
+ if ( pwnd->fnid == FNID_MENU ||
+ pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
+ continue;
+
+ Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam);
+ }
+ ExFreePool(List);
+ }
+ }
+ else
+ {
+ Ret = co_IntSendMessageNoWait( hWnd, Msg, wParam, lParam);
+ }
+ return Ret;
+}
+
+
+DWORD APIENTRY
+IntGetQueueStatus(DWORD Changes)
+{
+ PTHREADINFO pti;
+ DWORD Result;
+
+ pti = PsGetCurrentThreadWin32Thread();
+// wine:
+ Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT);
+
+ /* High word, types of messages currently in the queue.
+ Low word, types of messages that have been added to the queue and that
+ are still in the queue
+ */
+ Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes);
+
+ pti->pcti->fsChangeBits &= ~Changes;
+
+ return Result;
+}
+
+BOOL APIENTRY
+IntInitMessagePumpHook()
+{
+ PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+
+ if (pti->pcti)
+ {
+ pti->pcti->dwcPumpHook++;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL APIENTRY
+IntUninitMessagePumpHook()
+{
+ PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+
+ if (pti->pcti)
+ {
+ if (pti->pcti->dwcPumpHook <= 0)
+ {
+ return FALSE;
+ }
+ pti->pcti->dwcPumpHook--;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL FASTCALL
+IntCallMsgFilter( LPMSG lpmsg, INT code)
+{
+ BOOL Ret = FALSE;
+
+ if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)lpmsg))
+ {
+ Ret = TRUE;
+ }
+ else
+ {
+ Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)lpmsg);
+ }
+ return Ret;
+}
+
+/** Functions ******************************************************************/
+
+BOOL
+APIENTRY
+NtUserDragDetect(
+ HWND hWnd,
+ POINT pt) // Just like the User call.
+{
+ MSG msg;
+ RECT rect;
+ ULONG wDragWidth, wDragHeight;
+ DECLARE_RETURN(BOOL);
+
+ TRACE("Enter NtUserDragDetect(%p)\n", hWnd);
+ UserEnterExclusive();
+
+ wDragWidth = UserGetSystemMetrics(SM_CXDRAG);
+ wDragHeight= UserGetSystemMetrics(SM_CYDRAG);
+
+ rect.left = pt.x - wDragWidth;
+ rect.right = pt.x + wDragWidth;
+
+ rect.top = pt.y - wDragHeight;
+ rect.bottom = pt.y + wDragHeight;
+
+ co_UserSetCapture(hWnd);
+
+ for (;;)
+ {
+ while (co_IntGetPeekMessage( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, FALSE ) ||
+ co_IntGetPeekMessage( &msg, 0, WM_QUEUESYNC, WM_QUEUESYNC, PM_REMOVE, FALSE ) ||
+ co_IntGetPeekMessage( &msg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE, FALSE ) )
+ {
+ if ( msg.message == WM_LBUTTONUP )
+ {
+ co_UserSetCapture(NULL);
+ RETURN( FALSE);
+ }
+ if ( msg.message == WM_MOUSEMOVE )
+ {
+ POINT tmp;
+ tmp.x = (short)LOWORD(msg.lParam);
+ tmp.y = (short)HIWORD(msg.lParam);
+ if( !RECTL_bPointInRect( &rect, tmp.x, tmp.y ) )
+ {
+ co_UserSetCapture(NULL);
+ RETURN( TRUE);
+ }
+ }
+ if ( msg.message == WM_KEYDOWN )
+ {
+ if ( msg.wParam == VK_ESCAPE )
+ {
+ co_UserSetCapture(NULL);
+ RETURN( TRUE);
+ }
+ }
+ if ( msg.message == WM_QUEUESYNC )
+ {
+ co_HOOK_CallHooks( WH_CBT, HCBT_QS, 0, 0 );
+ }
+ }
+ co_IntWaitMessage(NULL, 0, 0);
+ }
+ RETURN( FALSE);
+
+CLEANUP:
+ TRACE("Leave NtUserDragDetect, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+BOOL APIENTRY
+NtUserPostMessage(HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ BOOL ret;
+
+ UserEnterExclusive();
+
+ ret = UserPostMessage(hWnd, Msg, wParam, lParam);
+
+ UserLeave();
+
+ return ret;
+}
+
+BOOL APIENTRY
+NtUserPostThreadMessage(DWORD idThread,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ BOOL ret = FALSE;
+ PETHREAD peThread;
+ PTHREADINFO pThread;
+ NTSTATUS Status;
+
+ UserEnterExclusive();
+
+ Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
+
+ if ( Status == STATUS_SUCCESS )
+ {
+ pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
+ if( !pThread ||
+ !pThread->MessageQueue ||
+ (pThread->TIF_flags & TIF_INCLEANUP))
+ {
+ ObDereferenceObject( peThread );
+ goto exit;
+ }
+ ret = UserPostThreadMessage( pThread, Msg, wParam, lParam);
+ ObDereferenceObject( peThread );
+ }
+ else
+ {
+ SetLastNtError( Status );
+ }
+exit:
+ UserLeave();
+ return ret;
+}
+
+BOOL APIENTRY
+NtUserWaitMessage(VOID)
+{
+ BOOL ret;
+
+ UserEnterExclusive();
+ TRACE("NtUserWaitMessage Enter\n");
+ ret = co_IntWaitMessage(NULL, 0, 0);
+ TRACE("NtUserWaitMessage Leave\n");
+ UserLeave();
+
+ return ret;
+}
+
+BOOL APIENTRY
+NtUserGetMessage(PMSG pMsg,
+ HWND hWnd,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax )
+{
+ MSG Msg;
+ BOOL Ret;
+
+ if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ UserEnterExclusive();
+
+ RtlZeroMemory(&Msg, sizeof(MSG));
+
+ Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
+
+ UserLeave();
+
++ if (Ret)
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite(pMsg, sizeof(MSG), 1);
+ RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ Ret = FALSE;
+ }
+ _SEH2_END;
+ }
+
+ if ((INT)Ret != -1)
+ Ret = Ret ? (WM_QUIT != pMsg->message) : FALSE;
+
+ return Ret;
+}
+
+BOOL APIENTRY
+NtUserPeekMessage( PMSG pMsg,
+ HWND hWnd,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax,
+ UINT RemoveMsg)
+{
+ MSG Msg;
+ BOOL Ret;
+
+ if ( RemoveMsg & PM_BADMSGFLAGS )
+ {
+ EngSetLastError(ERROR_INVALID_FLAGS);
+ return FALSE;
+ }
+
+ UserEnterExclusive();
+
+ RtlZeroMemory(&Msg, sizeof(MSG));
+
+ Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
+
+ UserLeave();
+
+ if (Ret)
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite(pMsg, sizeof(MSG), 1);
+ RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ Ret = FALSE;
+ }
+ _SEH2_END;
+ }
+
+ return Ret;
+}
+
+BOOL APIENTRY
+NtUserCallMsgFilter( LPMSG lpmsg, INT code)
+{
+ BOOL Ret = FALSE;
+ MSG Msg;
+
+ _SEH2_TRY
+ {
+ ProbeForRead(lpmsg, sizeof(MSG), 1);
+ RtlCopyMemory( &Msg, lpmsg, sizeof(MSG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ _SEH2_YIELD(return FALSE);
+ }
+ _SEH2_END;
+
+ UserEnterExclusive();
+
+ if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
+ {
+ Ret = TRUE;
+ }
+ else
+ {
+ Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
+ }
+
+ UserLeave();
+
+ _SEH2_TRY
+ {
+ ProbeForWrite(lpmsg, sizeof(MSG), 1);
+ RtlCopyMemory(lpmsg, &Msg, sizeof(MSG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Ret = FALSE;
+ }
+ _SEH2_END;
+
+ return Ret;
+}
+
+LRESULT APIENTRY
+NtUserDispatchMessage(PMSG UnsafeMsgInfo)
+{
+ LRESULT Res = 0;
+ MSG SafeMsg;
+
+ _SEH2_TRY
+ {
+ ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
+ RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ _SEH2_YIELD(return FALSE);
+ }
+ _SEH2_END;
+
+ UserEnterExclusive();
+
+ Res = IntDispatchMessage(&SafeMsg);
+
+ UserLeave();
+ return Res;
+}
+
+BOOL APIENTRY
+NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
+{
+ MSG SafeMsg;
+ BOOL Ret;
+ PWND pWnd;
+
+ _SEH2_TRY
+ {
+ ProbeForRead(lpMsg, sizeof(MSG), 1);
+ RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ _SEH2_YIELD(return FALSE);
+ }
+ _SEH2_END;
+
+ UserEnterExclusive();
+ pWnd = UserGetWindowObject(SafeMsg.hwnd);
+ if (pWnd) // Must have a window!
+ {
+ Ret = IntTranslateKbdMessage(&SafeMsg, flags);
+ }
+ else
+ {
+ TRACE("No Window for Translate. hwnd 0x%p Msg %u\n", SafeMsg.hwnd, SafeMsg.message);
+ Ret = FALSE;
+ }
+ UserLeave();
+
+ return Ret;
+}
+
+LRESULT APIENTRY ScrollBarWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam);
+
+BOOL APIENTRY
+NtUserMessageCall( HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ ULONG_PTR ResultInfo,
+ DWORD dwType, // fnID?
+ BOOL Ansi)
+{
+ LRESULT lResult = 0;
+ BOOL Ret = FALSE;
+ PWND Window = NULL;
+ USER_REFERENCE_ENTRY Ref;
+
+ UserEnterExclusive();
+
+ switch(dwType)
+ {
+ case FNID_SCROLLBAR:
+ {
+ lResult = ScrollBarWndProc(hWnd, Msg, wParam, lParam);
+ break;
+ }
+ case FNID_DESKTOP:
+ {
+ Window = UserGetWindowObject(hWnd);
+ if (Window)
+ {
+ //ERR("FNID_DESKTOP IN\n");
+ Ret = DesktopWindowProc(Window, Msg, wParam, lParam, &lResult);
+ //ERR("FNID_DESKTOP OUT\n");
+ }
+ break;
+ }
+
+ case FNID_MESSAGEWND:
+ {
+ Window = UserGetWindowObject(hWnd);
+ if (Window)
+ {
+ Ret = !UserMessageWindowProc(Window, Msg, wParam, lParam,&lResult);
+ }
+ break;
+ }
+ case FNID_DEFWINDOWPROC:
+ /* Validate input */
+ if (hWnd)
+ {
+ Window = UserGetWindowObject(hWnd);
+ if (!Window)
+ {
+ UserLeave();
+ return FALSE;
+ }
+ UserRefObjectCo(Window, &Ref);
+ }
+ lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
+ Ret = TRUE;
+ if (hWnd)
+ UserDerefObjectCo(Window);
+ break;
+ case FNID_SENDNOTIFYMESSAGE:
+ Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
+ break;
+ case FNID_BROADCASTSYSTEMMESSAGE:
+ {
+ BROADCASTPARM parm, *retparam;
+ DWORD_PTR RetVal = 0;
+
+ if (ResultInfo)
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1);
+ RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ _SEH2_YIELD(break);
+ }
+ _SEH2_END;
+ }
+ else
+ break;
+
+ if ( parm.recipients & BSM_ALLDESKTOPS ||
+ parm.recipients == BSM_ALLCOMPONENTS )
+ {
+ PLIST_ENTRY DesktopEntry;
+ PDESKTOP rpdesk;
+ HWND *List, hwndDenied = NULL;
+ HDESK hDesk = NULL;
+ PWND pwnd, pwndDesk;
+ ULONG i;
+ UINT fuFlags;
+
+ for (DesktopEntry = InputWindowStation->DesktopListHead.Flink;
+ DesktopEntry != &InputWindowStation->DesktopListHead;
+ DesktopEntry = DesktopEntry->Flink)
+ {
+ rpdesk = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
+ pwndDesk = rpdesk->pDeskInfo->spwnd;
+ List = IntWinListChildren(pwndDesk);
+
+ if (parm.flags & BSF_QUERY)
+ {
+ if (List != NULL)
+ {
+ if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
+ {
+ fuFlags = SMTO_ABORTIFHUNG;
+ }
+ else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
+ {
+ fuFlags = SMTO_NOTIMEOUTIFNOTHUNG;
+ }
+ else
+ {
+ fuFlags = SMTO_NORMAL;
+ }
+ co_IntSendMessageTimeout( UserHMGetHandle(pwndDesk),
+ Msg,
+ wParam,
+ lParam,
+ fuFlags,
+ 2000,
+ &RetVal);
+ Ret = TRUE;
+ for (i = 0; List[i]; i++)
+ {
+ pwnd = UserGetWindowObject(List[i]);
+ if (!pwnd) continue;
+
+ if ( pwnd->fnid == FNID_MENU ||
+ pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
+ continue;
+
+ if ( parm.flags & BSF_IGNORECURRENTTASK )
+ {
+ if ( pwnd->head.pti == gptiCurrent )
+ continue;
+ }
+ co_IntSendMessageTimeout( List[i],
+ Msg,
+ wParam,
+ lParam,
+ fuFlags,
+ 2000,
+ &RetVal);
+
+ if (!RetVal && EngGetLastError() == ERROR_TIMEOUT)
+ {
+ if (!(parm.flags & BSF_FORCEIFHUNG))
+ Ret = FALSE;
+ }
+ if (RetVal == BROADCAST_QUERY_DENY)
+ {
+ hwndDenied = List[i];
+ hDesk = UserHMGetHandle(pwndDesk);
+ Ret = FALSE;
+ }
+ }
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ _SEH2_TRY
+ {
+ retparam = (PBROADCASTPARM) ResultInfo;
+ retparam->hDesk = hDesk;
+ retparam->hWnd = hwndDenied;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ _SEH2_YIELD(break);
+ }
+ _SEH2_END;
+ if (!Ret) break; // Have a hit! Let everyone know!
+ }
+ }
+ else if (parm.flags & BSF_POSTMESSAGE)
+ {
+ if (List != NULL)
+ {
+ UserPostMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
+
+ for (i = 0; List[i]; i++)
+ {
+ pwnd = UserGetWindowObject(List[i]);
+ if (!pwnd) continue;
+
+ if ( pwnd->fnid == FNID_MENU ||
+ pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
+ continue;
+
+ if ( parm.flags & BSF_IGNORECURRENTTASK )
+ {
+ if ( pwnd->head.pti == gptiCurrent )
+ continue;
+ }
+ UserPostMessage(List[i], Msg, wParam, lParam);
+ }
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ }
+ Ret = TRUE;
+ }
+ else
+ {
+ if (List != NULL)
+ {
+ UserSendNotifyMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
+
+ for (i = 0; List[i]; i++)
+ {
+ pwnd = UserGetWindowObject(List[i]);
+ if (!pwnd) continue;
+
+ if ( pwnd->fnid == FNID_MENU ||
+ pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
+ continue;
+
+ if ( parm.flags & BSF_IGNORECURRENTTASK )
+ {
+ if ( pwnd->head.pti == gptiCurrent )
+ continue;
+ }
+ UserSendNotifyMessage(List[i], Msg, wParam, lParam);
+ }
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ }
+ Ret = TRUE;
+ }
+ }
+ }
+ else if (parm.recipients & BSM_APPLICATIONS)
+ {
+ HWND *List, hwndDenied = NULL;
+ HDESK hDesk = NULL;
+ PWND pwnd, pwndDesk;
+ ULONG i;
+ UINT fuFlags;
+
+ pwndDesk = UserGetDesktopWindow();
+ List = IntWinListChildren(pwndDesk);
+
+ if (parm.flags & BSF_QUERY)
+ {
+ if (List != NULL)
+ {
+ if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
+ {
+ fuFlags = SMTO_ABORTIFHUNG;
+ }
+ else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
+ {
+ fuFlags = SMTO_NOTIMEOUTIFNOTHUNG;
+ }
+ else
+ {
+ fuFlags = SMTO_NORMAL;
+ }
+ co_IntSendMessageTimeout( UserHMGetHandle(pwndDesk),
+ Msg,
+ wParam,
+ lParam,
+ fuFlags,
+ 2000,
+ &RetVal);
+ Ret = TRUE;
+ for (i = 0; List[i]; i++)
+ {
+ pwnd = UserGetWindowObject(List[i]);
+ if (!pwnd) continue;
+
+ if ( pwnd->fnid == FNID_MENU ||
+ pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
+ continue;
+
+ if ( parm.flags & BSF_IGNORECURRENTTASK )
+ {
+ if ( pwnd->head.pti == gptiCurrent )
+ continue;
+ }
+ co_IntSendMessageTimeout( List[i],
+ Msg,
+ wParam,
+ lParam,
+ fuFlags,
+ 2000,
+ &RetVal);
+
+ if (!RetVal && EngGetLastError() == ERROR_TIMEOUT)
+ {
+ if (!(parm.flags & BSF_FORCEIFHUNG))
+ Ret = FALSE;
+ }
+ if (RetVal == BROADCAST_QUERY_DENY)
+ {
+ hwndDenied = List[i];
+ hDesk = UserHMGetHandle(pwndDesk);
+ Ret = FALSE;
+ }
+ }
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ _SEH2_TRY
+ {
+ retparam = (PBROADCASTPARM) ResultInfo;
+ retparam->hDesk = hDesk;
+ retparam->hWnd = hwndDenied;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ _SEH2_YIELD(break);
+ }
+ _SEH2_END;
+ }
+ }
+ else if (parm.flags & BSF_POSTMESSAGE)
+ {
+ if (List != NULL)
+ {
+ UserPostMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
+
+ for (i = 0; List[i]; i++)
+ {
+ pwnd = UserGetWindowObject(List[i]);
+ if (!pwnd) continue;
+
+ if ( pwnd->fnid == FNID_MENU ||
+ pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
+ continue;
+
+ if ( parm.flags & BSF_IGNORECURRENTTASK )
+ {
+ if ( pwnd->head.pti == gptiCurrent )
+ continue;
+ }
+ UserPostMessage(List[i], Msg, wParam, lParam);
+ }
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ }
+ Ret = TRUE;
+ }
+ else
+ {
+ if (List != NULL)
+ {
+ UserSendNotifyMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
+
+ for (i = 0; List[i]; i++)
+ {
+ pwnd = UserGetWindowObject(List[i]);
+ if (!pwnd) continue;
+
+ if ( pwnd->fnid == FNID_MENU ||
+ pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
+ continue;
+
+ if ( parm.flags & BSF_IGNORECURRENTTASK )
+ {
+ if ( pwnd->head.pti == gptiCurrent )
+ continue;
+ }
+ UserSendNotifyMessage(List[i], Msg, wParam, lParam);
+ }
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ }
+ Ret = TRUE;
+ }
+ }
+ }
+ break;
+ case FNID_SENDMESSAGECALLBACK:
+ {
+ CALL_BACK_INFO CallBackInfo;
+ ULONG_PTR uResult;
+
+ _SEH2_TRY
+ {
+ ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1);
+ RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ _SEH2_YIELD(break);
+ }
+ _SEH2_END;
+
+ if (is_pointer_message(Msg))
+ {
+ EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
+ break;
+ }
+
+ if (!(Ret = co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
+ CallBackInfo.CallBack, CallBackInfo.Context, &uResult)))
+ {
+ ERR("Callback failure!\n");
+ }
+ }
+ break;
+ case FNID_SENDMESSAGE:
+ {
+ Ret = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
+
+ if (ResultInfo)
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1);
+ RtlCopyMemory((PVOID)ResultInfo, &Ret, sizeof(ULONG_PTR));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Ret = FALSE;
+ _SEH2_YIELD(break);
+ }
+ _SEH2_END;
+ }
+ break;
+ }
+ case FNID_SENDMESSAGEFF:
+ case FNID_SENDMESSAGEWTOOPTION:
+ {
+ DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo;
+ if (ResultInfo)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1);
+ RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ _SEH2_YIELD(break);
+ }
+ _SEH2_END;
+ }
+
+ Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, &dsm );
+
+ if (pdsm)
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1);
+ RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Ret = FALSE;
+ _SEH2_YIELD(break);
+ }
+ _SEH2_END;
+ }
+ break;
+ }
+ // CallNextHook bypass.
+ case FNID_CALLWNDPROC:
+ case FNID_CALLWNDPROCRET:
+ {
+ PTHREADINFO pti;
+ PCLIENTINFO ClientInfo;
+ PHOOK NextObj, Hook;
+
+ pti = GetW32ThreadInfo();
+
+ Hook = pti->sphkCurrent;
+
+ if (!Hook) break;
+
+ NextObj = Hook->phkNext;
+ ClientInfo = pti->pClientInfo;
+ _SEH2_TRY
+ {
+ ClientInfo->phkCurrent = NextObj;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ClientInfo = NULL;
+ }
+ _SEH2_END;
+
+ if (!ClientInfo || !NextObj) break;
+
+ NextObj->phkNext = IntGetNextHook(NextObj);
+
+ if ( Hook->HookId == WH_CALLWNDPROC)
+ {
+ CWPSTRUCT CWP;
+ CWP.hwnd = hWnd;
+ CWP.message = Msg;
+ CWP.wParam = wParam;
+ CWP.lParam = lParam;
+ TRACE("WH_CALLWNDPROC: Hook %p NextHook %p\n", Hook, NextObj);
+
+ lResult = co_IntCallHookProc( Hook->HookId,
+ HC_ACTION,
+ ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
+ (LPARAM)&CWP,
+ Hook->Proc,
+ Hook->ihmod,
+ Hook->offPfn,
+ Hook->Ansi,
+ &Hook->ModuleName);
+ }
+ else
+ {
+ CWPRETSTRUCT CWPR;
+ CWPR.hwnd = hWnd;
+ CWPR.message = Msg;
+ CWPR.wParam = wParam;
+ CWPR.lParam = lParam;
+ CWPR.lResult = ClientInfo->dwHookData;
+
+ lResult = co_IntCallHookProc( Hook->HookId,
+ HC_ACTION,
+ ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
+ (LPARAM)&CWPR,
+ Hook->Proc,
+ Hook->ihmod,
+ Hook->offPfn,
+ Hook->Ansi,
+ &Hook->ModuleName);
+ }
+ }
+ break;
+ }
+
+ switch(dwType)
+ {
+ case FNID_DEFWINDOWPROC:
+ case FNID_CALLWNDPROC:
+ case FNID_CALLWNDPROCRET:
+ case FNID_SCROLLBAR:
+ case FNID_DESKTOP:
+ if (ResultInfo)
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
+ RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Ret = FALSE;
+ }
+ _SEH2_END;
+ }
+ break;
+ default:
+ break;
+ }
+
+ UserLeave();
+
+ return Ret;
+}
+
+#define INFINITE 0xFFFFFFFF
+#define WAIT_FAILED ((DWORD)0xFFFFFFFF)
+
+DWORD
+APIENTRY
+NtUserWaitForInputIdle( IN HANDLE hProcess,
+ IN DWORD dwMilliseconds,
+ IN BOOL Unknown2)
+{
+ PEPROCESS Process;
+ PPROCESSINFO W32Process;
+ PTHREADINFO pti;
+ NTSTATUS Status;
+ HANDLE Handles[3];
+ LARGE_INTEGER Timeout;
+
+ UserEnterExclusive();
+
+ Status = ObReferenceObjectByHandle(hProcess,
+ PROCESS_QUERY_INFORMATION,
+ *PsProcessType,
+ UserMode,
+ (PVOID*)&Process,
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ {
+ UserLeave();
+ SetLastNtError(Status);
+ return WAIT_FAILED;
+ }
+
+ pti = PsGetCurrentThreadWin32Thread();
+
+ W32Process = (PPROCESSINFO)Process->Win32Process;
+
+ if ( PsGetProcessExitProcessCalled(Process) ||
+ !W32Process ||
+ pti->ppi == W32Process)
+ {
+ ObDereferenceObject(Process);
+ UserLeave();
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ return WAIT_FAILED;
+ }
+
+ Handles[0] = Process;
+ Handles[1] = W32Process->InputIdleEvent;
+ Handles[2] = pti->pEventQueueServer; // IntMsqSetWakeMask returns hEventQueueClient
+
+ if (!Handles[1])
+ {
+ ObDereferenceObject(Process);
+ UserLeave();
+ return STATUS_SUCCESS; /* no event to wait on */
+ }
+
+ if (dwMilliseconds != INFINITE)
+ Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
+
+ W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE;
+ for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
+ {
+ pti->TIF_flags |= TIF_WAITFORINPUTIDLE;
+ pti->pClientInfo->dwTIFlags = pti->TIF_flags;
+ }
+
+ TRACE("WFII: ppi %p\n", W32Process);
+ TRACE("WFII: waiting for %p\n", Handles[1] );
+
+ /*
+ * We must add a refcount to our current PROCESSINFO,
+ * because anything could happen (including process death) we're leaving win32k
+ */
+ IntReferenceProcessInfo(W32Process);
+
+ do
+ {
+ UserLeave();
+ Status = KeWaitForMultipleObjects( 3,
+ Handles,
+ WaitAny,
+ UserRequest,
+ UserMode,
+ FALSE,
+ dwMilliseconds == INFINITE ? NULL : &Timeout,
+ NULL);
+ UserEnterExclusive();
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ Status = WAIT_FAILED;
+ goto WaitExit;
+ }
+
+ switch (Status)
+ {
+ case STATUS_WAIT_0:
+ goto WaitExit;
+
+ case STATUS_WAIT_2:
+ {
+ MSG Msg;
+ co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE);
+ ERR("WFII: WAIT 2\n");
+ }
+ break;
+
+ case STATUS_TIMEOUT:
+ ERR("WFII: timeout\n");
+ case WAIT_FAILED:
+ goto WaitExit;
+
+ default:
+ ERR("WFII: finished\n");
+ Status = STATUS_SUCCESS;
+ goto WaitExit;
+ }
+ }
+ while (TRUE);
+
+WaitExit:
+ for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
+ {
+ pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE;
+ pti->pClientInfo->dwTIFlags = pti->TIF_flags;
+ }
+ W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE;
+ IntDereferenceProcessInfo(W32Process);
+ ObDereferenceObject(Process);
+ UserLeave();
+ return Status;
+}
+
+/* EOF */
--- /dev/null
- if (Message->HasPackedLParam == TRUE)
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Win32k subsystem
+ * PURPOSE: Message queues
+ * FILE: subsystems/win32/win32k/ntuser/msgqueue.c
+ * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ Alexandre Julliard
+ Maarten Lankhorst
+ */
+
+#include <win32k.h>
+DBG_DEFAULT_CHANNEL(UserMsgQ);
+
+/* GLOBALS *******************************************************************/
+
+static PPAGED_LOOKASIDE_LIST pgMessageLookasideList;
+PUSER_MESSAGE_QUEUE gpqCursor;
+
+/* FUNCTIONS *****************************************************************/
+
+INIT_FUNCTION
+NTSTATUS
+NTAPI
+MsqInitializeImpl(VOID)
+{
+ pgMessageLookasideList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST), TAG_USRMSG);
+ if(!pgMessageLookasideList)
+ return STATUS_NO_MEMORY;
+ ExInitializePagedLookasideList(pgMessageLookasideList,
+ NULL,
+ NULL,
+ 0,
+ sizeof(USER_MESSAGE),
+ TAG_USRMSG,
+ 256);
+
+ return(STATUS_SUCCESS);
+}
+
+PWND FASTCALL
+IntChildrenWindowFromPoint(PWND pWndTop, INT x, INT y)
+{
+ PWND pWnd, pWndChild;
+
+ if ( !pWndTop )
+ {
+ pWndTop = UserGetDesktopWindow();
+ if ( !pWndTop ) return NULL;
+ }
+
+ if (!(pWndTop->style & WS_VISIBLE)) return NULL;
+ if ((pWndTop->style & WS_DISABLED)) return NULL;
+ if (!IntPtInWindow(pWndTop, x, y)) return NULL;
+
+ if (RECTL_bPointInRect(&pWndTop->rcClient, x, y))
+ {
+ for (pWnd = pWndTop->spwndChild;
+ pWnd != NULL;
+ pWnd = pWnd->spwndNext)
+ {
+ if (pWnd->state2 & WNDS2_INDESTROY || pWnd->state & WNDS_DESTROYED )
+ {
+ TRACE("The Window is in DESTROY!\n");
+ continue;
+ }
+
+ pWndChild = IntChildrenWindowFromPoint(pWnd, x, y);
+
+ if (pWndChild)
+ {
+ return pWndChild;
+ }
+ }
+ }
+ return pWndTop;
+}
+
+PWND FASTCALL
+IntTopLevelWindowFromPoint(INT x, INT y)
+{
+ PWND pWnd, pwndDesktop;
+
+ /* Get the desktop window */
+ pwndDesktop = UserGetDesktopWindow();
+ if (!pwndDesktop)
+ return NULL;
+
+ /* Loop all top level windows */
+ for (pWnd = pwndDesktop->spwndChild;
+ pWnd != NULL;
+ pWnd = pWnd->spwndNext)
+ {
+ if (pWnd->state2 & WNDS2_INDESTROY || pWnd->state & WNDS_DESTROYED)
+ {
+ TRACE("The Window is in DESTROY!\n");
+ continue;
+ }
+
+ if ((pWnd->style & WS_VISIBLE) && IntPtInWindow(pWnd, x, y))
+ return pWnd;
+ }
+
+ /* Window has not been found */
+ return pwndDesktop;
+}
+
+PCURICON_OBJECT
+FASTCALL
+UserSetCursor(
+ PCURICON_OBJECT NewCursor,
+ BOOL ForceChange)
+{
+ PCURICON_OBJECT OldCursor;
+ HDC hdcScreen;
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+ PWND pWnd;
+
+ pti = PsGetCurrentThreadWin32Thread();
+ MessageQueue = pti->MessageQueue;
+
+ /* Get the screen DC */
+ if(!(hdcScreen = IntGetScreenDC()))
+ {
+ return NULL;
+ }
+
+ OldCursor = MessageQueue->CursorObject;
+
+ /* Check if cursors are different */
+ if (OldCursor == NewCursor)
+ return OldCursor;
+
+ /* Update cursor for this message queue */
+ MessageQueue->CursorObject = NewCursor;
+
+ /* If cursor is not visible we have nothing to do */
+ if (MessageQueue->iCursorLevel < 0)
+ return OldCursor;
+
+ /* Update cursor if this message queue controls it */
+ pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y);
+ if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue)
+ {
+ if (NewCursor)
+ {
+ /* Call GDI to set the new screen cursor */
+#ifdef NEW_CURSORICON
+ PCURICON_OBJECT CursorFrame = NewCursor;
+ if(NewCursor->CURSORF_flags & CURSORF_ACON)
+ {
+ FIXME("Should animate the cursor, using only the first frame now.\n");
+ CursorFrame = ((PACON)NewCursor)->aspcur[0];
+ }
+ GreSetPointerShape(hdcScreen,
+ CursorFrame->hbmAlpha ? NULL : NewCursor->hbmMask,
+ CursorFrame->hbmAlpha ? NewCursor->hbmAlpha : NewCursor->hbmColor,
+ CursorFrame->xHotspot,
+ CursorFrame->yHotspot,
+ gpsi->ptCursor.x,
+ gpsi->ptCursor.y,
+ CursorFrame->hbmAlpha ? SPS_ALPHA : 0);
+#else
+ GreSetPointerShape(hdcScreen,
+ NewCursor->IconInfo.hbmMask,
+ NewCursor->IconInfo.hbmColor,
+ NewCursor->IconInfo.xHotspot,
+ NewCursor->IconInfo.yHotspot,
+ gpsi->ptCursor.x,
+ gpsi->ptCursor.y,
+ 0);
+#endif
+ }
+ else /* Note: OldCursor != NewCursor so we have to hide cursor */
+ {
+ /* Remove the cursor */
+ GreMovePointer(hdcScreen, -1, -1);
+ TRACE("Removing pointer!\n");
+ }
+ IntGetSysCursorInfo()->CurrentCursorObject = NewCursor;
+ }
+
+ /* Return the old cursor */
+ return OldCursor;
+}
+
+/* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
+ * User32 macro NtUserShowCursor */
+int UserShowCursor(BOOL bShow)
+{
+ HDC hdcScreen;
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+ PWND pWnd;
+
+ if (!(hdcScreen = IntGetScreenDC()))
+ {
+ return -1; /* No mouse */
+ }
+
+ pti = PsGetCurrentThreadWin32Thread();
+ MessageQueue = pti->MessageQueue;
+
+ /* Update counter */
+ MessageQueue->iCursorLevel += bShow ? 1 : -1;
+ pti->iCursorLevel += bShow ? 1 : -1;
+
+ /* Check for trivial cases */
+ if ((bShow && MessageQueue->iCursorLevel != 0) ||
+ (!bShow && MessageQueue->iCursorLevel != -1))
+ {
+ /* Note: w don't update global info here because it is used only
+ internally to check if cursor is visible */
+ return MessageQueue->iCursorLevel;
+ }
+
+ /* Check if cursor is above window owned by this MessageQueue */
+ pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y);
+ if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue)
+ {
+ if (bShow)
+ {
+ /* Show the pointer */
+ GreMovePointer(hdcScreen, gpsi->ptCursor.x, gpsi->ptCursor.y);
+ TRACE("Showing pointer!\n");
+ }
+ else
+ {
+ /* Remove the pointer */
+ GreMovePointer(hdcScreen, -1, -1);
+ TRACE("Removing pointer!\n");
+ }
+
+ /* Update global info */
+ IntGetSysCursorInfo()->ShowingCursor = MessageQueue->iCursorLevel;
+ }
+
+ return MessageQueue->iCursorLevel;
+}
+
+DWORD FASTCALL
+UserGetKeyState(DWORD dwKey)
+{
+ DWORD dwRet = 0;
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+
+ pti = PsGetCurrentThreadWin32Thread();
+ MessageQueue = pti->MessageQueue;
+
+ if (dwKey < 0x100)
+ {
+ if (IS_KEY_DOWN(MessageQueue->afKeyState, dwKey))
+ dwRet |= 0xFF80; // If down, windows returns 0xFF80.
+ if (IS_KEY_LOCKED(MessageQueue->afKeyState, dwKey))
+ dwRet |= 0x1;
+ }
+ else
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ }
+ return dwRet;
+}
+
+/* change the input key state for a given key */
+static VOID
+UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue, WORD wVk, BOOL bIsDown)
+{
+ TRACE("UpdateKeyState wVk: %u, bIsDown: %d\n", wVk, bIsDown);
+
+ if (bIsDown)
+ {
+ /* If it's first key down event, xor lock bit */
+ if (!IS_KEY_DOWN(MessageQueue->afKeyState, wVk))
+ SET_KEY_LOCKED(MessageQueue->afKeyState, wVk, !IS_KEY_LOCKED(MessageQueue->afKeyState, wVk));
+
+ SET_KEY_DOWN(MessageQueue->afKeyState, wVk, TRUE);
+ MessageQueue->afKeyRecentDown[wVk / 8] |= (1 << (wVk % 8));
+ }
+ else
+ SET_KEY_DOWN(MessageQueue->afKeyState, wVk, FALSE);
+}
+
+/* update the input key state for a keyboard message */
+static VOID
+UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue, MSG* msg)
+{
+ UCHAR key;
+ BOOL down = FALSE;
+
+ TRACE("UpdateKeyStateFromMsg message:%u\n", msg->message);
+
+ switch (msg->message)
+ {
+ case WM_LBUTTONDOWN:
+ down = TRUE;
+ /* fall through */
+ case WM_LBUTTONUP:
+ UpdateKeyState(MessageQueue, VK_LBUTTON, down);
+ break;
+ case WM_MBUTTONDOWN:
+ down = TRUE;
+ /* fall through */
+ case WM_MBUTTONUP:
+ UpdateKeyState(MessageQueue, VK_MBUTTON, down);
+ break;
+ case WM_RBUTTONDOWN:
+ down = TRUE;
+ /* fall through */
+ case WM_RBUTTONUP:
+ UpdateKeyState(MessageQueue, VK_RBUTTON, down);
+ break;
+ case WM_XBUTTONDOWN:
+ down = TRUE;
+ /* fall through */
+ case WM_XBUTTONUP:
+ if (msg->wParam == XBUTTON1)
+ UpdateKeyState(MessageQueue, VK_XBUTTON1, down);
+ else if (msg->wParam == XBUTTON2)
+ UpdateKeyState(MessageQueue, VK_XBUTTON2, down);
+ break;
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ down = TRUE;
+ /* fall through */
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ key = (UCHAR)msg->wParam;
+ UpdateKeyState(MessageQueue, key, down);
+ switch(key)
+ {
+ case VK_LCONTROL:
+ case VK_RCONTROL:
+ down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LCONTROL) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RCONTROL);
+ UpdateKeyState(MessageQueue, VK_CONTROL, down);
+ break;
+ case VK_LMENU:
+ case VK_RMENU:
+ down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LMENU) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RMENU);
+ UpdateKeyState(MessageQueue, VK_MENU, down);
+ break;
+ case VK_LSHIFT:
+ case VK_RSHIFT:
+ down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LSHIFT) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RSHIFT);
+ UpdateKeyState(MessageQueue, VK_SHIFT, down);
+ break;
+ }
+ break;
+ }
+}
+
+HANDLE FASTCALL
+IntMsqSetWakeMask(DWORD WakeMask)
+{
+ PTHREADINFO Win32Thread;
+ HANDLE MessageEventHandle;
+ DWORD dwFlags = HIWORD(WakeMask);
+
+ Win32Thread = PsGetCurrentThreadWin32Thread();
+ if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
+ return 0;
+
+// Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
+ MessageEventHandle = Win32Thread->hEventQueueClient;
+
+ if (Win32Thread->pcti)
+ {
+ if ( (Win32Thread->pcti->fsChangeBits & LOWORD(WakeMask)) ||
+ ( (dwFlags & MWMO_INPUTAVAILABLE) && (Win32Thread->pcti->fsWakeBits & LOWORD(WakeMask)) ) )
+ {
+ ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread->pcti->fsChangeBits, Win32Thread->pcti->fsWakeBits, WakeMask);
+ KeSetEvent(Win32Thread->pEventQueueServer, IO_NO_INCREMENT, FALSE); // Wake it up!
+ return MessageEventHandle;
+ }
+ }
+
+ IdlePing();
+
+ return MessageEventHandle;
+}
+
+BOOL FASTCALL
+IntMsqClearWakeMask(VOID)
+{
+ PTHREADINFO Win32Thread;
+
+ Win32Thread = PsGetCurrentThreadWin32Thread();
+ if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
+ return FALSE;
+ // Very hacky, but that is what they do.
+ Win32Thread->pcti->fsWakeBits = 0;
+
+ IdlePong();
+
+ return TRUE;
+}
+
+/*
+ Due to the uncertainty of knowing what was set in our multilevel message queue,
+ and even if the bits are all cleared. The same as cTimers/cPaintsReady.
+ I think this is the best solution... (jt) */
+VOID FASTCALL
+MsqWakeQueue(PTHREADINFO pti, DWORD MessageBits, BOOL KeyEvent)
+{
+ PUSER_MESSAGE_QUEUE Queue;
+
+ Queue = pti->MessageQueue;
+
+ if (Queue->QF_flags & QF_INDESTROY)
+ {
+ ERR("This Message Queue is in Destroy!\n");
+ }
+ pti->pcti->fsWakeBits |= MessageBits;
+ pti->pcti->fsChangeBits |= MessageBits;
+
+ // Start bit accounting to help clear the main set of bits.
+ if (MessageBits & QS_KEY)
+ {
+ pti->nCntsQBits[QSRosKey]++;
+ }
+ if (MessageBits & QS_MOUSE)
+ {
+ if (MessageBits & QS_MOUSEMOVE) pti->nCntsQBits[QSRosMouseMove]++;
+ if (MessageBits & QS_MOUSEBUTTON) pti->nCntsQBits[QSRosMouseButton]++;
+ }
+ if (MessageBits & QS_POSTMESSAGE) pti->nCntsQBits[QSRosPostMessage]++;
+ if (MessageBits & QS_SENDMESSAGE) pti->nCntsQBits[QSRosSendMessage]++;
+ if (MessageBits & QS_HOTKEY) pti->nCntsQBits[QSRosHotKey]++;
+ if (MessageBits & QS_EVENT) pti->nCntsQBits[QSRosEvent]++;
+
+ if (KeyEvent)
+ KeSetEvent(pti->pEventQueueServer, IO_NO_INCREMENT, FALSE);
+}
+
+VOID FASTCALL
+ClearMsgBitsMask(PTHREADINFO pti, UINT MessageBits)
+{
+ PUSER_MESSAGE_QUEUE Queue;
+ UINT ClrMask = 0;
+
+ Queue = pti->MessageQueue;
+
+ if (MessageBits & QS_KEY)
+ {
+ if (--pti->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY;
+ }
+ if (MessageBits & QS_MOUSEMOVE) // ReactOS hard coded.
+ { // Account for tracking mouse moves..
+ if (--pti->nCntsQBits[QSRosMouseMove] == 0) ClrMask |= QS_MOUSEMOVE;
+ // Handle mouse move bits here.
+ if (Queue->MouseMoved) ClrMask |= QS_MOUSEMOVE;
+ }
+ if (MessageBits & QS_MOUSEBUTTON)
+ {
+ if (--pti->nCntsQBits[QSRosMouseButton] == 0) ClrMask |= QS_MOUSEBUTTON;
+ }
+ if (MessageBits & QS_POSTMESSAGE)
+ {
+ if (--pti->nCntsQBits[QSRosPostMessage] == 0) ClrMask |= QS_POSTMESSAGE;
+ }
+ if (MessageBits & QS_TIMER) // ReactOS hard coded.
+ { // Handle timer bits here.
+ if ( pti->cTimersReady )
+ {
+ if (--pti->cTimersReady == 0) ClrMask |= QS_TIMER;
+ }
+ }
+ if (MessageBits & QS_PAINT) // ReactOS hard coded.
+ { // Handle paint bits here.
+ if ( pti->cPaintsReady )
+ {
+ if (--pti->cPaintsReady == 0) ClrMask |= QS_PAINT;
+ }
+ }
+ if (MessageBits & QS_SENDMESSAGE)
+ {
+ if (--pti->nCntsQBits[QSRosSendMessage] == 0) ClrMask |= QS_SENDMESSAGE;
+ }
+ if (MessageBits & QS_HOTKEY)
+ {
+ if (--pti->nCntsQBits[QSRosHotKey] == 0) ClrMask |= QS_HOTKEY;
+ }
+ if (MessageBits & QS_EVENT)
+ {
+ if (--pti->nCntsQBits[QSRosEvent] == 0) ClrMask |= QS_EVENT;
+ }
+
+ pti->pcti->fsWakeBits &= ~ClrMask;
+ pti->pcti->fsChangeBits &= ~ClrMask;
+}
+
+VOID FASTCALL
+MsqIncPaintCountQueue(PTHREADINFO pti)
+{
+ pti->cPaintsReady++;
+ MsqWakeQueue(pti, QS_PAINT, TRUE);
+}
+
+VOID FASTCALL
+MsqDecPaintCountQueue(PTHREADINFO pti)
+{
+ ClearMsgBitsMask(pti, QS_PAINT);
+}
+
+VOID FASTCALL
+MsqPostMouseMove(PTHREADINFO pti, MSG* Msg)
+{
+ pti->MessageQueue->MouseMoveMsg = *Msg;
+ pti->MessageQueue->MouseMoved = TRUE;
+ MsqWakeQueue(pti, QS_MOUSEMOVE, TRUE);
+}
+
+VOID FASTCALL
+co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook)
+{
+ LARGE_INTEGER LargeTickCount;
+ MSLLHOOKSTRUCT MouseHookData;
+// PDESKTOP pDesk;
+ PWND pwnd, pwndDesktop;
+ HDC hdcScreen;
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+ PSYSTEM_CURSORINFO CurInfo;
+
+ KeQueryTickCount(&LargeTickCount);
+ Msg->time = MsqCalculateMessageTime(&LargeTickCount);
+
+ MouseHookData.pt.x = LOWORD(Msg->lParam);
+ MouseHookData.pt.y = HIWORD(Msg->lParam);
+ switch (Msg->message)
+ {
+ case WM_MOUSEWHEEL:
+ MouseHookData.mouseData = MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg->wParam));
+ break;
+ case WM_XBUTTONDOWN:
+ case WM_XBUTTONUP:
+ case WM_XBUTTONDBLCLK:
+ case WM_NCXBUTTONDOWN:
+ case WM_NCXBUTTONUP:
+ case WM_NCXBUTTONDBLCLK:
+ MouseHookData.mouseData = MAKELONG(0, HIWORD(Msg->wParam));
+ break;
+ default:
+ MouseHookData.mouseData = 0;
+ break;
+ }
+
+ MouseHookData.flags = flags; // LLMHF_INJECTED
+ MouseHookData.time = Msg->time;
+ MouseHookData.dwExtraInfo = dwExtraInfo;
+
+ /* If the hook procedure returned non zero, dont send the message */
+ if (Hook)
+ {
+ if (co_HOOK_CallHooks(WH_MOUSE_LL, HC_ACTION, Msg->message, (LPARAM) &MouseHookData))
+ return;
+ }
+
+ /* Get the desktop window */
+ pwndDesktop = UserGetDesktopWindow();
+ if (!pwndDesktop) return;
+// pDesk = pwndDesktop->head.rpdesk;
+
+ /* Check if the mouse is captured */
+ Msg->hwnd = IntGetCaptureWindow();
+ if (Msg->hwnd != NULL)
+ {
+ pwnd = UserGetWindowObject(Msg->hwnd);
+ }
+ else
+ {
+ pwnd = IntTopLevelWindowFromPoint(Msg->pt.x, Msg->pt.y);
+ if (pwnd) Msg->hwnd = pwnd->head.h;
+ }
+
+ hdcScreen = IntGetScreenDC();
+ CurInfo = IntGetSysCursorInfo();
+
+ /* Check if we found a window */
+ if (Msg->hwnd != NULL && pwnd != NULL)
+ {
+ pti = pwnd->head.pti;
+ MessageQueue = pti->MessageQueue;
+ // MessageQueue->ptiMouse = pti;
+
+ if ( pti->TIF_flags & TIF_INCLEANUP || MessageQueue->QF_flags & QF_INDESTROY)
+ {
+ ERR("Mouse is over the Window Thread is Dead!\n");
+ return;
+ }
+
+ if (Msg->message == WM_MOUSEMOVE)
+ {
+ /* Check if cursor should be visible */
+ if(hdcScreen &&
+ MessageQueue->CursorObject &&
+ MessageQueue->iCursorLevel >= 0)
+ {
+ /* Check if shape has changed */
+ if(CurInfo->CurrentCursorObject != MessageQueue->CursorObject)
+ {
+ /* Call GDI to set the new screen cursor */
+#ifdef NEW_CURSORICON
+ GreSetPointerShape(hdcScreen,
+ MessageQueue->CursorObject->hbmAlpha ?
+ NULL : MessageQueue->CursorObject->hbmMask,
+ MessageQueue->CursorObject->hbmAlpha ?
+ MessageQueue->CursorObject->hbmAlpha : MessageQueue->CursorObject->hbmColor,
+ MessageQueue->CursorObject->xHotspot,
+ MessageQueue->CursorObject->yHotspot,
+ gpsi->ptCursor.x,
+ gpsi->ptCursor.y,
+ MessageQueue->CursorObject->hbmAlpha ? SPS_ALPHA : 0);
+#else
+ GreSetPointerShape(hdcScreen,
+ MessageQueue->CursorObject->IconInfo.hbmMask,
+ MessageQueue->CursorObject->IconInfo.hbmColor,
+ MessageQueue->CursorObject->IconInfo.xHotspot,
+ MessageQueue->CursorObject->IconInfo.yHotspot,
+ gpsi->ptCursor.x,
+ gpsi->ptCursor.y,
+ 0);
+#endif
+ } else
+ GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y);
+ }
+ /* Check if w have to hide cursor */
+ else if (CurInfo->ShowingCursor >= 0)
+ GreMovePointer(hdcScreen, -1, -1);
+
+ /* Update global cursor info */
+ CurInfo->ShowingCursor = MessageQueue->iCursorLevel;
+ CurInfo->CurrentCursorObject = MessageQueue->CursorObject;
+ gpqCursor = MessageQueue;
+
+ /* Mouse move is a special case */
+ MsqPostMouseMove(pti, Msg);
+ }
+ else
+ {
+ if (!IntGetCaptureWindow())
+ {
+ // ERR("ptiLastInput is set\n");
+ // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground.
+ }
+ TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd));
+ MsqPostMessage(pti, Msg, TRUE, QS_MOUSEBUTTON, 0);
+ }
+ }
+ else if (hdcScreen)
+ {
+ /* always show cursor on background; FIXME: set default pointer */
+ GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y);
+ CurInfo->ShowingCursor = 0;
+ }
+}
+
+PUSER_MESSAGE FASTCALL
+MsqCreateMessage(LPMSG Msg)
+{
+ PUSER_MESSAGE Message;
+
+ Message = ExAllocateFromPagedLookasideList(pgMessageLookasideList);
+ if (!Message)
+ {
+ return NULL;
+ }
+
+ RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG));
+
+ return Message;
+}
+
+VOID FASTCALL
+MsqDestroyMessage(PUSER_MESSAGE Message)
+{
+ ExFreeToPagedLookasideList(pgMessageLookasideList, Message);
+}
+
+BOOLEAN FASTCALL
+co_MsqDispatchOneSentMessage(PTHREADINFO pti)
+{
+ PUSER_SENT_MESSAGE SaveMsg, Message;
+ PLIST_ENTRY Entry;
+ BOOL Ret;
+ LRESULT Result = 0;
+
+ if (IsListEmpty(&pti->SentMessagesListHead))
+ {
+ return(FALSE);
+ }
+
+ /* remove it from the list of pending messages */
+ Entry = RemoveHeadList(&pti->SentMessagesListHead);
+ Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
+
+ SaveMsg = pti->pusmCurrent;
+ pti->pusmCurrent = Message;
+
+ // Processing a message sent to it from another thread.
+ if ( ( Message->ptiSender && pti != Message->ptiSender) ||
+ ( Message->ptiCallBackSender && pti != Message->ptiCallBackSender ))
+ { // most likely, but, to be sure.
+ pti->pcti->CTI_flags |= CTI_INSENDMESSAGE; // Let the user know...
+ }
+
+ /* insert it to the list of messages that are currently dispatched by this
+ message queue */
+ InsertTailList(&pti->LocalDispatchingMessagesHead,
+ &Message->ListEntry);
+
+ ClearMsgBitsMask(pti, Message->QS_Flags);
+
+ if (Message->HookMessage == MSQ_ISHOOK)
+ { // Direct Hook Call processor
+ Result = co_CallHook( Message->Msg.message, // HookId
+ (INT)(INT_PTR)Message->Msg.hwnd, // Code
+ Message->Msg.wParam,
+ Message->Msg.lParam);
+ }
+ else if (Message->HookMessage == MSQ_ISEVENT)
+ { // Direct Event Call processor
+ Result = co_EVENT_CallEvents( Message->Msg.message,
+ Message->Msg.hwnd,
+ Message->Msg.wParam,
+ Message->Msg.lParam);
+ }
+ else if(Message->HookMessage == MSQ_INJECTMODULE)
+ {
+ Result = IntLoadHookModule(Message->Msg.message,
+ (HHOOK)Message->Msg.lParam,
+ Message->Msg.wParam);
+ }
+ else if ((Message->CompletionCallback) &&
+ (Message->ptiCallBackSender == pti))
+ { /* Call the callback routine */
+ if (Message->QS_Flags & QS_SMRESULT)
+ {
+ co_IntCallSentMessageCallback(Message->CompletionCallback,
+ Message->Msg.hwnd,
+ Message->Msg.message,
+ Message->CompletionCallbackContext,
+ Message->lResult);
+ /* Set callback to NULL to prevent reentry */
+ Message->CompletionCallback = NULL;
+ }
+ else
+ {
+ /* The message has not been processed yet, reinsert it. */
+ RemoveEntryList(&Message->ListEntry);
+ InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry);
+ TRACE("Callback Message not processed yet. Requeuing the message\n");
+ Ret = FALSE;
+ goto Exit;
+ }
+ }
+ else
+ { /* Call the window procedure. */
+ Result = co_IntSendMessage( Message->Msg.hwnd,
+ Message->Msg.message,
+ Message->Msg.wParam,
+ Message->Msg.lParam);
+ }
+
+ /* remove the message from the local dispatching list, because it doesn't need
+ to be cleaned up on thread termination anymore */
+ RemoveEntryList(&Message->ListEntry);
+
+ /* If the message is a callback, insert it in the callback senders MessageQueue */
+ if (Message->CompletionCallback)
+ {
+ if (Message->ptiCallBackSender)
+ {
+ Message->lResult = Result;
+ Message->QS_Flags |= QS_SMRESULT;
+
+ /* insert it in the callers message queue */
+ InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry);
+ MsqWakeQueue(Message->ptiCallBackSender, QS_SENDMESSAGE, TRUE);
+ }
+ Ret = TRUE;
+ goto Exit;
+ }
+
+ /* remove the message from the dispatching list if needed, so lock the sender's message queue */
+ if (Message->ptiSender)
+ {
+ if (Message->DispatchingListEntry.Flink != NULL)
+ {
+ /* only remove it from the dispatching list if not already removed by a timeout */
+ RemoveEntryList(&Message->DispatchingListEntry);
+ }
+ }
+ /* still keep the sender's message queue locked, so the sender can't exit the
+ MsqSendMessage() function (if timed out) */
+
+ if (Message->QS_Flags & QS_SMRESULT)
+ {
+ Result = Message->lResult;
+ }
+
+ /* Let the sender know the result. */
+ if (Message->Result != NULL)
+ {
+ *Message->Result = Result;
+ }
+
- if (SentMessage->HasPackedLParam == TRUE)
++ if (Message->HasPackedLParam)
+ {
+ if (Message->Msg.lParam)
+ ExFreePool((PVOID)Message->Msg.lParam);
+ }
+
+ /* Notify the sender. */
+ if (Message->CompletionEvent != NULL)
+ {
+ KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ /* free the message */
+ ExFreePoolWithTag(Message, TAG_USRMSG);
+ Ret = TRUE;
+Exit:
+ /* do not hangup on the user if this is reentering */
+ if (!SaveMsg) pti->pcti->CTI_flags &= ~CTI_INSENDMESSAGE;
+ pti->pusmCurrent = SaveMsg;
+
+ return Ret;
+}
+
+VOID APIENTRY
+MsqRemoveWindowMessagesFromQueue(PWND Window)
+{
+ PTHREADINFO pti;
+ PUSER_SENT_MESSAGE SentMessage;
+ PUSER_MESSAGE PostedMessage;
+ PLIST_ENTRY CurrentEntry, ListHead;
+
+ ASSERT(Window);
+
+ pti = Window->head.pti;
+
+ /* remove the posted messages for this window */
+ CurrentEntry = pti->PostedMessagesListHead.Flink;
+ ListHead = &pti->PostedMessagesListHead;
+ while (CurrentEntry != ListHead)
+ {
+ PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+ ListEntry);
+ if (PostedMessage->Msg.hwnd == Window->head.h)
+ {
+ RemoveEntryList(&PostedMessage->ListEntry);
+ ClearMsgBitsMask(pti, PostedMessage->QS_Flags);
+ MsqDestroyMessage(PostedMessage);
+ CurrentEntry = pti->PostedMessagesListHead.Flink;
+ }
+ else
+ {
+ CurrentEntry = CurrentEntry->Flink;
+ }
+ }
+
+ /* remove the sent messages for this window */
+ CurrentEntry = pti->SentMessagesListHead.Flink;
+ ListHead = &pti->SentMessagesListHead;
+ while (CurrentEntry != ListHead)
+ {
+ SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
+ ListEntry);
+ if(SentMessage->Msg.hwnd == Window->head.h)
+ {
+ TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
+
+ RemoveEntryList(&SentMessage->ListEntry);
+ ClearMsgBitsMask(pti, SentMessage->QS_Flags);
+
+ /* Only if the message has a sender was the queue referenced */
+ if ((SentMessage->ptiSender)
+ && (SentMessage->DispatchingListEntry.Flink != NULL))
+ {
+ RemoveEntryList(&SentMessage->DispatchingListEntry);
+ }
+
+ /* wake the sender's thread */
+ if (SentMessage->CompletionEvent != NULL)
+ {
+ KeSetEvent(SentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
+ }
+
- if (CurrentSentMessage->HasPackedLParam == TRUE)
++ if (SentMessage->HasPackedLParam)
+ {
+ if (SentMessage->Msg.lParam)
+ ExFreePool((PVOID)SentMessage->Msg.lParam);
+ }
+
+ /* free the message */
+ ExFreePoolWithTag(SentMessage, TAG_USRMSG);
+
+ CurrentEntry = pti->SentMessagesListHead.Flink;
+ }
+ else
+ {
+ CurrentEntry = CurrentEntry->Flink;
+ }
+ }
+}
+
+BOOL FASTCALL
+co_MsqSendMessageAsync(PTHREADINFO ptiReceiver,
+ HWND hwnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ SENDASYNCPROC CompletionCallback,
+ ULONG_PTR CompletionCallbackContext,
+ BOOL HasPackedLParam,
+ INT HookMessage)
+{
+
+ PTHREADINFO ptiSender;
+ PUSER_SENT_MESSAGE Message;
+
+ if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
+ {
+ ERR("MsqSendMessage(): Not enough memory to allocate a message");
+ return FALSE;
+ }
+
+ ptiSender = PsGetCurrentThreadWin32Thread();
+
+ Message->Msg.hwnd = hwnd;
+ Message->Msg.message = Msg;
+ Message->Msg.wParam = wParam;
+ Message->Msg.lParam = lParam;
+ Message->CompletionEvent = NULL;
+ Message->Result = 0;
+ Message->lResult = 0;
+ Message->ptiReceiver = ptiReceiver;
+ Message->ptiSender = NULL;
+ Message->ptiCallBackSender = ptiSender;
+ Message->DispatchingListEntry.Flink = NULL;
+ Message->CompletionCallback = CompletionCallback;
+ Message->CompletionCallbackContext = CompletionCallbackContext;
+ Message->HookMessage = HookMessage;
+ Message->HasPackedLParam = HasPackedLParam;
+ Message->QS_Flags = QS_SENDMESSAGE;
+
+ InsertTailList(&ptiReceiver->SentMessagesListHead, &Message->ListEntry);
+ MsqWakeQueue(ptiReceiver, QS_SENDMESSAGE, TRUE);
+
+ return TRUE;
+}
+
+NTSTATUS FASTCALL
+co_MsqSendMessage(PTHREADINFO ptirec,
+ HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
+ UINT uTimeout, BOOL Block, INT HookMessage,
+ ULONG_PTR *uResult)
+{
+ PTHREADINFO pti;
+ PUSER_SENT_MESSAGE Message;
+ KEVENT CompletionEvent;
+ NTSTATUS WaitStatus;
+ LARGE_INTEGER Timeout;
+ PLIST_ENTRY Entry;
+ PWND pWnd;
+ LRESULT Result = 0; //// Result could be trashed. ////
+
+ pti = PsGetCurrentThreadWin32Thread();
+ ASSERT(pti != ptirec);
+ ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!!
+
+ /* Don't send from or to a dying thread */
+ if (pti->TIF_flags & TIF_INCLEANUP || ptirec->TIF_flags & TIF_INCLEANUP)
+ {
+ // Unless we are dying and need to tell our parents.
+ if (pti->TIF_flags & TIF_INCLEANUP && !(ptirec->TIF_flags & TIF_INCLEANUP))
+ {
+ // Parent notify is the big one. Fire and forget!
+ TRACE("Send message from dying thread %d\n",Msg);
+ co_MsqSendMessageAsync(ptirec, Wnd, Msg, wParam, lParam, NULL, 0, FALSE, HookMessage);
+ }
+ if (uResult) *uResult = -1;
+ TRACE("MsqSM: Msg %d Current pti %lu or Rec pti %lu\n", Msg, pti->TIF_flags & TIF_INCLEANUP, ptirec->TIF_flags & TIF_INCLEANUP);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if ( HookMessage == MSQ_NORMAL )
+ {
+ pWnd = ValidateHwndNoErr(Wnd);
+
+ // These can not cross International Border lines!
+ if ( pti->ppi != ptirec->ppi && pWnd )
+ {
+ switch(Msg)
+ {
+ // Handle the special case when working with password transfers across bordering processes.
+ case EM_GETLINE:
+ case EM_SETPASSWORDCHAR:
+ case WM_GETTEXT:
+ // Look for edit controls setup for passwords.
+ if ( gpsi->atomSysClass[ICLS_EDIT] == pWnd->pcls->atomClassName && // Use atomNVClassName.
+ pWnd->style & ES_PASSWORD )
+ {
+ if (uResult) *uResult = -1;
+ ERR("Running across the border without a passport!\n");
+ EngSetLastError(ERROR_ACCESS_DENIED);
+ return STATUS_UNSUCCESSFUL;
+ }
+ break;
+ case WM_NOTIFY:
+ if (uResult) *uResult = -1;
+ ERR("Running across the border without a passport!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ // These can not cross State lines!
+ if ( Msg == WM_CREATE || Msg == WM_NCCREATE )
+ {
+ if (uResult) *uResult = -1;
+ ERR("Can not tell the other State we have Create!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ if(!(Message = ExAllocatePoolWithTag(PagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
+ {
+ ERR("MsqSendMessage(): Not enough memory to allocate a message");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ KeInitializeEvent(&CompletionEvent, NotificationEvent, FALSE);
+
+ Timeout.QuadPart = (LONGLONG) uTimeout * (LONGLONG) -10000;
+
+ /* FIXME: Increase reference counter of sender's message queue here */
+
+ Message->Msg.hwnd = Wnd;
+ Message->Msg.message = Msg;
+ Message->Msg.wParam = wParam;
+ Message->Msg.lParam = lParam;
+ Message->CompletionEvent = &CompletionEvent;
+ Message->Result = &Result;
+ Message->lResult = 0;
+ Message->QS_Flags = 0;
+ Message->ptiReceiver = ptirec;
+ Message->ptiSender = pti;
+ Message->ptiCallBackSender = NULL;
+ Message->CompletionCallback = NULL;
+ Message->CompletionCallbackContext = 0;
+ Message->HookMessage = HookMessage;
+ Message->HasPackedLParam = FALSE;
+
+ /* Add it to the list of pending messages */
+ InsertTailList(&pti->DispatchingMessagesHead, &Message->DispatchingListEntry);
+
+ /* Queue it in the destination's message queue */
+ InsertTailList(&ptirec->SentMessagesListHead, &Message->ListEntry);
+
+ Message->QS_Flags = QS_SENDMESSAGE;
+ MsqWakeQueue(ptirec, QS_SENDMESSAGE, TRUE);
+
+ /* We can't access the Message anymore since it could have already been deleted! */
+
+ if(Block)
+ {
+ UserLeaveCo();
+
+ /* Don't process messages sent to the thread */
+ WaitStatus = KeWaitForSingleObject(&CompletionEvent, UserRequest, UserMode,
+ FALSE, (uTimeout ? &Timeout : NULL));
+
+ UserEnterCo();
+
+ if(WaitStatus == STATUS_TIMEOUT)
+ {
+ /* Look up if the message has not yet dispatched, if so
+ make sure it can't pass a result and it must not set the completion event anymore */
+ Entry = ptirec->SentMessagesListHead.Flink;
+ while (Entry != &ptirec->SentMessagesListHead)
+ {
+ if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry)
+ == Message)
+ {
+ /* We can access Message here, it's secure because the message queue is locked
+ and the message is still hasn't been dispatched */
+ Message->CompletionEvent = NULL;
+ Message->Result = NULL;
+ break;
+ }
+ Entry = Entry->Flink;
+ }
+
+ /* Remove from the local dispatching list so the other thread knows,
+ it can't pass a result and it must not set the completion event anymore */
+ Entry = pti->DispatchingMessagesHead.Flink;
+ while (Entry != &pti->DispatchingMessagesHead)
+ {
+ if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
+ == Message)
+ {
+ /* We can access Message here, it's secure because the sender's message is locked
+ and the message has definitely not yet been destroyed, otherwise it would
+ have been removed from this list by the dispatching routine right after
+ dispatching the message */
+ Message->CompletionEvent = NULL;
+ Message->Result = NULL;
+ RemoveEntryList(&Message->DispatchingListEntry);
+ Message->DispatchingListEntry.Flink = NULL;
+ break;
+ }
+ Entry = Entry->Flink;
+ }
+
+ TRACE("MsqSendMessage (blocked) timed out 1\n");
+ }
+ while (co_MsqDispatchOneSentMessage(ptirec))
+ ;
+ }
+ else
+ {
+ PVOID WaitObjects[3];
+
+ WaitObjects[0] = &CompletionEvent; // Wait 0
+ WaitObjects[1] = pti->pEventQueueServer; // Wait 1
+ WaitObjects[2] = ptirec->pEThread; // Wait 2
+
+ do
+ {
+ UserLeaveCo();
+
+ WaitStatus = KeWaitForMultipleObjects(3, WaitObjects, WaitAny, UserRequest,
+ UserMode, FALSE, (uTimeout ? &Timeout : NULL), NULL);
+
+ UserEnterCo();
+
+ if(WaitStatus == STATUS_TIMEOUT)
+ {
+ /* Look up if the message has not yet been dispatched, if so
+ make sure it can't pass a result and it must not set the completion event anymore */
+ Entry = ptirec->SentMessagesListHead.Flink;
+ while (Entry != &ptirec->SentMessagesListHead)
+ {
+ if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry)
+ == Message)
+ {
+ /* We can access Message here, it's secure because the message queue is locked
+ and the message is still hasn't been dispatched */
+ Message->CompletionEvent = NULL;
+ Message->Result = NULL;
+ break;
+ }
+ Entry = Entry->Flink;
+ }
+
+ /* Remove from the local dispatching list so the other thread knows,
+ it can't pass a result and it must not set the completion event anymore */
+ Entry = pti->DispatchingMessagesHead.Flink;
+ while (Entry != &pti->DispatchingMessagesHead)
+ {
+ if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
+ == Message)
+ {
+ /* We can access Message here, it's secure because the sender's message is locked
+ and the message has definitely not yet been destroyed, otherwise it would
+ have been removed from this list by the dispatching routine right after
+ dispatching the message */
+ Message->CompletionEvent = NULL;
+ Message->Result = NULL;
+ RemoveEntryList(&Message->DispatchingListEntry);
+ Message->DispatchingListEntry.Flink = NULL;
+ break;
+ }
+ Entry = Entry->Flink;
+ }
+
+ TRACE("MsqSendMessage timed out 2\n");
+ break;
+ }
+ // Receiving thread passed on and left us hanging with issues still pending.
+ if ( WaitStatus == STATUS_WAIT_2 )
+ {
+ ERR("Receiving Thread woken up dead!\n");
+ Entry = pti->DispatchingMessagesHead.Flink;
+ while (Entry != &pti->DispatchingMessagesHead)
+ {
+ if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
+ == Message)
+ {
+ Message->CompletionEvent = NULL;
+ Message->Result = NULL;
+ RemoveEntryList(&Message->DispatchingListEntry);
+ Message->DispatchingListEntry.Flink = NULL;
+ break;
+ }
+ Entry = Entry->Flink;
+ }
+ }
+ while (co_MsqDispatchOneSentMessage(pti))
+ ;
+ }
+ while (NT_SUCCESS(WaitStatus) && WaitStatus == STATUS_WAIT_1);
+ }
+
+ if(WaitStatus != STATUS_TIMEOUT)
+ if (uResult) *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1);
+
+ return WaitStatus;
+}
+
+VOID FASTCALL
+MsqPostMessage(PTHREADINFO pti,
+ MSG* Msg,
+ BOOLEAN HardwareMessage,
+ DWORD MessageBits,
+ DWORD dwQEvent)
+{
+ PUSER_MESSAGE Message;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+
+ if ( pti->TIF_flags & TIF_INCLEANUP || pti->MessageQueue->QF_flags & QF_INDESTROY )
+ {
+ ERR("Post Msg; Thread or Q is Dead!\n");
+ return;
+ }
+
+ if(!(Message = MsqCreateMessage(Msg)))
+ {
+ return;
+ }
+
+ MessageQueue = pti->MessageQueue;
+
+ if (dwQEvent)
+ {
+ ERR("Post Msg; System Qeued Event Message!\n");
+ InsertHeadList(&pti->PostedMessagesListHead,
+ &Message->ListEntry);
+ }
+ else if (!HardwareMessage)
+ {
+ InsertTailList(&pti->PostedMessagesListHead,
+ &Message->ListEntry);
+ }
+ else
+ {
+ InsertTailList(&MessageQueue->HardwareMessagesListHead,
+ &Message->ListEntry);
+ }
+
+ if (Msg->message == WM_HOTKEY) MessageBits |= QS_HOTKEY; // Justin Case, just set it.
+ Message->dwQEvent = dwQEvent;
+ Message->QS_Flags = MessageBits;
+ Message->pti = pti;
+ MsqWakeQueue(pti, MessageBits, TRUE);
+}
+
+VOID FASTCALL
+MsqPostQuitMessage(PTHREADINFO pti, ULONG ExitCode)
+{
+ pti->QuitPosted = TRUE;
+ pti->exitCode = ExitCode;
+ MsqWakeQueue(pti, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE, TRUE);
+}
+
+/***********************************************************************
+ * MsqSendParentNotify
+ *
+ * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
+ * the window has the WS_EX_NOPARENTNOTIFY style.
+ */
+static void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt )
+{
+ PWND pwndDesktop = UserGetDesktopWindow();
+
+ /* pt has to be in the client coordinates of the parent window */
+ pt.x += pwndDesktop->rcClient.left - pwnd->rcClient.left;
+ pt.y += pwndDesktop->rcClient.top - pwnd->rcClient.top;
+
+ for (;;)
+ {
+ PWND pwndParent;
+
+ if (!(pwnd->style & WS_CHILD)) break;
+ if (pwnd->ExStyle & WS_EX_NOPARENTNOTIFY) break;
+ if (!(pwndParent = IntGetParent(pwnd))) break;
+ if (pwndParent == pwndDesktop) break;
+ pt.x += pwnd->rcClient.left - pwndParent->rcClient.left;
+ pt.y += pwnd->rcClient.top - pwndParent->rcClient.top;
+
+ pwnd = pwndParent;
+ co_IntSendMessage( UserHMGetHandle(pwnd), WM_PARENTNOTIFY,
+ MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) );
+ }
+}
+
+VOID
+FASTCALL
+IntTrackMouseMove(PWND pwndTrack, PDESKTOP pDesk, PMSG msg, USHORT hittest)
+{
+// PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
+// hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this???
+
+ if ( pDesk->spwndTrack != pwndTrack || // Change with tracking window or
+ msg->message != WM_MOUSEMOVE || // Mouse click changes or
+ pDesk->htEx != hittest) // Change in current hit test states.
+ {
+ TRACE("ITMM: Track Mouse Move!\n");
+
+ /* Handle only the changing window track and mouse move across a border. */
+ if ( pDesk->spwndTrack != pwndTrack ||
+ (pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT) )
+ {
+ TRACE("ITMM: Another Wnd %d or Across Border %d\n",
+ pDesk->spwndTrack != pwndTrack,(pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT));
+
+ if ( pDesk->dwDTFlags & DF_TME_LEAVE )
+ UserPostMessage( UserHMGetHandle(pDesk->spwndTrack),
+ (pDesk->htEx != HTCLIENT) ? WM_NCMOUSELEAVE : WM_MOUSELEAVE,
+ 0, 0);
+
+ if ( pDesk->dwDTFlags & DF_TME_HOVER )
+ IntKillTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE);
+
+ /* Clear the flags to sign a change. */
+ pDesk->dwDTFlags &= ~(DF_TME_LEAVE|DF_TME_HOVER);
+ }
+ /* Set the Track window and hit test. */
+ pDesk->spwndTrack = pwndTrack;
+ pDesk->htEx = hittest;
+ }
+
+ /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
+ if ( pDesk->spwndTrack == pwndTrack &&
+ ( msg->message != WM_MOUSEMOVE || !RECTL_bPointInRect(&pDesk->rcMouseHover, msg->pt.x, msg->pt.y)) &&
+ pDesk->dwDTFlags & DF_TME_HOVER )
+ {
+ TRACE("ITMM: Reset Hover points!\n");
+ // Restart timer for the hover period.
+ IntSetTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM);
+ // Reset desktop mouse hover from the system default hover rectangle.
+ RECTL_vSetRect(&pDesk->rcMouseHover,
+ msg->pt.x - gspv.iMouseHoverWidth / 2,
+ msg->pt.y - gspv.iMouseHoverHeight / 2,
+ msg->pt.x + gspv.iMouseHoverWidth / 2,
+ msg->pt.y + gspv.iMouseHoverHeight / 2);
+ }
+}
+
+BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT last)
+{
+ MSG clk_msg;
+ POINT pt;
+ UINT message;
+ USHORT hittest;
+ EVENTMSG event;
+ MOUSEHOOKSTRUCT hook;
+ BOOL eatMsg = FALSE;
+
+ PWND pwndMsg, pwndDesktop;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+ PTHREADINFO pti;
+ PSYSTEM_CURSORINFO CurInfo;
+ PDESKTOP pDesk;
+ DECLARE_RETURN(BOOL);
+
+ pti = PsGetCurrentThreadWin32Thread();
+ pwndDesktop = UserGetDesktopWindow();
+ MessageQueue = pti->MessageQueue;
+ CurInfo = IntGetSysCursorInfo();
+ pwndMsg = ValidateHwndNoErr(msg->hwnd);
+ clk_msg = MessageQueue->msgDblClk;
+ pDesk = pwndDesktop->head.rpdesk;
+
+ /* find the window to dispatch this mouse message to */
+ if (MessageQueue->spwndCapture)
+ {
+ hittest = HTCLIENT;
+ pwndMsg = MessageQueue->spwndCapture;
+ if (pwndMsg) UserReferenceObject(pwndMsg);
+ }
+ else
+ {
+ pwndMsg = co_WinPosWindowFromPoint(NULL, &msg->pt, &hittest, FALSE);//TRUE);
+ }
+
+ TRACE("Got mouse message for %p, hittest: 0x%x\n", msg->hwnd, hittest);
+
+ if (pwndMsg == NULL || pwndMsg->head.pti != pti)
+ {
+ /* Remove and ignore the message */
+ *RemoveMessages = TRUE;
+ RETURN(FALSE);
+ }
+
+ if ( MessageQueue == gpqCursor ) // Cursor must use the same Queue!
+ {
+ IntTrackMouseMove(pwndMsg, pDesk, msg, hittest);
+ }
+ else
+ {
+ ERR("Not the same cursor!\n");
+ }
+
+ msg->hwnd = UserHMGetHandle(pwndMsg);
+
+ pt = msg->pt;
+ message = msg->message;
+ /* Note: windows has no concept of a non-client wheel message */
+ if (message != WM_MOUSEWHEEL)
+ {
+ if (hittest != HTCLIENT)
+ {
+ message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
+ msg->wParam = hittest;
+ }
+ else
+ {
+ /* coordinates don't get translated while tracking a menu */
+ /* FIXME: should differentiate popups and top-level menus */
+ if (!(MessageQueue->MenuOwner))
+ {
+ pt.x += pwndDesktop->rcClient.left - pwndMsg->rcClient.left;
+ pt.y += pwndDesktop->rcClient.top - pwndMsg->rcClient.top;
+ }
+ }
+ }
+ msg->lParam = MAKELONG( pt.x, pt.y );
+
+ /* translate double clicks */
+
+ if ((msg->message == WM_LBUTTONDOWN) ||
+ (msg->message == WM_RBUTTONDOWN) ||
+ (msg->message == WM_MBUTTONDOWN) ||
+ (msg->message == WM_XBUTTONDOWN))
+ {
+ BOOL update = *RemoveMessages;
+
+ /* translate double clicks -
+ * note that ...MOUSEMOVEs can slip in between
+ * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
+
+ if ((MessageQueue->MenuOwner || MessageQueue->MoveSize) ||
+ hittest != HTCLIENT ||
+ (pwndMsg->pcls->style & CS_DBLCLKS))
+ {
+ if ((msg->message == clk_msg.message) &&
+ (msg->hwnd == clk_msg.hwnd) &&
+ (msg->wParam == clk_msg.wParam) &&
+ ((msg->time - clk_msg.time) < (ULONG)gspv.iDblClickTime) &&
+ (abs(msg->pt.x - clk_msg.pt.x) < UserGetSystemMetrics(SM_CXDOUBLECLK)/2) &&
+ (abs(msg->pt.y - clk_msg.pt.y) < UserGetSystemMetrics(SM_CYDOUBLECLK)/2))
+ {
+ message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
+ if (update)
+ {
+ MessageQueue->msgDblClk.message = 0; /* clear the double click conditions */
+ update = FALSE;
+ }
+ }
+ }
+
+ if (!((first == 0 && last == 0) || (message >= first || message <= last)))
+ {
+ TRACE("Message out of range!!!\n");
+ RETURN(FALSE);
+ }
+
+ /* update static double click conditions */
+ if (update) MessageQueue->msgDblClk = *msg;
+ }
+ else
+ {
+ if (!((first == 0 && last == 0) || (message >= first || message <= last)))
+ {
+ TRACE("Message out of range!!!\n");
+ RETURN(FALSE);
+ }
+ }
+
+ if(gspv.bMouseClickLock)
+ {
+ BOOL IsClkLck = FALSE;
+
+ if(msg->message == WM_LBUTTONUP)
+ {
+ IsClkLck = ((msg->time - CurInfo->ClickLockTime) >= gspv.dwMouseClickLockTime);
+ if (IsClkLck && (!CurInfo->ClickLockActive))
+ {
+ CurInfo->ClickLockActive = TRUE;
+ }
+ }
+ else if (msg->message == WM_LBUTTONDOWN)
+ {
+ if (CurInfo->ClickLockActive)
+ {
+ IsClkLck = TRUE;
+ CurInfo->ClickLockActive = FALSE;
+ }
+
+ CurInfo->ClickLockTime = msg->time;
+ }
+
+ if(IsClkLck)
+ {
+ /* Remove and ignore the message */
+ *RemoveMessages = TRUE;
+ RETURN(FALSE);
+ }
+ }
+
+ /* message is accepted now (but may still get dropped) */
+
+ event.message = msg->message;
+ event.time = msg->time;
+ event.hwnd = msg->hwnd;
+ event.paramL = msg->pt.x;
+ event.paramH = msg->pt.y;
+ co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
+
+ hook.pt = msg->pt;
+ hook.hwnd = msg->hwnd;
+ hook.wHitTestCode = hittest;
+ hook.dwExtraInfo = 0 /* extra_info */ ;
+ if (co_HOOK_CallHooks( WH_MOUSE, *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
+ message, (LPARAM)&hook ))
+ {
+ hook.pt = msg->pt;
+ hook.hwnd = msg->hwnd;
+ hook.wHitTestCode = hittest;
+ hook.dwExtraInfo = 0 /* extra_info */ ;
+ co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook );
+
+ ERR("WH_MOUSE dropped mouse message!\n");
+
+ /* Remove and skip message */
+ *RemoveMessages = TRUE;
+ RETURN(FALSE);
+ }
+
+ if ((hittest == HTERROR) || (hittest == HTNOWHERE))
+ {
+ co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd,
+ MAKELONG( hittest, msg->message ));
+
+ /* Remove and skip message */
+ *RemoveMessages = TRUE;
+ RETURN(FALSE);
+ }
+
+ if ((*RemoveMessages == FALSE) || MessageQueue->spwndCapture)
+ {
+ /* Accept the message */
+ msg->message = message;
+ RETURN(TRUE);
+ }
+
+ if ((msg->message == WM_LBUTTONDOWN) ||
+ (msg->message == WM_RBUTTONDOWN) ||
+ (msg->message == WM_MBUTTONDOWN) ||
+ (msg->message == WM_XBUTTONDOWN))
+ {
+ /* Send the WM_PARENTNOTIFY,
+ * note that even for double/nonclient clicks
+ * notification message is still WM_L/M/RBUTTONDOWN.
+ */
+ MsqSendParentNotify(pwndMsg, msg->message, 0, msg->pt );
+
+ /* Activate the window if needed */
+
+ if (pwndMsg != MessageQueue->spwndActive)
+ {
+ PWND pwndTop = pwndMsg;
+ pwndTop = IntGetNonChildAncestor(pwndTop);
+
+ if (pwndTop && pwndTop != pwndDesktop)
+ {
+ LONG ret = co_IntSendMessage( msg->hwnd,
+ WM_MOUSEACTIVATE,
+ (WPARAM)UserHMGetHandle(pwndTop),
+ MAKELONG( hittest, msg->message));
+ switch(ret)
+ {
+ case MA_NOACTIVATEANDEAT:
+ eatMsg = TRUE;
+ /* fall through */
+ case MA_NOACTIVATE:
+ break;
+ case MA_ACTIVATEANDEAT:
+ eatMsg = TRUE;
+ /* fall through */
+ case MA_ACTIVATE:
+ case 0:
+ if (!co_IntMouseActivateWindow( pwndTop )) eatMsg = TRUE;
+ break;
+ default:
+ ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret );
+ break;
+ }
+ }
+ }
+ }
+
+ /* send the WM_SETCURSOR message */
+
+ /* Windows sends the normal mouse message as the message parameter
+ in the WM_SETCURSOR message even if it's non-client mouse message */
+ co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message ));
+
+ msg->message = message;
+ RETURN(!eatMsg);
+
+CLEANUP:
+ if(pwndMsg)
+ UserDereferenceObject(pwndMsg);
+
+ END_CLEANUP;
+}
+
+BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
+{
+ EVENTMSG Event;
+
+ if (Msg->message == WM_KEYDOWN || Msg->message == WM_SYSKEYDOWN ||
+ Msg->message == WM_KEYUP || Msg->message == WM_SYSKEYUP)
+ {
+ switch (Msg->wParam)
+ {
+ case VK_LSHIFT: case VK_RSHIFT:
+ Msg->wParam = VK_SHIFT;
+ break;
+ case VK_LCONTROL: case VK_RCONTROL:
+ Msg->wParam = VK_CONTROL;
+ break;
+ case VK_LMENU: case VK_RMENU:
+ Msg->wParam = VK_MENU;
+ break;
+ }
+ }
+
+ Event.message = Msg->message;
+ Event.hwnd = Msg->hwnd;
+ Event.time = Msg->time;
+ Event.paramL = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8);
+ Event.paramH = Msg->lParam & 0x7FFF;
+ if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000;
+ co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
+
+ if (co_HOOK_CallHooks( WH_KEYBOARD,
+ *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
+ LOWORD(Msg->wParam),
+ Msg->lParam))
+ {
+ /* skip this message */
+ co_HOOK_CallHooks( WH_CBT,
+ HCBT_KEYSKIPPED,
+ LOWORD(Msg->wParam),
+ Msg->lParam );
+ ERR("KeyboardMessage WH_CBT Call Hook return!\n");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOL co_IntProcessHardwareMessage(MSG* Msg, BOOL* RemoveMessages, UINT first, UINT last)
+{
+ if ( IS_MOUSE_MESSAGE(Msg->message))
+ {
+ return co_IntProcessMouseMessage(Msg, RemoveMessages, first, last);
+ }
+ else if ( IS_KBD_MESSAGE(Msg->message))
+ {
+ return co_IntProcessKeyboardMessage(Msg, RemoveMessages);
+ }
+
+ return TRUE;
+}
+
+BOOL APIENTRY
+co_MsqPeekMouseMove(IN PTHREADINFO pti,
+ IN BOOL Remove,
+ IN PWND Window,
+ IN UINT MsgFilterLow,
+ IN UINT MsgFilterHigh,
+ OUT MSG* pMsg)
+{
+ BOOL AcceptMessage;
+ MSG msg;
+ PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
+
+ if(!(MessageQueue->MouseMoved))
+ return FALSE;
+
+ if (!MessageQueue->ptiSysLock)
+ {
+ MessageQueue->ptiSysLock = pti;
+ pti->pcti->CTI_flags |= CTI_THREADSYSLOCK;
+ }
+
+ if (MessageQueue->ptiSysLock != pti)
+ {
+ ERR("MsqPeekMouseMove: Thread Q is locked to another pti!\n");
+ return FALSE;
+ }
+
+ msg = MessageQueue->MouseMoveMsg;
+
+ AcceptMessage = co_IntProcessMouseMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh);
+
+ if(AcceptMessage)
+ *pMsg = msg;
+
+ if(Remove)
+ {
+ ClearMsgBitsMask(pti, QS_MOUSEMOVE);
+ MessageQueue->MouseMoved = FALSE;
+ }
+
+ MessageQueue->ptiSysLock = NULL;
+ pti->pcti->CTI_flags &= ~CTI_THREADSYSLOCK;
+ return AcceptMessage;
+}
+
+/* check whether a message filter contains at least one potential hardware message */
+static INT FASTCALL
+filter_contains_hw_range( UINT first, UINT last )
+{
+ /* hardware message ranges are (in numerical order):
+ * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
+ * WM_KEYFIRST .. WM_KEYLAST
+ * WM_MOUSEFIRST .. WM_MOUSELAST
+ */
+ if (!last) --last;
+ if (last < WM_NCMOUSEFIRST) return 0;
+ if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) return 0;
+ if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0;
+ if (first > WM_MOUSELAST) return 0;
+ return 1;
+}
+
+BOOL APIENTRY
+co_MsqPeekHardwareMessage(IN PTHREADINFO pti,
+ IN BOOL Remove,
+ IN PWND Window,
+ IN UINT MsgFilterLow,
+ IN UINT MsgFilterHigh,
+ IN UINT QSflags,
+ OUT MSG* pMsg)
+{
+
+ BOOL AcceptMessage;
+ PUSER_MESSAGE CurrentMessage;
+ PLIST_ENTRY ListHead, CurrentEntry = NULL;
+ MSG msg;
+ BOOL Ret = FALSE;
+ PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
+
+ if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE;
+
+ ListHead = &MessageQueue->HardwareMessagesListHead;
+ CurrentEntry = ListHead->Flink;
+
+ if (IsListEmpty(CurrentEntry)) return FALSE;
+
+ if (!MessageQueue->ptiSysLock)
+ {
+ MessageQueue->ptiSysLock = pti;
+ pti->pcti->CTI_flags |= CTI_THREADSYSLOCK;
+ }
+
+ if (MessageQueue->ptiSysLock != pti)
+ {
+ ERR("MsqPeekHardwareMessage: Thread Q is locked to another pti!\n");
+ return FALSE;
+ }
+
+ CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+ ListEntry);
+ do
+ {
+ if (IsListEmpty(CurrentEntry)) break;
+ if (!CurrentMessage) break;
+ CurrentEntry = CurrentMessage->ListEntry.Flink;
+ if (!CurrentEntry) break; //// Fix CORE-6734 reported crash.
+/*
+ MSDN:
+ 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
+ 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
+ 3: handle to the window whose messages are to be retrieved.
+ */
+ if ( ( !Window || // 1
+ ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
+ ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3
+ ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
+ ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
+ {
+ msg = CurrentMessage->Msg;
+
+ UpdateKeyStateFromMsg(MessageQueue, &msg);
+ AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh);
+
+ if (Remove)
+ {
+ RemoveEntryList(&CurrentMessage->ListEntry);
+ ClearMsgBitsMask(pti, CurrentMessage->QS_Flags);
+ MsqDestroyMessage(CurrentMessage);
+ }
+
+ if (AcceptMessage)
+ {
+ *pMsg = msg;
+ Ret = TRUE;
+ break;
+ }
+ }
+ CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
+ }
+ while(CurrentEntry != ListHead);
+
+ MessageQueue->ptiSysLock = NULL;
+ pti->pcti->CTI_flags &= ~CTI_THREADSYSLOCK;
+ return Ret;
+}
+
+BOOLEAN APIENTRY
+MsqPeekMessage(IN PTHREADINFO pti,
+ IN BOOLEAN Remove,
+ IN PWND Window,
+ IN UINT MsgFilterLow,
+ IN UINT MsgFilterHigh,
+ IN UINT QSflags,
+ OUT PMSG Message)
+{
+ PLIST_ENTRY CurrentEntry;
+ PUSER_MESSAGE CurrentMessage;
+ PLIST_ENTRY ListHead;
+ BOOL Ret = FALSE;
+
+ CurrentEntry = pti->PostedMessagesListHead.Flink;
+ ListHead = &pti->PostedMessagesListHead;
+
+ if (IsListEmpty(CurrentEntry)) return FALSE;
+
+ CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+ ListEntry);
+ do
+ {
+ if (IsListEmpty(CurrentEntry)) break;
+ if (!CurrentMessage) break;
+ CurrentEntry = CurrentEntry->Flink;
+/*
+ MSDN:
+ 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
+ 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
+ 3: handle to the window whose messages are to be retrieved.
+ */
+ if ( ( !Window || // 1
+ ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
+ ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3
+ ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
+ ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
+ {
+ *Message = CurrentMessage->Msg;
+
+ if (Remove)
+ {
+ RemoveEntryList(&CurrentMessage->ListEntry);
+ ClearMsgBitsMask(pti, CurrentMessage->QS_Flags);
+ MsqDestroyMessage(CurrentMessage);
+ }
+ Ret = TRUE;
+ break;
+ }
+ CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+ ListEntry);
+ }
+ while (CurrentEntry != ListHead);
+
+ return Ret;
+}
+
+NTSTATUS FASTCALL
+co_MsqWaitForNewMessages(PTHREADINFO pti, PWND WndFilter,
+ UINT MsgFilterMin, UINT MsgFilterMax)
+{
+ NTSTATUS ret;
+ UserLeaveCo();
+ ret = KeWaitForSingleObject( pti->pEventQueueServer,
+ UserRequest,
+ UserMode,
+ FALSE,
+ NULL );
+ UserEnterCo();
+ return ret;
+}
+
+BOOL FASTCALL
+MsqIsHung(PTHREADINFO pti)
+{
+ LARGE_INTEGER LargeTickCount;
+
+ KeQueryTickCount(&LargeTickCount);
+ return ((LargeTickCount.u.LowPart - pti->timeLast) > MSQ_HUNG);
+}
+
+VOID
+CALLBACK
+HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ DoTheScreenSaver();
+ TRACE("HungAppSysTimerProc\n");
+ // Process list of windows that are hung and waiting.
+}
+
+BOOLEAN FASTCALL
+MsqInitializeMessageQueue(PTHREADINFO pti, PUSER_MESSAGE_QUEUE MessageQueue)
+{
+ MessageQueue->CaretInfo = (PTHRDCARETINFO)(MessageQueue + 1);
+ InitializeListHead(&MessageQueue->HardwareMessagesListHead); // Keep here!
+ MessageQueue->spwndFocus = NULL;
+ MessageQueue->iCursorLevel = 0;
+ MessageQueue->CursorObject = NULL;
+ RtlCopyMemory(MessageQueue->afKeyState, gafAsyncKeyState, sizeof(gafAsyncKeyState));
+ MessageQueue->ptiMouse = pti;
+ MessageQueue->ptiKeyboard = pti;
+ MessageQueue->cThreads++;
+
+ return TRUE;
+}
+
+VOID FASTCALL
+MsqCleanupThreadMsgs(PTHREADINFO pti)
+{
+ PLIST_ENTRY CurrentEntry;
+ PUSER_MESSAGE CurrentMessage;
+ PUSER_SENT_MESSAGE CurrentSentMessage;
+
+ /* cleanup posted messages */
+ while (!IsListEmpty(&pti->PostedMessagesListHead))
+ {
+ CurrentEntry = RemoveHeadList(&pti->PostedMessagesListHead);
+ CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+ ListEntry);
+ MsqDestroyMessage(CurrentMessage);
+ }
+
+ /* remove the messages that have not yet been dispatched */
+ while (!IsListEmpty(&pti->SentMessagesListHead))
+ {
+ CurrentEntry = RemoveHeadList(&pti->SentMessagesListHead);
+ CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
+ ListEntry);
+
+ TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
+ /* Only if the message has a sender was the message in the DispatchingList */
+ if ((CurrentSentMessage->ptiSender)
+ && (CurrentSentMessage->DispatchingListEntry.Flink != NULL))
+ {
+ RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
+ }
+
+ /* wake the sender's thread */
+ if (CurrentSentMessage->CompletionEvent != NULL)
+ {
+ KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
+ }
+
- if (CurrentSentMessage->HasPackedLParam == TRUE)
++ if (CurrentSentMessage->HasPackedLParam)
+ {
+ if (CurrentSentMessage->Msg.lParam)
+ ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
+ }
+
+ /* free the message */
+ ExFreePool(CurrentSentMessage);
+ }
+
+ /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
+ ExitThread() was called in a SendMessage() umode callback */
+ while (!IsListEmpty(&pti->LocalDispatchingMessagesHead))
+ {
+ CurrentEntry = RemoveHeadList(&pti->LocalDispatchingMessagesHead);
+ CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
+ ListEntry);
+
+ /* remove the message from the dispatching list */
+ if(CurrentSentMessage->DispatchingListEntry.Flink != NULL)
+ {
+ RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
+ }
+
+ TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
+
+ /* wake the sender's thread */
+ if (CurrentSentMessage->CompletionEvent != NULL)
+ {
+ KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
+ }
+
++ if (CurrentSentMessage->HasPackedLParam)
+ {
+ if (CurrentSentMessage->Msg.lParam)
+ ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
+ }
+
+ /* free the message */
+ ExFreePool(CurrentSentMessage);
+ }
+
+ /* tell other threads not to bother returning any info to us */
+ while (! IsListEmpty(&pti->DispatchingMessagesHead))
+ {
+ CurrentEntry = RemoveHeadList(&pti->DispatchingMessagesHead);
+ CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
+ DispatchingListEntry);
+ CurrentSentMessage->CompletionEvent = NULL;
+ CurrentSentMessage->Result = NULL;
+
+ /* do NOT dereference our message queue as it might get attempted to be
+ locked later */
+ }
+
+ // Clear it all out.
+ if (pti->pcti)
+ {
+ pti->pcti->fsWakeBits = 0;
+ pti->pcti->fsChangeBits = 0;
+ }
+
+ pti->nCntsQBits[QSRosKey] = 0;
+ pti->nCntsQBits[QSRosMouseMove] = 0;
+ pti->nCntsQBits[QSRosMouseButton] = 0;
+ pti->nCntsQBits[QSRosPostMessage] = 0;
+ pti->nCntsQBits[QSRosSendMessage] = 0;
+ pti->nCntsQBits[QSRosHotKey] = 0;
+ pti->nCntsQBits[QSRosEvent] = 0;
+}
+
+VOID FASTCALL
+MsqCleanupMessageQueue(PTHREADINFO pti)
+{
+ PUSER_MESSAGE_QUEUE MessageQueue;
+
+ MessageQueue = pti->MessageQueue;
+ MessageQueue->cThreads--;
+
+ if (MessageQueue->cThreads)
+ {
+ if (MessageQueue->ptiSysLock == pti) MessageQueue->ptiSysLock = NULL;
+ }
+
+ if (MessageQueue->CursorObject)
+ {
+ PCURICON_OBJECT pCursor = MessageQueue->CursorObject;
+
+ /* Change to another cursor if we going to dereference current one
+ Note: we can't use UserSetCursor because it uses current thread
+ message queue instead of queue given for cleanup */
+ if (IntGetSysCursorInfo()->CurrentCursorObject == pCursor)
+ {
+ HDC hdcScreen;
+
+ /* Get the screen DC */
+ hdcScreen = IntGetScreenDC();
+ if (hdcScreen)
+ GreMovePointer(hdcScreen, -1, -1);
+ IntGetSysCursorInfo()->CurrentCursorObject = NULL;
+ }
+
+ TRACE("DereferenceObject pCursor\n");
+ UserDereferenceObject(pCursor);
+ }
+
+ if (gpqForeground == MessageQueue)
+ {
+ IntSetFocusMessageQueue(NULL);
+ }
+ if (gpqForegroundPrev == MessageQueue)
+ {
+ gpqForegroundPrev = NULL;
+ }
+ if (gpqCursor == MessageQueue)
+ {
+ gpqCursor = NULL;
+ }
+}
+
+PUSER_MESSAGE_QUEUE FASTCALL
+MsqCreateMessageQueue(PTHREADINFO pti)
+{
+ PUSER_MESSAGE_QUEUE MessageQueue;
+
+ MessageQueue = (PUSER_MESSAGE_QUEUE)ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO),
+ USERTAG_Q);
+
+ if (!MessageQueue)
+ {
+ return NULL;
+ }
+
+ RtlZeroMemory(MessageQueue, sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO));
+ /* hold at least one reference until it'll be destroyed */
+ IntReferenceMessageQueue(MessageQueue);
+ /* initialize the queue */
+ if (!MsqInitializeMessageQueue(pti, MessageQueue))
+ {
+ IntDereferenceMessageQueue(MessageQueue);
+ return NULL;
+ }
+
+ return MessageQueue;
+}
+
+VOID FASTCALL
+MsqDestroyMessageQueue(PTHREADINFO pti)
+{
+ PDESKTOP desk;
+ PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
+
+ MessageQueue->QF_flags |= QF_INDESTROY;
+
+ /* remove the message queue from any desktops */
+ if ((desk = InterlockedExchangePointer((PVOID*)&MessageQueue->Desktop, 0)))
+ {
+ (void)InterlockedExchangePointer((PVOID*)&desk->ActiveMessageQueue, 0);
+ IntDereferenceMessageQueue(MessageQueue);
+ }
+
+ /* clean it up */
+ MsqCleanupMessageQueue(pti);
+
+ /* decrease the reference counter, if it hits zero, the queue will be freed */
+ IntDereferenceMessageQueue(MessageQueue);
+}
+
+LPARAM FASTCALL
+MsqSetMessageExtraInfo(LPARAM lParam)
+{
+ LPARAM Ret;
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+
+ pti = PsGetCurrentThreadWin32Thread();
+ MessageQueue = pti->MessageQueue;
+ if(!MessageQueue)
+ {
+ return 0;
+ }
+
+ Ret = MessageQueue->ExtraInfo;
+ MessageQueue->ExtraInfo = lParam;
+
+ return Ret;
+}
+
+LPARAM FASTCALL
+MsqGetMessageExtraInfo(VOID)
+{
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+
+ pti = PsGetCurrentThreadWin32Thread();
+ MessageQueue = pti->MessageQueue;
+ if(!MessageQueue)
+ {
+ return 0;
+ }
+
+ return MessageQueue->ExtraInfo;
+}
+
+// ReplyMessage is called by the thread receiving the window message.
+BOOL FASTCALL
+co_MsqReplyMessage( LRESULT lResult )
+{
+ PUSER_SENT_MESSAGE Message;
+ PTHREADINFO pti;
+
+ pti = PsGetCurrentThreadWin32Thread();
+ Message = pti->pusmCurrent;
+
+ if (!Message) return FALSE;
+
+ if (Message->QS_Flags & QS_SMRESULT) return FALSE;
+
+ // SendMessageXxx || Callback msg and not a notify msg
+ if (Message->ptiSender || Message->CompletionCallback)
+ {
+ Message->lResult = lResult;
+ Message->QS_Flags |= QS_SMRESULT;
+ // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
+ }
+ return TRUE;
+}
+
+HWND FASTCALL
+MsqSetStateWindow(PTHREADINFO pti, ULONG Type, HWND hWnd)
+{
+ HWND Prev;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+
+ MessageQueue = pti->MessageQueue;
+
+ switch(Type)
+ {
+ case MSQ_STATE_CAPTURE:
+ Prev = MessageQueue->spwndCapture ? UserHMGetHandle(MessageQueue->spwndCapture) : 0;
+ MessageQueue->spwndCapture = ValidateHwndNoErr(hWnd);
+ return Prev;
+ case MSQ_STATE_ACTIVE:
+ Prev = MessageQueue->spwndActive ? UserHMGetHandle(MessageQueue->spwndActive) : 0;
+ MessageQueue->spwndActive = ValidateHwndNoErr(hWnd);
+ return Prev;
+ case MSQ_STATE_FOCUS:
+ Prev = MessageQueue->spwndFocus ? UserHMGetHandle(MessageQueue->spwndFocus) : 0;
+ MessageQueue->spwndFocus = ValidateHwndNoErr(hWnd);
+ return Prev;
+ case MSQ_STATE_MENUOWNER:
+ Prev = MessageQueue->MenuOwner;
+ MessageQueue->MenuOwner = hWnd;
+ return Prev;
+ case MSQ_STATE_MOVESIZE:
+ Prev = MessageQueue->MoveSize;
+ MessageQueue->MoveSize = hWnd;
+ return Prev;
+ case MSQ_STATE_CARET:
+ ASSERT(MessageQueue->CaretInfo);
+ Prev = MessageQueue->CaretInfo->hWnd;
+ MessageQueue->CaretInfo->hWnd = hWnd;
+ return Prev;
+ }
+
+ return NULL;
+}
+
+SHORT
+APIENTRY
+NtUserGetKeyState(INT key)
+{
+ DWORD Ret;
+
+ UserEnterShared();
+
+ Ret = UserGetKeyState(key);
+
+ UserLeave();
+
+ return (SHORT)Ret;
+}
+
+
+DWORD
+APIENTRY
+NtUserGetKeyboardState(LPBYTE lpKeyState)
+{
+ DWORD i, ret = TRUE;
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+
+ UserEnterShared();
+
+ pti = PsGetCurrentThreadWin32Thread();
+ MessageQueue = pti->MessageQueue;
+
+ _SEH2_TRY
+ {
+ /* Probe and copy key state to an array */
+ ProbeForWrite(lpKeyState, 256 * sizeof(BYTE), 1);
+ for (i = 0; i < 256; ++i)
+ {
+ lpKeyState[i] = 0;
+ if (IS_KEY_DOWN(MessageQueue->afKeyState, i))
+ lpKeyState[i] |= KS_DOWN_BIT;
+ if (IS_KEY_LOCKED(MessageQueue->afKeyState, i))
+ lpKeyState[i] |= KS_LOCK_BIT;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ ret = FALSE;
+ }
+ _SEH2_END;
+
+ UserLeave();
+
+ return ret;
+}
+
+BOOL
+APIENTRY
+NtUserSetKeyboardState(LPBYTE pKeyState)
+{
+ UINT i;
+ BOOL bRet = TRUE;
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+
+ UserEnterExclusive();
+
+ pti = PsGetCurrentThreadWin32Thread();
+ MessageQueue = pti->MessageQueue;
+
+ _SEH2_TRY
+ {
+ ProbeForRead(pKeyState, 256 * sizeof(BYTE), 1);
+ for (i = 0; i < 256; ++i)
+ {
+ SET_KEY_DOWN(MessageQueue->afKeyState, i, pKeyState[i] & KS_DOWN_BIT);
+ SET_KEY_LOCKED(MessageQueue->afKeyState, i, pKeyState[i] & KS_LOCK_BIT);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ bRet = FALSE;
+ }
+ _SEH2_END;
+
+ UserLeave();
+
+ return bRet;
+}
+
+/* EOF */
--- /dev/null
- if (wParam == TRUE)
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: dll/win32/user32/controls/appswitch.c
+ * PURPOSE: app switching functionality
+ * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
+ * David Quintana (gigaherz@gmail.com)
+ */
+
+#include <user32.h>
+
+#include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(user32);
+
+// limit the number of windows shown in the alt-tab window
+// 120 windows results in (12*40) by (10*40) pixels worth of icons.
+#define MAX_WINDOWS 120
+
+// Global variables
+HWND switchdialog = NULL;
+HFONT dialogFont;
+int selectedWindow = 0;
+BOOL isOpen = FALSE;
+
+int fontHeight=0;
+
+WCHAR windowText[1024];
+
+HWND windowList[MAX_WINDOWS];
+HICON iconList[MAX_WINDOWS];
+int windowCount = 0;
+
+int cxBorder, cyBorder;
+int nItems, nCols, nRows;
+int itemsW, itemsH;
+int totalW, totalH;
+int xOffset, yOffset;
+POINT pt;
+
+void ResizeAndCenter(HWND hwnd, int width, int height)
+{
+ int screenwidth = GetSystemMetrics(SM_CXSCREEN);
+ int screenheight = GetSystemMetrics(SM_CYSCREEN);
+
+ pt.x = (screenwidth - width) / 2;
+ pt.y = (screenheight - height) / 2;
+
+ MoveWindow(hwnd, pt.x, pt.y, width, height, FALSE);
+}
+
+void MakeWindowActive(HWND hwnd)
+{
+ WINDOWPLACEMENT wpl;
+
+ wpl.length = sizeof(WINDOWPLACEMENT);
+ GetWindowPlacement(hwnd, &wpl);
+
+ TRACE("GetWindowPlacement wpl.showCmd %d\n",wpl.showCmd);
+ if (wpl.showCmd == SW_SHOWMINIMIZED)
+ ShowWindowAsync(hwnd, SW_RESTORE);
+
+ BringWindowToTop(hwnd); // same as: SetWindowPos(hwnd,HWND_TOP,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); ?
+ SetForegroundWindow(hwnd);
+}
+
+void CompleteSwitch(BOOL doSwitch)
+{
+ if (!isOpen)
+ return;
+
+ isOpen = FALSE;
+
+ TRACE("[ATbot] CompleteSwitch Hiding Window.\n");
+ ShowWindow(switchdialog, SW_HIDE);
+
+ if(doSwitch)
+ {
+ if(selectedWindow >= windowCount)
+ return;
+
+ // FIXME: workaround because reactos fails to activate the previous window correctly.
+ //if(selectedWindow != 0)
+ {
+ HWND hwnd = windowList[selectedWindow];
+
+ GetWindowTextW(hwnd, windowText, _countof(windowText));
+
+ TRACE("[ATbot] CompleteSwitch Switching to 0x%08x (%ls)\n", hwnd, windowText);
+
+ MakeWindowActive(hwnd);
+ }
+ }
+
+ windowCount = 0;
+}
+
+BOOL CALLBACK EnumerateCallback(HWND window, LPARAM lParam)
+{
+ HICON hIcon;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if (!IsWindowVisible(window))
+ return TRUE;
+
+ GetClassNameW(window, windowText, _countof(windowText));
+ if ((wcscmp(L"Shell_TrayWnd", windowText)==0) ||
+ (wcscmp(L"Progman", windowText)==0) )
+ return TRUE;
+
+ // First try to get the big icon assigned to the window
+ hIcon = (HICON)SendMessageW(window, WM_GETICON, ICON_BIG, 0);
+ if (!hIcon)
+ {
+ // If no icon is assigned, try to get the icon assigned to the windows' class
+ hIcon = (HICON)GetClassLongPtrW(window, GCL_HICON);
+ if (!hIcon)
+ {
+ // If we still don't have an icon, see if we can do with the small icon,
+ // or a default application icon
+ hIcon = (HICON)SendMessageW(window, WM_GETICON, ICON_SMALL2, 0);
+ if (!hIcon)
+ {
+ // If all fails, give up and continue with the next window
+ return TRUE;
+ }
+ }
+ }
+
+ windowList[windowCount] = window;
+ iconList[windowCount] = CopyIcon(hIcon);
+
+ windowCount++;
+
+ // If we got to the max number of windows,
+ // we won't be able to add any more
+ if(windowCount == MAX_WINDOWS)
+ return FALSE;
+
+ return TRUE;
+}
+
+// Function mostly compatible with the normal EnumWindows,
+// except it lists in Z-Order and it doesn't ensure consistency
+// if a window is removed while enumerating
+void EnumWindowsZOrder(WNDENUMPROC callback, LPARAM lParam)
+{
+ HWND next = GetTopWindow(NULL);
+ while (next != NULL)
+ {
+ if(!callback(next, lParam))
+ break;
+ next = GetWindow(next, GW_HWNDNEXT);
+ }
+}
+
+void ProcessMouseMessage(UINT message, LPARAM lParam)
+{
+ int xPos = LOWORD(lParam);
+ int yPos = HIWORD(lParam);
+
+ int xIndex = (xPos - xOffset)/40;
+ int xOff = (xPos - xOffset)%40;
+
+ int yIndex = (yPos - yOffset)/40;
+ int yOff = (yPos - yOffset)%40;
+
+ if(xOff > 32 || xIndex > nItems)
+ return;
+
+ if(yOff > 32 || yIndex > nRows)
+ return;
+
+ selectedWindow = (yIndex*nCols) + xIndex;
+ if (message == WM_MOUSEMOVE)
+ {
+ InvalidateRect(switchdialog, NULL, TRUE);
+ //RedrawWindow(switchdialog, NULL, NULL, 0);
+ }
+ else
+ {
+ selectedWindow = (yIndex*nCols) + xIndex;
+ CompleteSwitch(TRUE);
+ }
+}
+
+void OnPaint(HWND hWnd)
+{
+ HDC dialogDC;
+ PAINTSTRUCT paint;
+ RECT cRC, textRC;
+ int i;
+ HBRUSH hBrush;
+ HPEN hPen;
+ HFONT dcFont;
+ COLORREF cr;
+ int nch = GetWindowTextW(windowList[selectedWindow], windowText, _countof(windowText));
+
+ dialogDC = BeginPaint(hWnd, &paint);
+ {
+ GetClientRect(hWnd, &cRC);
+ FillRect(dialogDC, &cRC, GetSysColorBrush(COLOR_MENU));
+
+ for(i=0; i< windowCount; i++)
+ {
+ HICON hIcon = iconList[i];
+
+ int xpos = xOffset + 40 * (i % nCols);
+ int ypos = yOffset + 40 * (i / nCols);
+
+ if (selectedWindow == i)
+ {
+ hBrush = GetSysColorBrush(COLOR_HIGHLIGHT);
+ }
+ else
+ {
+ hBrush = GetSysColorBrush(COLOR_MENU);
+ }
+#if TRUE
+ cr = GetSysColor(COLOR_BTNTEXT); // doesn't look right! >_<
+ hPen = CreatePen(PS_DOT, 1, cr);
+ SelectObject(dialogDC, hPen);
+ SelectObject(dialogDC, hBrush);
+ Rectangle(dialogDC, xpos-2, ypos-2, xpos+32+2, ypos+32+2);
+ DeleteObject(hPen);
+ // Must NOT destroy the system brush!
+#else
+ RECT rc = { xpos-2, ypos-2, xpos+32+2, ypos+32+2 };
+ FillRect(dialogDC, &rc, hBrush);
+#endif
+ DrawIcon(dialogDC, xpos, ypos, hIcon);
+ }
+
+ dcFont = SelectObject(dialogDC, dialogFont);
+ SetTextColor(dialogDC, GetSysColor(COLOR_BTNTEXT));
+ SetBkColor(dialogDC, GetSysColor(COLOR_BTNFACE));
+
+ textRC.top = itemsH;
+ textRC.left = 8;
+ textRC.right = totalW - 8;
+ textRC.bottom = totalH - 8;
+ DrawTextW(dialogDC, windowText, nch, &textRC, DT_CENTER|DT_END_ELLIPSIS);
+ SelectObject(dialogDC, dcFont);
+ }
+ EndPaint(hWnd, &paint);
+}
+
+DWORD CreateSwitcherWindow(HINSTANCE hInstance)
+{
+ switchdialog = CreateWindowExW( WS_EX_TOPMOST|WS_EX_DLGMODALFRAME|WS_EX_TOOLWINDOW,
+ WC_SWITCH,
+ L"",
+ WS_POPUP|WS_BORDER|WS_DISABLED,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ 400, 150,
+ NULL, NULL,
+ hInstance, NULL);
+ if (!switchdialog)
+ {
+ TRACE("[ATbot] Task Switcher Window failed to create.\n");
+ return 0;
+ }
+
+ isOpen = FALSE;
+ return 1;
+}
+
+DWORD GetDialogFont()
+{
+ HDC tDC;
+ TEXTMETRIC tm;
+
+ dialogFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+
+ tDC = GetDC(0);
+ GetTextMetrics(tDC, &tm);
+ fontHeight = tm.tmHeight;
+ ReleaseDC(0, tDC);
+
+ return 1;
+}
+
+void PrepareWindow()
+{
+ cxBorder = GetSystemMetrics(SM_CXBORDER);
+ cyBorder = GetSystemMetrics(SM_CYBORDER);
+
+ nItems = windowCount;
+ nCols = min(max(nItems,8),12);
+ nRows = (nItems+nCols-1)/nCols;
+
+ itemsW = nCols*32 + (nCols+1)*8;
+ itemsH = nRows*32 + (nRows+1)*8;
+
+ totalW = itemsW + 2*cxBorder + 4;
+ totalH = itemsH + 2*cyBorder + fontHeight + 8; // give extra pixels for the window title
+
+ xOffset = 8;
+ yOffset = 8;
+
+ if (nItems < nCols)
+ {
+ int w2 = nItems*32 + (nItems-1)*8;
+ xOffset = (itemsW-w2)/2;
+ }
+ ResizeAndCenter(switchdialog, totalW, totalH);
+}
+
+void ProcessHotKey()
+{
+ if (!isOpen)
+ {
+ windowCount=0;
+ EnumWindowsZOrder(EnumerateCallback, 0);
+
+ if (windowCount < 2)
+ return;
+
+ selectedWindow = 1;
+
+ TRACE("[ATbot] HotKey Received. Opening window.\n");
+ ShowWindow(switchdialog, SW_SHOWNORMAL);
+ MakeWindowActive(switchdialog);
+ isOpen = TRUE;
+ }
+ else
+ {
+ TRACE("[ATbot] HotKey Received Rotating.\n");
+ selectedWindow = (selectedWindow + 1)%windowCount;
+ InvalidateRect(switchdialog, NULL, TRUE);
+ }
+}
+
+LRESULT WINAPI DoAppSwitch( WPARAM wParam, LPARAM lParam )
+{
+ HWND hwnd, hwndActive;
+ MSG msg;
+ BOOL Esc = FALSE;
+ INT Count = 0;
+ WCHAR Text[1024];
+
+ // Already in the loop.
+ if (switchdialog) return 0;
+
+ hwndActive = GetActiveWindow();
+ // Nothing is active so exit.
+ if (!hwndActive) return 0;
+ // Capture current active window.
+ SetCapture( hwndActive );
+
+ switch (lParam)
+ {
+ case VK_TAB:
+ if( !CreateSwitcherWindow(User32Instance) ) goto Exit;
+ if( !GetDialogFont() ) goto Exit;
+ ProcessHotKey();
+ break;
+
+ case VK_ESCAPE:
+ windowCount = 0;
+ Count = 0;
+ EnumWindowsZOrder(EnumerateCallback, 0);
+ if (windowCount < 2) goto Exit;
+ if (wParam == SC_NEXTWINDOW)
+ Count = 1;
+ else
+ {
+ if (windowCount == 2)
+ Count = 0;
+ else
+ Count = windowCount - 1;
+ }
+ TRACE("DoAppSwitch VK_ESCAPE 1 Count %d windowCount %d\n",Count,windowCount);
+ hwnd = windowList[Count];
+ GetWindowTextW(hwnd, Text, _countof(Text));
+ TRACE("[ATbot] Switching to 0x%08x (%ls)\n", hwnd, Text);
+ MakeWindowActive(hwnd);
+ Esc = TRUE;
+ break;
+
+ default:
+ goto Exit;
+ }
+ // Main message loop:
+ while (1)
+ {
+ for (;;)
+ {
+ if (PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ))
+ {
+ if (!CallMsgFilterW( &msg, MSGF_NEXTWINDOW )) break;
+ /* remove the message from the queue */
+ PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
+ }
+ else
+ WaitMessage();
+ }
+
+ switch (msg.message)
+ {
+ case WM_KEYUP:
+ {
+ PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
+ if (msg.wParam == VK_MENU)
+ {
+ CompleteSwitch(TRUE);
+ }
+ else if (msg.wParam == VK_RETURN)
+ {
+ CompleteSwitch(TRUE);
+ }
+ else if (msg.wParam == VK_ESCAPE)
+ {
+ TRACE("DoAppSwitch VK_ESCAPE 2\n");
+ CompleteSwitch(FALSE);
+ }
+ goto Exit; //break;
+ }
+
+ case WM_SYSKEYDOWN:
+ {
+ PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
+ if (HIWORD(msg.lParam) & KF_ALTDOWN)
+ {
+ INT Shift;
+ if ( msg.wParam == VK_TAB )
+ {
+ if (Esc) break;
+ Shift = GetKeyState(VK_SHIFT) & 0x8000 ? SC_PREVWINDOW : SC_NEXTWINDOW;
+ if (Shift == SC_NEXTWINDOW)
+ {
+ selectedWindow = (selectedWindow + 1)%windowCount;
+ }
+ else
+ {
+ selectedWindow = selectedWindow - 1;
+ if (selectedWindow < 0)
+ selectedWindow = windowCount - 1;
+ }
+ InvalidateRect(switchdialog, NULL, TRUE);
+ }
+ else if ( msg.wParam == VK_ESCAPE )
+ {
+ if (!Esc) break;
+ if (windowCount < 2)
+ goto Exit;
+ if (wParam == SC_NEXTWINDOW)
+ {
+ Count = (Count + 1)%windowCount;
+ }
+ else
+ {
+ Count--;
+ if (Count < 0)
+ Count = windowCount - 1;
+ }
+ hwnd = windowList[Count];
+ GetWindowTextW(hwnd, Text, _countof(Text));
+ MakeWindowActive(hwnd);
+ }
+ }
+ break;
+ }
+
+ case WM_LBUTTONUP:
+ PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
+ ProcessMouseMessage(msg.message, msg.lParam);
+ goto Exit;
+
+ default:
+ if (PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ))
+ {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+ break;
+ }
+ }
+Exit:
+ ReleaseCapture();
+ if (switchdialog) DestroyWindow(switchdialog);
+ switchdialog = NULL;
+ selectedWindow = 0;
+ windowCount = 0;
+ return 0;
+}
+
+VOID
+DestroyAppWindows()
+{
+ INT i;
+ for (i=0; i< windowCount; i++)
+ {
+ HICON hIcon = iconList[i];
+ DestroyIcon(hIcon);
+ }
+}
+
+//
+// Switch System Class Window Proc.
+//
+LRESULT WINAPI SwitchWndProc_common(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL unicode )
+{
+ PWND pWnd;
+ PALTTABINFO ati;
+ pWnd = ValidateHwnd(hWnd);
+ if (pWnd)
+ {
+ if (!pWnd->fnid)
+ {
+ NtUserSetWindowFNID(hWnd, FNID_SWITCH);
+ }
+ }
+
+ switch (uMsg)
+ {
+ case WM_NCCREATE:
+ if (!(ati = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ati))))
+ return 0;
+ SetWindowLongPtrW( hWnd, 0, (LONG_PTR)ati );
+ return TRUE;
+
+ case WM_SHOWWINDOW:
++ if (wParam)
+ {
+ PrepareWindow();
+ ati = (PALTTABINFO)GetWindowLongPtrW(hWnd, 0);
+ ati->cItems = nItems;
+ ati->cxItem = ati->cyItem = 43;
+ ati->cRows = nRows;
+ ati->cColumns = nCols;
+ }
+ return 0;
+
+ case WM_MOUSEMOVE:
+ ProcessMouseMessage(uMsg, lParam);
+ return 0;
+
+ case WM_ACTIVATE:
+ if (wParam == WA_INACTIVE)
+ {
+ CompleteSwitch(FALSE);
+ }
+ return 0;
+
+ case WM_PAINT:
+ OnPaint(hWnd);
+ return 0;
+
+ case WM_DESTROY:
+ isOpen = FALSE;
+ ati = (PALTTABINFO)GetWindowLongPtrW(hWnd, 0);
+ HeapFree( GetProcessHeap(), 0, ati );
+ SetWindowLongPtrW( hWnd, 0, 0 );
+ DestroyAppWindows();
+ NtUserSetWindowFNID(hWnd, FNID_DESTROY);
+ return 0;
+ }
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+}
+
+LRESULT WINAPI SwitchWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ return SwitchWndProc_common(hWnd, uMsg, wParam, lParam, FALSE);
+}
+
+LRESULT WINAPI SwitchWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ return SwitchWndProc_common(hWnd, uMsg, wParam, lParam, TRUE);
+}
--- /dev/null
- if( fInherit == TRUE )
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS user32.dll
+ * FILE: lib/user32/misc/desktop.c
+ * PURPOSE: Desktops
+ * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * UPDATE HISTORY:
+ * 06-06-2001 CSH Created
+ */
+
+#include <user32.h>
+
+#include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(user32);
+
+/*********************************************************************
+ * desktop class descriptor
+ */
+#if 0 // Kept for referencing.
+const struct builtin_class_descr DESKTOP_builtin_class =
+{
+ WC_DESKTOP, /* name */
+ CS_DBLCLKS, /* style */
+ NULL, /* procA (winproc is Unicode only) */
+ DesktopWndProc, /* procW */
+ 0, /* extra */
+ IDC_ARROW, /* cursor */
+ (HBRUSH)(COLOR_BACKGROUND+1) /* brush */
+};
+#endif
+
+LRESULT
+WINAPI
+DesktopWndProcW(HWND Wnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ TRACE("Desktop W Class Atom! hWnd 0x%x, Msg %d\n", Wnd, Msg);
+
+ switch(Msg)
+ {
+ case WM_ERASEBKGND:
+ case WM_NCCREATE:
+ case WM_CREATE:
+ case WM_CLOSE:
+ case WM_DISPLAYCHANGE:
+ case WM_PAINT:
+ case WM_SYSCOLORCHANGE:
+ {
+ LRESULT lResult;
+ NtUserMessageCall( Wnd, Msg, wParam, lParam, (ULONG_PTR)&lResult, FNID_DESKTOP, FALSE);
+ TRACE("Desktop lResult %d\n", lResult);
+ return lResult;
+ }
+
+ case WM_PALETTECHANGED:
+ if (Wnd == (HWND)wParam) break;
+ case WM_QUERYNEWPALETTE:
+ {
+ HDC hdc = GetWindowDC( Wnd );
+ PaintDesktop(hdc);
+ ReleaseDC( Wnd, hdc );
+ break;
+ }
+
+ case WM_SETCURSOR:
+ return (LRESULT)SetCursor(LoadCursorW(0, (LPCWSTR)IDC_ARROW));
+
+ default:
+ return DefWindowProcW(Wnd, Msg, wParam, lParam);
+ }
+ return 0;
+}
+
+VOID
+WINAPI
+LogFontA2W(LPLOGFONTW pW, CONST LOGFONTA *pA)
+{
+#define COPYS(f,len) MultiByteToWideChar ( CP_THREAD_ACP, 0, pA->f, len, pW->f, len )
+#define COPYN(f) pW->f = pA->f
+
+ COPYN(lfHeight);
+ COPYN(lfWidth);
+ COPYN(lfEscapement);
+ COPYN(lfOrientation);
+ COPYN(lfWeight);
+ COPYN(lfItalic);
+ COPYN(lfUnderline);
+ COPYN(lfStrikeOut);
+ COPYN(lfCharSet);
+ COPYN(lfOutPrecision);
+ COPYN(lfClipPrecision);
+ COPYN(lfQuality);
+ COPYN(lfPitchAndFamily);
+ COPYS(lfFaceName,LF_FACESIZE);
+
+#undef COPYN
+#undef COPYS
+}
+
+VOID
+WINAPI
+LogFontW2A(LPLOGFONTA pA, CONST LOGFONTW *pW)
+{
+#define COPYS(f,len) WideCharToMultiByte ( CP_THREAD_ACP, 0, pW->f, len, pA->f, len, NULL, NULL )
+#define COPYN(f) pA->f = pW->f
+
+ COPYN(lfHeight);
+ COPYN(lfWidth);
+ COPYN(lfEscapement);
+ COPYN(lfOrientation);
+ COPYN(lfWeight);
+ COPYN(lfItalic);
+ COPYN(lfUnderline);
+ COPYN(lfStrikeOut);
+ COPYN(lfCharSet);
+ COPYN(lfOutPrecision);
+ COPYN(lfClipPrecision);
+ COPYN(lfQuality);
+ COPYN(lfPitchAndFamily);
+ COPYS(lfFaceName,LF_FACESIZE);
+
+#undef COPYN
+#undef COPYS
+}
+
+int WINAPI
+RealGetSystemMetrics(int nIndex)
+{
+ //GetConnected();
+ //FIXME("Global Server Data -> %x\n",gpsi);
+ if (nIndex < 0 || nIndex >= SM_CMETRICS) return 0;
+ return gpsi->aiSysMet[nIndex];
+}
+
+/*
+ * @implemented
+ */
+int WINAPI
+GetSystemMetrics(int nIndex)
+{
+ BOOL Hook;
+ int Ret = 0;
+
+ if (!gpsi) // Fixme! Hax! Need Timos delay load support?
+ {
+ return RealGetSystemMetrics(nIndex);
+ }
+
+ LoadUserApiHook();
+
+ Hook = BeginIfHookedUserApiHook();
+
+ /* Bypass SEH and go direct. */
+ if (!Hook) return RealGetSystemMetrics(nIndex);
+
+ _SEH2_TRY
+ {
+ Ret = guah.GetSystemMetrics(nIndex);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ _SEH2_END;
+
+ EndUserApiHook();
+
+ return Ret;
+}
+
+/*
+ * @unimplemented
+ */
+BOOL WINAPI SetDeskWallpaper(LPCSTR filename)
+{
+ return SystemParametersInfoA(SPI_SETDESKWALLPAPER,0,(PVOID)filename,TRUE);
+}
+
+BOOL WINAPI
+RealSystemParametersInfoA(UINT uiAction,
+ UINT uiParam,
+ PVOID pvParam,
+ UINT fWinIni)
+{
+ switch (uiAction)
+ {
+
+ case SPI_GETNONCLIENTMETRICS:
+ {
+ LPNONCLIENTMETRICSA pnclma = (LPNONCLIENTMETRICSA)pvParam;
+ NONCLIENTMETRICSW nclmw;
+ if(pnclma->cbSize != sizeof(NONCLIENTMETRICSA))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ nclmw.cbSize = sizeof(NONCLIENTMETRICSW);
+
+ if (!SystemParametersInfoW(uiAction, sizeof(NONCLIENTMETRICSW),
+ &nclmw, fWinIni))
+ return FALSE;
+
+ pnclma->iBorderWidth = nclmw.iBorderWidth;
+ pnclma->iScrollWidth = nclmw.iScrollWidth;
+ pnclma->iScrollHeight = nclmw.iScrollHeight;
+ pnclma->iCaptionWidth = nclmw.iCaptionWidth;
+ pnclma->iCaptionHeight = nclmw.iCaptionHeight;
+ pnclma->iSmCaptionWidth = nclmw.iSmCaptionWidth;
+ pnclma->iSmCaptionHeight = nclmw.iSmCaptionHeight;
+ pnclma->iMenuWidth = nclmw.iMenuWidth;
+ pnclma->iMenuHeight = nclmw.iMenuHeight;
+ LogFontW2A(&(pnclma->lfCaptionFont), &(nclmw.lfCaptionFont));
+ LogFontW2A(&(pnclma->lfSmCaptionFont), &(nclmw.lfSmCaptionFont));
+ LogFontW2A(&(pnclma->lfMenuFont), &(nclmw.lfMenuFont));
+ LogFontW2A(&(pnclma->lfStatusFont), &(nclmw.lfStatusFont));
+ LogFontW2A(&(pnclma->lfMessageFont), &(nclmw.lfMessageFont));
+ return TRUE;
+ }
+ case SPI_SETNONCLIENTMETRICS:
+ {
+ LPNONCLIENTMETRICSA pnclma = (LPNONCLIENTMETRICSA)pvParam;
+ NONCLIENTMETRICSW nclmw;
+ if(pnclma->cbSize != sizeof(NONCLIENTMETRICSA))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ nclmw.cbSize = sizeof(NONCLIENTMETRICSW);
+ nclmw.iBorderWidth = pnclma->iBorderWidth;
+ nclmw.iScrollWidth = pnclma->iScrollWidth;
+ nclmw.iScrollHeight = pnclma->iScrollHeight;
+ nclmw.iCaptionWidth = pnclma->iCaptionWidth;
+ nclmw.iCaptionHeight = pnclma->iCaptionHeight;
+ nclmw.iSmCaptionWidth = pnclma->iSmCaptionWidth;
+ nclmw.iSmCaptionHeight = pnclma->iSmCaptionHeight;
+ nclmw.iMenuWidth = pnclma->iMenuWidth;
+ nclmw.iMenuHeight = pnclma->iMenuHeight;
+ LogFontA2W(&(nclmw.lfCaptionFont), &(pnclma->lfCaptionFont));
+ LogFontA2W(&(nclmw.lfSmCaptionFont), &(pnclma->lfSmCaptionFont));
+ LogFontA2W(&(nclmw.lfMenuFont), &(pnclma->lfMenuFont));
+ LogFontA2W(&(nclmw.lfStatusFont), &(pnclma->lfStatusFont));
+ LogFontA2W(&(nclmw.lfMessageFont), &(pnclma->lfMessageFont));
+
+ return SystemParametersInfoW(uiAction, sizeof(NONCLIENTMETRICSW),
+ &nclmw, fWinIni);
+ }
+ case SPI_GETICONMETRICS:
+ {
+ LPICONMETRICSA picma = (LPICONMETRICSA)pvParam;
+ ICONMETRICSW icmw;
+ if(picma->cbSize != sizeof(ICONMETRICSA))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ icmw.cbSize = sizeof(ICONMETRICSW);
+ if (!SystemParametersInfoW(uiAction, sizeof(ICONMETRICSW),
+ &icmw, fWinIni))
+ return FALSE;
+
+ picma->iHorzSpacing = icmw.iHorzSpacing;
+ picma->iVertSpacing = icmw.iVertSpacing;
+ picma->iTitleWrap = icmw.iTitleWrap;
+ LogFontW2A(&(picma->lfFont), &(icmw.lfFont));
+ return TRUE;
+ }
+ case SPI_SETICONMETRICS:
+ {
+ LPICONMETRICSA picma = (LPICONMETRICSA)pvParam;
+ ICONMETRICSW icmw;
+ if(picma->cbSize != sizeof(ICONMETRICSA))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ icmw.cbSize = sizeof(ICONMETRICSW);
+ icmw.iHorzSpacing = picma->iHorzSpacing;
+ icmw.iVertSpacing = picma->iVertSpacing;
+ icmw.iTitleWrap = picma->iTitleWrap;
+ LogFontA2W(&(icmw.lfFont), &(picma->lfFont));
+
+ return SystemParametersInfoW(uiAction, sizeof(ICONMETRICSW),
+ &icmw, fWinIni);
+ }
+ case SPI_GETICONTITLELOGFONT:
+ {
+ LOGFONTW lfw;
+ if (!SystemParametersInfoW(uiAction, 0, &lfw, fWinIni))
+ return FALSE;
+ LogFontW2A(pvParam, &lfw);
+ return TRUE;
+ }
+ case SPI_SETICONTITLELOGFONT:
+ {
+ LPLOGFONTA plfa = (LPLOGFONTA)pvParam;
+ LOGFONTW lfw;
+ LogFontA2W(&lfw,plfa);
+ return SystemParametersInfoW(uiAction, 0, &lfw, fWinIni);
+ }
+ case SPI_GETDESKWALLPAPER:
+ {
+ BOOL Ret;
+ WCHAR awc[MAX_PATH];
+ UNICODE_STRING ustrWallpaper;
+ ANSI_STRING astrWallpaper;
+
+ Ret = NtUserSystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, awc, fWinIni);
+ RtlInitUnicodeString(&ustrWallpaper, awc);
+ RtlUnicodeStringToAnsiString(&astrWallpaper, &ustrWallpaper, TRUE);
+
+ RtlCopyMemory(pvParam, astrWallpaper.Buffer, uiParam);
+ RtlFreeAnsiString(&astrWallpaper);
+ return Ret;
+ }
+
+ case SPI_SETDESKWALLPAPER:
+ {
+ UNICODE_STRING ustrWallpaper;
+ BOOL Ret;
+
+ if (pvParam)
+ {
+ if (!RtlCreateUnicodeStringFromAsciiz(&ustrWallpaper, pvParam))
+ {
+ ERR("RtlCreateUnicodeStringFromAsciiz failed\n");
+ return FALSE;
+ }
+ pvParam = &ustrWallpaper;
+ }
+
+ Ret = NtUserSystemParametersInfo(SPI_SETDESKWALLPAPER, uiParam, pvParam, fWinIni);
+
+ if (pvParam)
+ RtlFreeUnicodeString(&ustrWallpaper);
+
+ return Ret;
+ }
+ }
+ return NtUserSystemParametersInfo(uiAction, uiParam, pvParam, fWinIni);
+}
+
+BOOL WINAPI
+RealSystemParametersInfoW(UINT uiAction,
+ UINT uiParam,
+ PVOID pvParam,
+ UINT fWinIni)
+{
+ switch(uiAction)
+ {
+
+ case SPI_SETDESKWALLPAPER:
+ {
+ UNICODE_STRING ustrWallpaper;
+
+ RtlInitUnicodeString(&ustrWallpaper, pvParam);
+ return NtUserSystemParametersInfo(SPI_SETDESKWALLPAPER, uiParam, &ustrWallpaper, fWinIni);
+ }
+ }
+ return NtUserSystemParametersInfo(uiAction, uiParam, pvParam, fWinIni);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+SystemParametersInfoA(UINT uiAction,
+ UINT uiParam,
+ PVOID pvParam,
+ UINT fWinIni)
+{
+ BOOL Hook, Ret = FALSE;
+
+ LoadUserApiHook();
+
+ Hook = BeginIfHookedUserApiHook();
+
+ /* Bypass SEH and go direct. */
+ if (!Hook) return RealSystemParametersInfoA(uiAction, uiParam, pvParam, fWinIni);
+
+ _SEH2_TRY
+ {
+ Ret = guah.SystemParametersInfoA(uiAction, uiParam, pvParam, fWinIni);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ _SEH2_END;
+
+ EndUserApiHook();
+
+ return Ret;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+SystemParametersInfoW(UINT uiAction,
+ UINT uiParam,
+ PVOID pvParam,
+ UINT fWinIni)
+{
+ BOOL Hook, Ret = FALSE;
+
+ LoadUserApiHook();
+
+ Hook = BeginIfHookedUserApiHook();
+
+ /* Bypass SEH and go direct. */
+ if (!Hook) return RealSystemParametersInfoW(uiAction, uiParam, pvParam, fWinIni);
+
+ _SEH2_TRY
+ {
+ Ret = guah.SystemParametersInfoW(uiAction, uiParam, pvParam, fWinIni);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ _SEH2_END;
+
+ EndUserApiHook();
+
+ return Ret;
+}
+
+/*
+ * @implemented
+ */
+HDESK WINAPI
+CreateDesktopA(LPCSTR lpszDesktop,
+ LPCSTR lpszDevice,
+ LPDEVMODEA pDevmode,
+ DWORD dwFlags,
+ ACCESS_MASK dwDesiredAccess,
+ LPSECURITY_ATTRIBUTES lpsa)
+{
+ UNICODE_STRING DesktopNameU;
+ HDESK hDesktop;
+ LPDEVMODEW DevmodeW = NULL;
+
+ if (lpszDesktop)
+ {
+ /* After conversion, the buffer is zero-terminated */
+ RtlCreateUnicodeStringFromAsciiz(&DesktopNameU, lpszDesktop);
+ }
+ else
+ {
+ RtlInitUnicodeString(&DesktopNameU, NULL);
+ }
+
+ if (pDevmode)
+ DevmodeW = GdiConvertToDevmodeW(pDevmode);
+
+ hDesktop = CreateDesktopW(DesktopNameU.Buffer,
+ NULL,
+ DevmodeW,
+ dwFlags,
+ dwDesiredAccess,
+ lpsa);
+
+ /* Free the string, if it was allocated */
+ if (lpszDesktop) RtlFreeUnicodeString(&DesktopNameU);
+
+ return hDesktop;
+}
+
+
+/*
+ * @implemented
+ */
+HDESK WINAPI
+CreateDesktopW(LPCWSTR lpszDesktop,
+ LPCWSTR lpszDevice,
+ LPDEVMODEW pDevmode,
+ DWORD dwFlags,
+ ACCESS_MASK dwDesiredAccess,
+ LPSECURITY_ATTRIBUTES lpsa)
+{
+ OBJECT_ATTRIBUTES oas;
+ UNICODE_STRING DesktopName, DesktopDevice;
+ HWINSTA hWinSta;
+ HDESK hDesktop;
+ ULONG Attributes = (OBJ_OPENIF|OBJ_CASE_INSENSITIVE);
+
+ /* Retrive WinStation handle. */
+ hWinSta = NtUserGetProcessWindowStation();
+
+ /* Initialize the strings. */
+ RtlInitUnicodeString(&DesktopName, lpszDesktop);
+ RtlInitUnicodeString(&DesktopDevice, lpszDevice);
+
+ /* Check for process is inherited, set flag if set. */
+ if (lpsa && lpsa->bInheritHandle) Attributes |= OBJ_INHERIT;
+
+ /* Initialize the attributes for the desktop. */
+ InitializeObjectAttributes( &oas,
+ &DesktopName,
+ Attributes,
+ hWinSta,
+ lpsa ? lpsa->lpSecurityDescriptor : NULL);
+
+ /* Send the request and call to win32k. */
+ hDesktop = NtUserCreateDesktop( &oas,
+ &DesktopDevice,
+ pDevmode,
+ dwFlags,
+ dwDesiredAccess);
+
+ return(hDesktop);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+EnumDesktopsA(
+ HWINSTA WindowStation,
+ DESKTOPENUMPROCA EnumFunc,
+ LPARAM Context)
+{
+ return EnumNamesA(WindowStation, EnumFunc, Context, TRUE);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+EnumDesktopsW(
+ HWINSTA WindowStation,
+ DESKTOPENUMPROCW EnumFunc,
+ LPARAM Context)
+{
+ return EnumNamesW(WindowStation, EnumFunc, Context, TRUE);
+}
+
+
+/*
+ * @implemented
+ */
+HDESK
+WINAPI
+GetThreadDesktop(
+ DWORD dwThreadId)
+{
+ return NtUserGetThreadDesktop(dwThreadId, 0);
+}
+
+
+/*
+ * @implemented
+ */
+HDESK
+WINAPI
+OpenDesktopA(
+ LPCSTR lpszDesktop,
+ DWORD dwFlags,
+ BOOL fInherit,
+ ACCESS_MASK dwDesiredAccess)
+{
+ UNICODE_STRING DesktopNameU;
+ HDESK hDesktop;
+
+ if (lpszDesktop)
+ {
+ /* After conversion, the buffer is zero-terminated */
+ RtlCreateUnicodeStringFromAsciiz(&DesktopNameU, lpszDesktop);
+ }
+ else
+ {
+ RtlInitUnicodeString(&DesktopNameU, NULL);
+ }
+
+ hDesktop = OpenDesktopW(DesktopNameU.Buffer,
+ dwFlags,
+ fInherit,
+ dwDesiredAccess);
+
+ /* Free the string, if it was allocated */
+ if (lpszDesktop) RtlFreeUnicodeString(&DesktopNameU);
+
+ return hDesktop;
+}
+
+
+/*
+ * @implemented
+ */
+HDESK
+WINAPI
+OpenDesktopW(
+ LPCWSTR lpszDesktop,
+ DWORD dwFlags,
+ BOOL fInherit,
+ ACCESS_MASK dwDesiredAccess)
+{
+ UNICODE_STRING DesktopName;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+
+ RtlInitUnicodeString(&DesktopName, lpszDesktop);
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &DesktopName,
+ OBJ_CASE_INSENSITIVE,
+ GetProcessWindowStation(),
+ 0);
+
++ if( fInherit )
+ {
+ ObjectAttributes.Attributes |= OBJ_INHERIT;
+ }
+
+ return NtUserOpenDesktop(&ObjectAttributes, dwFlags, dwDesiredAccess);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+SetShellWindow(HWND hwndShell)
+{
+ return SetShellWindowEx(hwndShell, hwndShell);
+}
+
+
+/*
+ * @implemented
+ */
+HWND WINAPI
+GetShellWindow(VOID)
+{
+ PDESKTOPINFO pdi;
+ pdi = GetThreadDesktopInfo();
+ if (pdi) return pdi->hShellWindow;
+ return NULL;
+}
+
+
+/* EOF */
--- /dev/null
- if( fInherit == TRUE )
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS user32.dll
+ * FILE: lib/user32/misc/winsta.c
+ * PURPOSE: Window stations
+ * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * UPDATE HISTORY:
+ * 04-06-2001 CSH Created
+ */
+
+#include <user32.h>
+
+#include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(winsta);
+
+
+/*
+ * @implemented
+ */
+HWINSTA WINAPI
+CreateWindowStationA(LPCSTR lpwinsta,
+ DWORD dwReserved,
+ ACCESS_MASK dwDesiredAccess,
+ LPSECURITY_ATTRIBUTES lpsa)
+{
+ UNICODE_STRING WindowStationNameU;
+ HWINSTA hWinSta;
+
+ if (lpwinsta)
+ {
+ /* After conversion, the buffer is zero-terminated */
+ RtlCreateUnicodeStringFromAsciiz(&WindowStationNameU, lpwinsta);
+ }
+ else
+ {
+ RtlInitUnicodeString(&WindowStationNameU, NULL);
+ }
+
+ hWinSta = CreateWindowStationW(WindowStationNameU.Buffer,
+ dwReserved,
+ dwDesiredAccess,
+ lpsa);
+
+ /* Free the string, if it was allocated */
+ if (lpwinsta) RtlFreeUnicodeString(&WindowStationNameU);
+
+ return hWinSta;
+}
+
+
+/*
+ * @implemented
+ */
+HWINSTA WINAPI
+CreateWindowStationW(LPCWSTR lpwinsta,
+ DWORD dwReserved,
+ ACCESS_MASK dwDesiredAccess,
+ LPSECURITY_ATTRIBUTES lpsa)
+{
+ UNICODE_STRING WindowStationName;
+ UNICODE_STRING WindowStationsDir = RTL_CONSTANT_STRING(L"\\Windows\\WindowStations");
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE hWindowStationsDir;
+ NTSTATUS Status;
+ HWINSTA hwinsta;
+
+ /* Open WindowStations directory */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &WindowStationsDir,
+ OBJ_CASE_INSENSITIVE,
+ 0,
+ 0);
+
+ Status = NtOpenDirectoryObject(&hWindowStationsDir,
+ DIRECTORY_CREATE_OBJECT,
+ &ObjectAttributes);
+ if(!NT_SUCCESS(Status))
+ {
+ ERR("Failed to open WindowStations directory\n");
+ return NULL;
+ }
+
+ RtlInitUnicodeString(&WindowStationName, lpwinsta);
+
+ /* Create the window station object */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &WindowStationName,
+ OBJ_CASE_INSENSITIVE,
+ hWindowStationsDir,
+ 0);
+
+ /* Check if the handle should be inheritable */
+ if (lpsa && lpsa->bInheritHandle)
+ {
+ ObjectAttributes.Attributes |= OBJ_INHERIT;
+ }
+
+ hwinsta = NtUserCreateWindowStation(&ObjectAttributes,
+ dwDesiredAccess,
+ 0, 0, 0, 0, 0);
+
+ NtClose(hWindowStationsDir);
+
+ return hwinsta;
+}
+
+/*
+ * Common code for EnumDesktopsA/W and EnumWindowStationsA/W
+ */
+BOOL FASTCALL
+EnumNamesW(HWINSTA WindowStation,
+ NAMEENUMPROCW EnumFunc,
+ LPARAM Context,
+ BOOL Desktops)
+{
+ char Buffer[256];
+ PVOID NameList;
+ PWCHAR Name;
+ NTSTATUS Status;
+ ULONG RequiredSize;
+ ULONG CurrentEntry, EntryCount;
+ BOOL Ret;
+
+ /*
+ * Check parameters
+ */
+ if (NULL == WindowStation && Desktops)
+ {
+ WindowStation = GetProcessWindowStation();
+ }
+
+ /*
+ * Try with fixed-size buffer
+ */
+ Status = NtUserBuildNameList(WindowStation, sizeof(Buffer), Buffer, &RequiredSize);
+ if (NT_SUCCESS(Status))
+ {
+ /* Fixed-size buffer is large enough */
+ NameList = (PWCHAR) Buffer;
+ }
+ else if (Status == STATUS_BUFFER_TOO_SMALL)
+ {
+ /* Allocate a larger buffer */
+ NameList = HeapAlloc(GetProcessHeap(), 0, RequiredSize);
+ if (NULL == NameList)
+ {
+ return FALSE;
+ }
+ /* Try again */
+ Status = NtUserBuildNameList(WindowStation, RequiredSize, NameList, NULL);
+ if (! NT_SUCCESS(Status))
+ {
+ HeapFree(GetProcessHeap(), 0, NameList);
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+ }
+ else
+ {
+ /* Some unrecognized error occured */
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+
+ /*
+ * Enum the names one by one
+ */
+ EntryCount = *((DWORD *) NameList);
+ Name = (PWCHAR) ((PCHAR) NameList + sizeof(DWORD));
+ Ret = TRUE;
+ for (CurrentEntry = 0; CurrentEntry < EntryCount && Ret; ++CurrentEntry)
+ {
+ Ret = (*EnumFunc)(Name, Context);
+ Name += wcslen(Name) + 1;
+ }
+
+ /*
+ * Cleanup
+ */
+ if (NameList != Buffer)
+ {
+ HeapFree(GetProcessHeap(), 0, NameList);
+ }
+
+ return Ret;
+}
+
+
+/* For W->A conversion */
+typedef struct tagENUMNAMESASCIICONTEXT
+{
+ NAMEENUMPROCA UserEnumFunc;
+ LPARAM UserContext;
+} ENUMNAMESASCIICONTEXT, *PENUMNAMESASCIICONTEXT;
+
+/*
+ * Callback used by Ascii versions. Converts the Unicode name to
+ * Ascii and then calls the user callback
+ */
+BOOL CALLBACK
+EnumNamesCallback(LPWSTR Name, LPARAM Param)
+{
+ PENUMNAMESASCIICONTEXT Context = (PENUMNAMESASCIICONTEXT) Param;
+ char FixedNameA[32];
+ LPSTR NameA;
+ int Len;
+ BOOL Ret;
+
+ /*
+ * Determine required size of Ascii string and see if we can use
+ * fixed buffer
+ */
+ Len = WideCharToMultiByte(CP_ACP, 0, Name, -1, NULL, 0, NULL, NULL);
+ if (Len <= 0)
+ {
+ /* Some strange error occured */
+ return FALSE;
+ }
+ else if (Len <= sizeof(FixedNameA))
+ {
+ /* Fixed-size buffer is large enough */
+ NameA = FixedNameA;
+ }
+ else
+ {
+ /* Allocate a larger buffer */
+ NameA = HeapAlloc(GetProcessHeap(), 0, Len);
+ if (NULL == NameA)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ }
+
+ /*
+ * Do the Unicode ->Ascii conversion
+ */
+ if (0 == WideCharToMultiByte(CP_ACP, 0, Name, -1, NameA, Len, NULL, NULL))
+ {
+ /* Something went wrong, clean up */
+ if (NameA != FixedNameA)
+ {
+ HeapFree(GetProcessHeap(), 0, NameA);
+ }
+ return FALSE;
+ }
+
+ /*
+ * Call user callback
+ */
+ Ret = Context->UserEnumFunc(NameA, Context->UserContext);
+
+ /*
+ * Clean up
+ */
+ if (NameA != FixedNameA)
+ {
+ HeapFree(GetProcessHeap(), 0, NameA);
+ }
+
+ return Ret;
+}
+
+/*
+ * Common code for EnumDesktopsA and EnumWindowStationsA
+ */
+BOOL FASTCALL
+EnumNamesA(HWINSTA WindowStation,
+ NAMEENUMPROCA EnumFunc,
+ LPARAM Context,
+ BOOL Desktops)
+{
+ ENUMNAMESASCIICONTEXT PrivateContext;
+
+ PrivateContext.UserEnumFunc = EnumFunc;
+ PrivateContext.UserContext = Context;
+
+ return EnumNamesW(WindowStation, EnumNamesCallback, (LPARAM) &PrivateContext, Desktops);
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+EnumWindowStationsA(WINSTAENUMPROCA EnumFunc,
+ LPARAM Context)
+{
+ return EnumNamesA(NULL, EnumFunc, Context, FALSE);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+EnumWindowStationsW(WINSTAENUMPROCW EnumFunc,
+ LPARAM Context)
+{
+ return EnumNamesW(NULL, EnumFunc, Context, FALSE);
+}
+
+
+/*
+ * @implemented
+ */
+HWINSTA WINAPI
+OpenWindowStationA(LPCSTR lpszWinSta,
+ BOOL fInherit,
+ ACCESS_MASK dwDesiredAccess)
+{
+ UNICODE_STRING WindowStationNameU;
+ HWINSTA hWinSta;
+
+ if (lpszWinSta)
+ {
+ /* After conversion, the buffer is zero-terminated */
+ RtlCreateUnicodeStringFromAsciiz(&WindowStationNameU, lpszWinSta);
+ }
+ else
+ {
+ RtlInitUnicodeString(&WindowStationNameU, NULL);
+ }
+
+ hWinSta = OpenWindowStationW(WindowStationNameU.Buffer,
+ fInherit,
+ dwDesiredAccess);
+
+ /* Free the string, if it was allocated */
+ if (lpszWinSta) RtlFreeUnicodeString(&WindowStationNameU);
+
+ return hWinSta;
+}
+
+
+/*
+ * @implemented
+ */
+HWINSTA WINAPI
+OpenWindowStationW(LPCWSTR lpszWinSta,
+ BOOL fInherit,
+ ACCESS_MASK dwDesiredAccess)
+{
+ UNICODE_STRING WindowStationName;
+ UNICODE_STRING WindowStationsDir = RTL_CONSTANT_STRING(L"\\Windows\\WindowStations");
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE hWindowStationsDir;
+ NTSTATUS Status;
+ HWINSTA hwinsta;
+
+ /* Open WindowStations directory */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &WindowStationsDir,
+ OBJ_CASE_INSENSITIVE,
+ 0,
+ 0);
+
+ Status = NtOpenDirectoryObject(&hWindowStationsDir,
+ DIRECTORY_TRAVERSE,
+ &ObjectAttributes);
+ if(!NT_SUCCESS(Status))
+ {
+ ERR("Failed to open WindowStations directory\n");
+ return NULL;
+ }
+
+ /* Open the window station object */
+ RtlInitUnicodeString(&WindowStationName, lpszWinSta);
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &WindowStationName,
+ OBJ_CASE_INSENSITIVE,
+ hWindowStationsDir,
+ 0);
+
++ if( fInherit )
+ {
+ ObjectAttributes.Attributes |= OBJ_INHERIT;
+ }
+
+ hwinsta = NtUserOpenWindowStation(&ObjectAttributes, dwDesiredAccess);
+
+ NtClose(hWindowStationsDir);
+
+ return hwinsta;
+}
+
+
+/*
+ * @unimplemented
+ */
+DWORD
+WINAPI
+SetWindowStationUser(
+ DWORD Unknown1,
+ DWORD Unknown2,
+ DWORD Unknown3,
+ DWORD Unknown4
+ )
+{
+ return NtUserSetWindowStationUser(Unknown1, Unknown2, Unknown3, Unknown4);
+}
+
+/* EOF */
+
--- /dev/null
- if (OpenClipboard(GuiData->hWindow) == TRUE)
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Console Server DLL
+ * FILE: frontends/gui/conwnd.c
+ * PURPOSE: GUI Console Window Class
+ * PROGRAMMERS: Gé van Geldorp
+ * Johannes Anderwald
+ * Jeffrey Morlan
+ * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <consrv.h>
+#include <intrin.h>
+#include <windowsx.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "guiterm.h"
+#include "conwnd.h"
+#include "resource.h"
+
+/* GLOBALS ********************************************************************/
+
+// #define PM_CREATE_CONSOLE (WM_APP + 1)
+// #define PM_DESTROY_CONSOLE (WM_APP + 2)
+
+// See guiterm.c
+#define CONGUI_MIN_WIDTH 10
+#define CONGUI_MIN_HEIGHT 10
+#define CONGUI_UPDATE_TIME 0
+#define CONGUI_UPDATE_TIMER 1
+
+#define CURSOR_BLINK_TIME 500
+
+
+/**************************************************************\
+\** Define the Console Leader Process for the console window **/
+#define GWLP_CONWND_ALLOC (2 * sizeof(LONG_PTR))
+#define GWLP_CONSOLE_LEADER_PID 0
+#define GWLP_CONSOLE_LEADER_TID 4
+
+VOID
+SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData)
+{
+ PCONSOLE_PROCESS_DATA ProcessData;
+ CLIENT_ID ConsoleLeaderCID;
+
+ ProcessData = ConSrvGetConsoleLeaderProcess(GuiData->Console);
+ ConsoleLeaderCID = ProcessData->Process->ClientId;
+ SetWindowLongPtrW(GuiData->hWindow, GWLP_CONSOLE_LEADER_PID,
+ (LONG_PTR)(ConsoleLeaderCID.UniqueProcess));
+ SetWindowLongPtrW(GuiData->hWindow, GWLP_CONSOLE_LEADER_TID,
+ (LONG_PTR)(ConsoleLeaderCID.UniqueThread));
+}
+/**************************************************************/
+
+HICON ghDefaultIcon = NULL;
+HICON ghDefaultIconSm = NULL;
+HCURSOR ghDefaultCursor = NULL;
+
+typedef struct _GUICONSOLE_MENUITEM
+{
+ UINT uID;
+ const struct _GUICONSOLE_MENUITEM *SubMenu;
+ WORD wCmdID;
+} GUICONSOLE_MENUITEM, *PGUICONSOLE_MENUITEM;
+
+static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems[] =
+{
+ { IDS_MARK, NULL, ID_SYSTEM_EDIT_MARK },
+ { IDS_COPY, NULL, ID_SYSTEM_EDIT_COPY },
+ { IDS_PASTE, NULL, ID_SYSTEM_EDIT_PASTE },
+ { IDS_SELECTALL, NULL, ID_SYSTEM_EDIT_SELECTALL },
+ { IDS_SCROLL, NULL, ID_SYSTEM_EDIT_SCROLL },
+ { IDS_FIND, NULL, ID_SYSTEM_EDIT_FIND },
+
+ { 0, NULL, 0 } /* End of list */
+};
+
+static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems[] =
+{
+ { IDS_EDIT, GuiConsoleEditMenuItems, 0 },
+ { IDS_DEFAULTS, NULL, ID_SYSTEM_DEFAULTS },
+ { IDS_PROPERTIES, NULL, ID_SYSTEM_PROPERTIES },
+
+ { 0, NULL, 0 } /* End of list */
+};
+
+/*
+ * Default 16-color palette for foreground and background
+ * (corresponding flags in comments).
+ */
+const COLORREF s_Colors[16] =
+{
+ RGB(0, 0, 0), // (Black)
+ RGB(0, 0, 128), // BLUE
+ RGB(0, 128, 0), // GREEN
+ RGB(0, 128, 128), // BLUE | GREEN
+ RGB(128, 0, 0), // RED
+ RGB(128, 0, 128), // BLUE | RED
+ RGB(128, 128, 0), // GREEN | RED
+ RGB(192, 192, 192), // BLUE | GREEN | RED
+
+ RGB(128, 128, 128), // (Grey) INTENSITY
+ RGB(0, 0, 255), // BLUE | INTENSITY
+ RGB(0, 255, 0), // GREEN | INTENSITY
+ RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
+ RGB(255, 0, 0), // RED | INTENSITY
+ RGB(255, 0, 255), // BLUE | RED | INTENSITY
+ RGB(255, 255, 0), // GREEN | RED | INTENSITY
+ RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
+};
+
+/* FUNCTIONS ******************************************************************/
+
+static LRESULT CALLBACK
+ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+BOOLEAN
+RegisterConWndClass(IN HINSTANCE hInstance)
+{
+ WNDCLASSEXW WndClass;
+ ATOM WndClassAtom;
+
+ ghDefaultIcon = LoadImageW(hInstance,
+ MAKEINTRESOURCEW(IDI_TERMINAL),
+ IMAGE_ICON,
+ GetSystemMetrics(SM_CXICON),
+ GetSystemMetrics(SM_CYICON),
+ LR_SHARED);
+ ghDefaultIconSm = LoadImageW(hInstance,
+ MAKEINTRESOURCEW(IDI_TERMINAL),
+ IMAGE_ICON,
+ GetSystemMetrics(SM_CXSMICON),
+ GetSystemMetrics(SM_CYSMICON),
+ LR_SHARED);
+ ghDefaultCursor = LoadCursorW(NULL, IDC_ARROW);
+
+ WndClass.cbSize = sizeof(WNDCLASSEXW);
+ WndClass.lpszClassName = GUI_CONWND_CLASS;
+ WndClass.lpfnWndProc = ConWndProc;
+ WndClass.style = CS_DBLCLKS /* | CS_HREDRAW | CS_VREDRAW */;
+ WndClass.hInstance = hInstance;
+ WndClass.hIcon = ghDefaultIcon;
+ WndClass.hIconSm = ghDefaultIconSm;
+ WndClass.hCursor = ghDefaultCursor;
+ WndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // The color of a terminal when it is switched off.
+ WndClass.lpszMenuName = NULL;
+ WndClass.cbClsExtra = 0;
+ WndClass.cbWndExtra = GWLP_CONWND_ALLOC;
+
+ WndClassAtom = RegisterClassExW(&WndClass);
+ if (WndClassAtom == 0)
+ {
+ DPRINT1("Failed to register GUI console class\n");
+ }
+ else
+ {
+ NtUserConsoleControl(GuiConsoleWndClassAtom, &WndClassAtom, sizeof(ATOM));
+ }
+
+ return (WndClassAtom != 0);
+}
+
+BOOLEAN
+UnRegisterConWndClass(HINSTANCE hInstance)
+{
+ return !!UnregisterClassW(GUI_CONWND_CLASS, hInstance);
+}
+
+
+
+static VOID
+GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer,
+ IN PGUI_CONSOLE_DATA GuiData,
+ OUT PUINT WidthUnit,
+ OUT PUINT HeightUnit)
+{
+ if (Buffer == NULL || GuiData == NULL ||
+ WidthUnit == NULL || HeightUnit == NULL)
+ {
+ return;
+ }
+
+ if (GetType(Buffer) == TEXTMODE_BUFFER)
+ {
+ *WidthUnit = GuiData->CharWidth ;
+ *HeightUnit = GuiData->CharHeight;
+ }
+ else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
+ {
+ *WidthUnit = 1;
+ *HeightUnit = 1;
+ }
+}
+
+static VOID
+AppendMenuItems(HMENU hMenu,
+ const GUICONSOLE_MENUITEM *Items)
+{
+ UINT i = 0;
+ WCHAR szMenuString[255];
+ HMENU hSubMenu;
+
+ do
+ {
+ if (Items[i].uID != (UINT)-1)
+ {
+ if (LoadStringW(ConSrvDllInstance,
+ Items[i].uID,
+ szMenuString,
+ sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
+ {
+ if (Items[i].SubMenu != NULL)
+ {
+ hSubMenu = CreatePopupMenu();
+ if (hSubMenu != NULL)
+ {
+ AppendMenuItems(hSubMenu, Items[i].SubMenu);
+
+ if (!AppendMenuW(hMenu,
+ MF_STRING | MF_POPUP,
+ (UINT_PTR)hSubMenu,
+ szMenuString))
+ {
+ DestroyMenu(hSubMenu);
+ }
+ }
+ }
+ else
+ {
+ AppendMenuW(hMenu,
+ MF_STRING,
+ Items[i].wCmdID,
+ szMenuString);
+ }
+ }
+ }
+ else
+ {
+ AppendMenuW(hMenu,
+ MF_SEPARATOR,
+ 0,
+ NULL);
+ }
+ i++;
+ } while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
+}
+
+//static
+VOID
+CreateSysMenu(HWND hWnd)
+{
+ MENUITEMINFOW mii;
+ WCHAR szMenuStringBack[255];
+ WCHAR *ptrTab;
+ HMENU hMenu = GetSystemMenu(hWnd, FALSE);
+ if (hMenu != NULL)
+ {
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_STRING;
+ mii.dwTypeData = szMenuStringBack;
+ mii.cch = sizeof(szMenuStringBack)/sizeof(WCHAR);
+
+ GetMenuItemInfoW(hMenu, SC_CLOSE, FALSE, &mii);
+
+ ptrTab = wcschr(szMenuStringBack, '\t');
+ if (ptrTab)
+ {
+ *ptrTab = '\0';
+ mii.cch = wcslen(szMenuStringBack);
+
+ SetMenuItemInfoW(hMenu, SC_CLOSE, FALSE, &mii);
+ }
+
+ AppendMenuItems(hMenu, GuiConsoleMainMenuItems);
+ DrawMenuBar(hWnd);
+ }
+}
+
+static VOID
+SendMenuEvent(PCONSRV_CONSOLE Console, UINT CmdId)
+{
+ INPUT_RECORD er;
+
+ DPRINT("Menu item ID: %d\n", CmdId);
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
+ er.EventType = MENU_EVENT;
+ er.Event.MenuEvent.dwCommandId = CmdId;
+ ConioProcessInputEvent(Console, &er);
+
+ LeaveCriticalSection(&Console->Lock);
+}
+
+static VOID
+Copy(PGUI_CONSOLE_DATA GuiData);
+static VOID
+Paste(PGUI_CONSOLE_DATA GuiData);
+static VOID
+UpdateSelection(PGUI_CONSOLE_DATA GuiData,
+ PCOORD SelectionAnchor OPTIONAL,
+ PCOORD coord);
+
+static VOID
+Mark(PGUI_CONSOLE_DATA GuiData)
+{
+ PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
+
+ /* Clear the old selection */
+ GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
+
+ /* Restart a new selection */
+ GuiData->dwSelectionCursor = ActiveBuffer->ViewOrigin;
+ UpdateSelection(GuiData,
+ &GuiData->dwSelectionCursor,
+ &GuiData->dwSelectionCursor);
+}
+
+static VOID
+SelectAll(PGUI_CONSOLE_DATA GuiData)
+{
+ PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
+ COORD SelectionAnchor;
+
+ /* Clear the old selection */
+ GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
+
+ /*
+ * The selection area extends to the whole screen buffer's width.
+ */
+ SelectionAnchor.X = SelectionAnchor.Y = 0;
+ GuiData->dwSelectionCursor.X = ActiveBuffer->ScreenBufferSize.X - 1;
+
+ /*
+ * Determine whether the selection must extend to just some part
+ * (for text-mode screen buffers) or to all of the screen buffer's
+ * height (for graphics ones).
+ */
+ if (GetType(ActiveBuffer) == TEXTMODE_BUFFER)
+ {
+ /*
+ * We select all the characters from the first line
+ * to the line where the cursor is positioned.
+ */
+ GuiData->dwSelectionCursor.Y = ActiveBuffer->CursorPosition.Y;
+ }
+ else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
+ {
+ /*
+ * We select all the screen buffer area.
+ */
+ GuiData->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
+ }
+
+ /* Restart a new selection */
+ GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION;
+ UpdateSelection(GuiData, &SelectionAnchor, &GuiData->dwSelectionCursor);
+}
+
+static LRESULT
+OnCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT Ret = TRUE;
+ PCONSRV_CONSOLE Console = GuiData->Console;
+
+ /*
+ * In case the selected menu item belongs to the user-reserved menu id range,
+ * send to him a menu event and return directly. The user must handle those
+ * reserved menu commands...
+ */
+ if (GuiData->CmdIdLow <= (UINT)wParam && (UINT)wParam <= GuiData->CmdIdHigh)
+ {
+ SendMenuEvent(Console, (UINT)wParam);
+ goto Quit;
+ }
+
+ /* ... otherwise, perform actions. */
+ switch (wParam)
+ {
+ case ID_SYSTEM_EDIT_MARK:
+ Mark(GuiData);
+ break;
+
+ case ID_SYSTEM_EDIT_COPY:
+ Copy(GuiData);
+ break;
+
+ case ID_SYSTEM_EDIT_PASTE:
+ Paste(GuiData);
+ break;
+
+ case ID_SYSTEM_EDIT_SELECTALL:
+ SelectAll(GuiData);
+ break;
+
+ case ID_SYSTEM_EDIT_SCROLL:
+ DPRINT1("Scrolling is not handled yet\n");
+ break;
+
+ case ID_SYSTEM_EDIT_FIND:
+ DPRINT1("Finding is not handled yet\n");
+ break;
+
+ case ID_SYSTEM_DEFAULTS:
+ GuiConsoleShowConsoleProperties(GuiData, TRUE);
+ break;
+
+ case ID_SYSTEM_PROPERTIES:
+ GuiConsoleShowConsoleProperties(GuiData, FALSE);
+ break;
+
+ default:
+ Ret = FALSE;
+ break;
+ }
+
+Quit:
+ if (!Ret)
+ Ret = DefWindowProcW(GuiData->hWindow, WM_SYSCOMMAND, wParam, lParam);
+
+ return Ret;
+}
+
+static PGUI_CONSOLE_DATA
+GuiGetGuiData(HWND hWnd)
+{
+ /* This function ensures that the console pointer is not NULL */
+ PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
+ return ( ((GuiData == NULL) || (GuiData->hWindow == hWnd && GuiData->Console != NULL)) ? GuiData : NULL );
+}
+
+static VOID
+ResizeConWnd(PGUI_CONSOLE_DATA GuiData, DWORD WidthUnit, DWORD HeightUnit)
+{
+ PCONSOLE_SCREEN_BUFFER Buff = GuiData->ActiveBuffer;
+ SCROLLINFO sInfo;
+
+ DWORD Width, Height;
+
+ Width = Buff->ViewSize.X * WidthUnit +
+ 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
+ Height = Buff->ViewSize.Y * HeightUnit +
+ 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
+
+ /* Set scrollbar sizes */
+ sInfo.cbSize = sizeof(SCROLLINFO);
+ sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ sInfo.nMin = 0;
+ if (Buff->ScreenBufferSize.Y > Buff->ViewSize.Y)
+ {
+ sInfo.nMax = Buff->ScreenBufferSize.Y - 1;
+ sInfo.nPage = Buff->ViewSize.Y;
+ sInfo.nPos = Buff->ViewOrigin.Y;
+ SetScrollInfo(GuiData->hWindow, SB_VERT, &sInfo, TRUE);
+ Width += GetSystemMetrics(SM_CXVSCROLL);
+ ShowScrollBar(GuiData->hWindow, SB_VERT, TRUE);
+ }
+ else
+ {
+ ShowScrollBar(GuiData->hWindow, SB_VERT, FALSE);
+ }
+
+ if (Buff->ScreenBufferSize.X > Buff->ViewSize.X)
+ {
+ sInfo.nMax = Buff->ScreenBufferSize.X - 1;
+ sInfo.nPage = Buff->ViewSize.X;
+ sInfo.nPos = Buff->ViewOrigin.X;
+ SetScrollInfo(GuiData->hWindow, SB_HORZ, &sInfo, TRUE);
+ Height += GetSystemMetrics(SM_CYHSCROLL);
+ ShowScrollBar(GuiData->hWindow, SB_HORZ, TRUE);
+ }
+ else
+ {
+ ShowScrollBar(GuiData->hWindow, SB_HORZ, FALSE);
+ }
+
+ /* Resize the window */
+ SetWindowPos(GuiData->hWindow, NULL, 0, 0, Width, Height,
+ SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS);
+ // NOTE: The SWP_NOCOPYBITS flag can be replaced by a subsequent call
+ // to: InvalidateRect(GuiData->hWindow, NULL, TRUE);
+}
+
+
+VOID
+DeleteFonts(PGUI_CONSOLE_DATA GuiData)
+{
+ ULONG i;
+ for (i = 0; i < sizeof(GuiData->Font) / sizeof(GuiData->Font[0]); ++i)
+ {
+ if (GuiData->Font[i] != NULL) DeleteObject(GuiData->Font[i]);
+ GuiData->Font[i] = NULL;
+ }
+}
+
+static HFONT
+CreateDerivedFont(HFONT OrgFont,
+ // COORD FontSize,
+ ULONG FontWeight,
+ // BOOLEAN bItalic,
+ BOOLEAN bUnderline,
+ BOOLEAN bStrikeOut)
+{
+ LOGFONT lf;
+
+ /* Initialize the LOGFONT structure */
+ RtlZeroMemory(&lf, sizeof(lf));
+
+ /* Retrieve the details of the current font */
+ if (GetObject(OrgFont, sizeof(lf), &lf) == 0)
+ return NULL;
+
+ /* Change the font attributes */
+ // lf.lfHeight = FontSize.Y;
+ // lf.lfWidth = FontSize.X;
+ lf.lfWeight = FontWeight;
+ // lf.lfItalic = bItalic;
+ lf.lfUnderline = bUnderline;
+ lf.lfStrikeOut = bStrikeOut;
+
+ /* Build a new font */
+ return CreateFontIndirect(&lf);
+}
+
+BOOL
+InitFonts(PGUI_CONSOLE_DATA GuiData,
+ LPWSTR FaceName, // Points to a WCHAR array of LF_FACESIZE elements.
+ ULONG FontFamily,
+ COORD FontSize,
+ ULONG FontWeight)
+{
+ HDC hDC;
+ HFONT OldFont, NewFont;
+ TEXTMETRICW Metrics;
+ SIZE CharSize;
+
+ hDC = GetDC(GuiData->hWindow);
+
+ /*
+ * Initialize a new NORMAL font and get its metrics.
+ */
+
+ FontSize.Y = FontSize.Y > 0 ? -MulDiv(FontSize.Y, GetDeviceCaps(hDC, LOGPIXELSY), 72)
+ : FontSize.Y;
+
+ NewFont = CreateFontW(FontSize.Y,
+ FontSize.X,
+ 0,
+ TA_BASELINE,
+ FontWeight,
+ FALSE,
+ FALSE,
+ FALSE,
+ OEM_CHARSET,
+ OUT_DEFAULT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY,
+ FIXED_PITCH | FontFamily,
+ FaceName);
+ if (NewFont == NULL)
+ {
+ DPRINT1("InitFonts: CreateFontW failed\n");
+ ReleaseDC(GuiData->hWindow, hDC);
+ return FALSE;
+ }
+
+ OldFont = SelectObject(hDC, NewFont);
+ if (OldFont == NULL)
+ {
+ DPRINT1("InitFonts: SelectObject failed\n");
+ ReleaseDC(GuiData->hWindow, hDC);
+ DeleteObject(NewFont);
+ return FALSE;
+ }
+
+ if (!GetTextMetricsW(hDC, &Metrics))
+ {
+ DPRINT1("InitFonts: GetTextMetrics failed\n");
+ SelectObject(hDC, OldFont);
+ ReleaseDC(GuiData->hWindow, hDC);
+ DeleteObject(NewFont);
+ return FALSE;
+ }
+ GuiData->CharWidth = Metrics.tmMaxCharWidth;
+ GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
+
+ /* Measure real char width more precisely if possible */
+ if (GetTextExtentPoint32W(hDC, L"R", 1, &CharSize))
+ GuiData->CharWidth = CharSize.cx;
+
+ SelectObject(hDC, OldFont);
+ ReleaseDC(GuiData->hWindow, hDC);
+
+ /*
+ * Initialization succeeded.
+ */
+ // Delete all the old fonts first.
+ DeleteFonts(GuiData);
+ GuiData->Font[FONT_NORMAL] = NewFont;
+
+ /*
+ * Now build the other fonts (bold, underlined, mixed).
+ */
+ GuiData->Font[FONT_BOLD] =
+ CreateDerivedFont(GuiData->Font[FONT_NORMAL],
+ FontWeight < FW_BOLD ? FW_BOLD : FontWeight,
+ FALSE,
+ FALSE);
+ GuiData->Font[FONT_UNDERLINE] =
+ CreateDerivedFont(GuiData->Font[FONT_NORMAL],
+ FontWeight,
+ TRUE,
+ FALSE);
+ GuiData->Font[FONT_BOLD | FONT_UNDERLINE] =
+ CreateDerivedFont(GuiData->Font[FONT_NORMAL],
+ FontWeight < FW_BOLD ? FW_BOLD : FontWeight,
+ TRUE,
+ FALSE);
+
+ /*
+ * Save the settings.
+ */
+ if (FaceName != GuiData->GuiInfo.FaceName)
+ {
+ wcsncpy(GuiData->GuiInfo.FaceName, FaceName, LF_FACESIZE);
+ GuiData->GuiInfo.FaceName[LF_FACESIZE - 1] = UNICODE_NULL;
+ }
+ GuiData->GuiInfo.FontFamily = FontFamily;
+ GuiData->GuiInfo.FontSize = FontSize;
+ GuiData->GuiInfo.FontWeight = FontWeight;
+
+ return TRUE;
+}
+
+
+static BOOL
+OnNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
+{
+ PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)Create->lpCreateParams;
+ PCONSRV_CONSOLE Console;
+
+ if (NULL == GuiData)
+ {
+ DPRINT1("GuiConsoleNcCreate: No GUI data\n");
+ return FALSE;
+ }
+
+ Console = GuiData->Console;
+
+ GuiData->hWindow = hWnd;
+
+ /* Initialize the fonts */
+ if (!InitFonts(GuiData,
+ GuiData->GuiInfo.FaceName,
+ GuiData->GuiInfo.FontFamily,
+ GuiData->GuiInfo.FontSize,
+ GuiData->GuiInfo.FontWeight))
+ {
+ DPRINT1("GuiConsoleNcCreate: InitFonts failed\n");
+ GuiData->hWindow = NULL;
+ SetEvent(GuiData->hGuiInitEvent);
+ return FALSE;
+ }
+
+ /* Initialize the terminal framebuffer */
+ GuiData->hMemDC = CreateCompatibleDC(NULL);
+ GuiData->hBitmap = NULL;
+ GuiData->hSysPalette = NULL; /* Original system palette */
+
+ /* Update the icons of the window */
+ if (GuiData->hIcon != ghDefaultIcon)
+ {
+ DefWindowProcW(GuiData->hWindow, WM_SETICON, ICON_BIG , (LPARAM)GuiData->hIcon );
+ DefWindowProcW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
+ }
+
+ // FIXME: Keep these instructions here ? ///////////////////////////////////
+ Console->ActiveBuffer->CursorBlinkOn = TRUE;
+ Console->ActiveBuffer->ForceCursorOff = FALSE;
+ ////////////////////////////////////////////////////////////////////////////
+
+ SetWindowLongPtrW(GuiData->hWindow, GWLP_USERDATA, (DWORD_PTR)GuiData);
+
+ SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
+ // FIXME: HACK: Potential HACK for CORE-8129; see revision 63595.
+ //CreateSysMenu(GuiData->hWindow);
+
+ DPRINT("OnNcCreate - setting start event\n");
+ SetEvent(GuiData->hGuiInitEvent);
+
+ return (BOOL)DefWindowProcW(GuiData->hWindow, WM_NCCREATE, 0, (LPARAM)Create);
+}
+
+
+BOOL
+EnterFullScreen(PGUI_CONSOLE_DATA GuiData);
+VOID
+LeaveFullScreen(PGUI_CONSOLE_DATA GuiData);
+VOID
+SwitchFullScreen(PGUI_CONSOLE_DATA GuiData, BOOL FullScreen);
+VOID
+GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData);
+
+static VOID
+OnActivate(PGUI_CONSOLE_DATA GuiData, WPARAM wParam)
+{
+ WORD ActivationState = LOWORD(wParam);
+
+ DPRINT("WM_ACTIVATE - ActivationState = %d\n");
+
+ if ( ActivationState == WA_ACTIVE ||
+ ActivationState == WA_CLICKACTIVE )
+ {
+ if (GuiData->GuiInfo.FullScreen)
+ {
+ EnterFullScreen(GuiData);
+ // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
+ // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
+ }
+ }
+ else // if (ActivationState == WA_INACTIVE)
+ {
+ if (GuiData->GuiInfo.FullScreen)
+ {
+ SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+ LeaveFullScreen(GuiData);
+ // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+ // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+ }
+ }
+
+ /*
+ * Ignore the next mouse signal when we are going to be enabled again via
+ * the mouse, in order to prevent, e.g. when we are in Edit mode, erroneous
+ * mouse actions from the user that could spoil text selection or copy/pastes.
+ */
+ if (ActivationState == WA_CLICKACTIVE)
+ GuiData->IgnoreNextMouseSignal = TRUE;
+}
+
+static VOID
+OnFocus(PGUI_CONSOLE_DATA GuiData, BOOL SetFocus)
+{
+ PCONSRV_CONSOLE Console = GuiData->Console;
+ INPUT_RECORD er;
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
+ er.EventType = FOCUS_EVENT;
+ er.Event.FocusEvent.bSetFocus = SetFocus;
+ ConioProcessInputEvent(Console, &er);
+
+ LeaveCriticalSection(&Console->Lock);
+
+ if (SetFocus)
+ DPRINT1("TODO: Create console caret\n");
+ else
+ DPRINT1("TODO: Destroy console caret\n");
+}
+
+static VOID
+SmallRectToRect(PGUI_CONSOLE_DATA GuiData, PRECT Rect, PSMALL_RECT SmallRect)
+{
+ PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
+ UINT WidthUnit, HeightUnit;
+
+ GetScreenBufferSizeUnits(Buffer, GuiData, &WidthUnit, &HeightUnit);
+
+ Rect->left = (SmallRect->Left - Buffer->ViewOrigin.X) * WidthUnit ;
+ Rect->top = (SmallRect->Top - Buffer->ViewOrigin.Y) * HeightUnit;
+ Rect->right = (SmallRect->Right + 1 - Buffer->ViewOrigin.X) * WidthUnit ;
+ Rect->bottom = (SmallRect->Bottom + 1 - Buffer->ViewOrigin.Y) * HeightUnit;
+}
+
+VOID
+GetSelectionBeginEnd(PCOORD Begin, PCOORD End,
+ PCOORD SelectionAnchor,
+ PSMALL_RECT SmallRect)
+{
+ if (Begin == NULL || End == NULL) return;
+
+ *Begin = *SelectionAnchor;
+ End->X = (SelectionAnchor->X == SmallRect->Left) ? SmallRect->Right
+ /* Case X != Left, must be == Right */ : SmallRect->Left;
+ End->Y = (SelectionAnchor->Y == SmallRect->Top ) ? SmallRect->Bottom
+ /* Case Y != Top, must be == Bottom */ : SmallRect->Top;
+
+ /* Exchange Begin / End if Begin > End lexicographically */
+ if (Begin->Y > End->Y || (Begin->Y == End->Y && Begin->X > End->X))
+ {
+ End->X = _InterlockedExchange16(&Begin->X, End->X);
+ End->Y = _InterlockedExchange16(&Begin->Y, End->Y);
+ }
+}
+
+static HRGN
+CreateSelectionRgn(PGUI_CONSOLE_DATA GuiData,
+ BOOL LineSelection,
+ PCOORD SelectionAnchor,
+ PSMALL_RECT SmallRect)
+{
+ if (!LineSelection)
+ {
+ RECT rect;
+ SmallRectToRect(GuiData, &rect, SmallRect);
+ return CreateRectRgnIndirect(&rect);
+ }
+ else
+ {
+ HRGN SelRgn;
+ COORD Begin, End;
+
+ GetSelectionBeginEnd(&Begin, &End, SelectionAnchor, SmallRect);
+
+ if (Begin.Y == End.Y)
+ {
+ SMALL_RECT sr;
+ RECT r ;
+
+ sr.Left = Begin.X;
+ sr.Top = Begin.Y;
+ sr.Right = End.X;
+ sr.Bottom = End.Y;
+
+ // Debug thingie to see whether I can put this corner case
+ // together with the previous one.
+ if (SmallRect->Left != sr.Left ||
+ SmallRect->Top != sr.Top ||
+ SmallRect->Right != sr.Right ||
+ SmallRect->Bottom != sr.Bottom)
+ {
+ DPRINT1("\n"
+ "SmallRect = (%d, %d, %d, %d)\n"
+ "sr = (%d, %d, %d, %d)\n"
+ "\n",
+ SmallRect->Left, SmallRect->Top, SmallRect->Right, SmallRect->Bottom,
+ sr.Left, sr.Top, sr.Right, sr.Bottom);
+ }
+
+ SmallRectToRect(GuiData, &r, &sr);
+ SelRgn = CreateRectRgnIndirect(&r);
+ }
+ else
+ {
+ PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
+
+ HRGN rg1, rg2, rg3;
+ SMALL_RECT sr1, sr2, sr3;
+ RECT r1 , r2 , r3 ;
+
+ sr1.Left = Begin.X;
+ sr1.Top = Begin.Y;
+ sr1.Right = ActiveBuffer->ScreenBufferSize.X - 1;
+ sr1.Bottom = Begin.Y;
+
+ sr2.Left = 0;
+ sr2.Top = Begin.Y + 1;
+ sr2.Right = ActiveBuffer->ScreenBufferSize.X - 1;
+ sr2.Bottom = End.Y - 1;
+
+ sr3.Left = 0;
+ sr3.Top = End.Y;
+ sr3.Right = End.X;
+ sr3.Bottom = End.Y;
+
+ SmallRectToRect(GuiData, &r1, &sr1);
+ SmallRectToRect(GuiData, &r2, &sr2);
+ SmallRectToRect(GuiData, &r3, &sr3);
+
+ rg1 = CreateRectRgnIndirect(&r1);
+ rg2 = CreateRectRgnIndirect(&r2);
+ rg3 = CreateRectRgnIndirect(&r3);
+
+ CombineRgn(rg1, rg1, rg2, RGN_XOR);
+ CombineRgn(rg1, rg1, rg3, RGN_XOR);
+ DeleteObject(rg3);
+ DeleteObject(rg2);
+
+ SelRgn = rg1;
+ }
+
+ return SelRgn;
+ }
+}
+
+static VOID
+PaintSelectionRect(PGUI_CONSOLE_DATA GuiData, PPAINTSTRUCT pps)
+{
+ HRGN rgnPaint = CreateRectRgnIndirect(&pps->rcPaint);
+ HRGN rgnSel = CreateSelectionRgn(GuiData, GuiData->LineSelection,
+ &GuiData->Selection.dwSelectionAnchor,
+ &GuiData->Selection.srSelection);
+
+ /* Invert the selection */
+
+ int ErrorCode = CombineRgn(rgnPaint, rgnPaint, rgnSel, RGN_AND);
+ if (ErrorCode != ERROR && ErrorCode != NULLREGION)
+ {
+ InvertRgn(pps->hdc, rgnPaint);
+ }
+
+ DeleteObject(rgnSel);
+ DeleteObject(rgnPaint);
+}
+
+static VOID
+UpdateSelection(PGUI_CONSOLE_DATA GuiData,
+ PCOORD SelectionAnchor OPTIONAL,
+ PCOORD coord)
+{
+ PCONSRV_CONSOLE Console = GuiData->Console;
+ HRGN oldRgn = CreateSelectionRgn(GuiData, GuiData->LineSelection,
+ &GuiData->Selection.dwSelectionAnchor,
+ &GuiData->Selection.srSelection);
+
+ /* Update the anchor if needed (use the old one if NULL) */
+ if (SelectionAnchor)
+ GuiData->Selection.dwSelectionAnchor = *SelectionAnchor;
+
+ if (coord != NULL)
+ {
+ SMALL_RECT rc;
+ HRGN newRgn;
+
+ /*
+ * Pressing the Control key while selecting text, allows us to enter
+ * into line-selection mode, the selection mode of *nix terminals.
+ */
+ BOOL OldLineSel = GuiData->LineSelection;
+ GuiData->LineSelection = !!(GetKeyState(VK_CONTROL) & 0x8000);
+
+ /* Exchange left/top with right/bottom if required */
+ rc.Left = min(GuiData->Selection.dwSelectionAnchor.X, coord->X);
+ rc.Top = min(GuiData->Selection.dwSelectionAnchor.Y, coord->Y);
+ rc.Right = max(GuiData->Selection.dwSelectionAnchor.X, coord->X);
+ rc.Bottom = max(GuiData->Selection.dwSelectionAnchor.Y, coord->Y);
+
+ newRgn = CreateSelectionRgn(GuiData, GuiData->LineSelection,
+ &GuiData->Selection.dwSelectionAnchor,
+ &rc);
+
+ if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
+ {
+ if (OldLineSel != GuiData->LineSelection ||
+ memcmp(&rc, &GuiData->Selection.srSelection, sizeof(SMALL_RECT)) != 0)
+ {
+ /* Calculate the region that needs to be updated */
+ if (oldRgn && newRgn && CombineRgn(newRgn, newRgn, oldRgn, RGN_XOR) != ERROR)
+ {
+ InvalidateRgn(GuiData->hWindow, newRgn, FALSE);
+ }
+ }
+ }
+ else
+ {
+ InvalidateRgn(GuiData->hWindow, newRgn, FALSE);
+ }
+
+ DeleteObject(newRgn);
+
+ GuiData->Selection.dwFlags |= CONSOLE_SELECTION_NOT_EMPTY;
+ GuiData->Selection.srSelection = rc;
+ GuiData->dwSelectionCursor = *coord;
+
+ if ((GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) == 0)
+ {
+ LPWSTR SelTypeStr = NULL , WindowTitle = NULL;
+ SIZE_T SelTypeStrLength = 0, Length = 0;
+
+ /* Clear the old selection */
+ if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
+ {
+ InvalidateRgn(GuiData->hWindow, oldRgn, FALSE);
+ }
+
+ /*
+ * When passing a zero-length buffer size, LoadString(...) returns
+ * a read-only pointer buffer to the program's resource string.
+ */
+ SelTypeStrLength =
+ LoadStringW(ConSrvDllInstance,
+ (GuiData->Selection.dwFlags & CONSOLE_MOUSE_SELECTION)
+ ? IDS_SELECT_TITLE : IDS_MARK_TITLE,
+ (LPWSTR)&SelTypeStr, 0);
+
+ /*
+ * Prepend the selection type string to the current console title
+ * if we succeeded in retrieving a valid localized string.
+ */
+ if (SelTypeStr)
+ {
+ // 3 for " - " and 1 for NULL
+ Length = Console->Title.Length + (SelTypeStrLength + 3 + 1) * sizeof(WCHAR);
+ WindowTitle = ConsoleAllocHeap(0, Length);
+
+ wcsncpy(WindowTitle, SelTypeStr, SelTypeStrLength);
+ WindowTitle[SelTypeStrLength] = L'\0';
+ wcscat(WindowTitle, L" - ");
+ wcscat(WindowTitle, Console->Title.Buffer);
+
+ SetWindowText(GuiData->hWindow, WindowTitle);
+ ConsoleFreeHeap(WindowTitle);
+ }
+
+ GuiData->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS;
+ ConioPause(Console, PAUSED_FROM_SELECTION);
+ }
+ }
+ else
+ {
+ /* Clear the selection */
+ if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
+ {
+ InvalidateRgn(GuiData->hWindow, oldRgn, FALSE);
+ }
+
+ GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
+ ConioUnpause(Console, PAUSED_FROM_SELECTION);
+
+ /* Restore the console title */
+ SetWindowText(GuiData->hWindow, Console->Title.Buffer);
+ }
+
+ DeleteObject(oldRgn);
+}
+
+
+VOID
+GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
+ PGUI_CONSOLE_DATA GuiData,
+ PRECT rcView,
+ PRECT rcFramebuffer);
+VOID
+GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
+ PGUI_CONSOLE_DATA GuiData,
+ PRECT rcView,
+ PRECT rcFramebuffer);
+
+static VOID
+OnPaint(PGUI_CONSOLE_DATA GuiData)
+{
+ PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
+ PAINTSTRUCT ps;
+ RECT rcPaint;
+
+ BeginPaint(GuiData->hWindow, &ps);
+ if (ps.hdc != NULL &&
+ ps.rcPaint.left < ps.rcPaint.right &&
+ ps.rcPaint.top < ps.rcPaint.bottom)
+ {
+ EnterCriticalSection(&GuiData->Lock);
+
+ /* Compose the current screen-buffer on-memory */
+ if (GetType(ActiveBuffer) == TEXTMODE_BUFFER)
+ {
+ GuiPaintTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)ActiveBuffer,
+ GuiData, &ps.rcPaint, &rcPaint);
+ }
+ else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
+ {
+ GuiPaintGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)ActiveBuffer,
+ GuiData, &ps.rcPaint, &rcPaint);
+ }
+
+ /* Send it to screen */
+ BitBlt(ps.hdc,
+ ps.rcPaint.left,
+ ps.rcPaint.top,
+ rcPaint.right - rcPaint.left,
+ rcPaint.bottom - rcPaint.top,
+ GuiData->hMemDC,
+ rcPaint.left,
+ rcPaint.top,
+ SRCCOPY);
+
+ /* Draw the selection region if needed */
+ if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
+ {
+ PaintSelectionRect(GuiData, &ps);
+ }
+
+ LeaveCriticalSection(&GuiData->Lock);
+ }
+ EndPaint(GuiData->hWindow, &ps);
+
+ return;
+}
+
+static VOID
+OnPaletteChanged(PGUI_CONSOLE_DATA GuiData)
+{
+ PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
+
+ // See WM_PALETTECHANGED message
+ // if ((HWND)wParam == hWnd) break;
+
+ // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
+ if (ActiveBuffer->PaletteHandle)
+ {
+ DPRINT("WM_PALETTECHANGED changing palette\n");
+
+ /* Specify the use of the system palette for the framebuffer */
+ SetSystemPaletteUse(GuiData->hMemDC, ActiveBuffer->PaletteUsage);
+
+ /* Realize the (logical) palette */
+ RealizePalette(GuiData->hMemDC);
+ }
+}
+
+static BOOL
+IsSystemKey(WORD VirtualKeyCode)
+{
+ switch (VirtualKeyCode)
+ {
+ /* From MSDN, "Virtual-Key Codes" */
+ case VK_RETURN:
+ case VK_SHIFT:
+ case VK_CONTROL:
+ case VK_MENU:
+ case VK_PAUSE:
+ case VK_CAPITAL:
+ case VK_ESCAPE:
+ case VK_LWIN:
+ case VK_RWIN:
+ case VK_NUMLOCK:
+ case VK_SCROLL:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static VOID
+OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ PCONSRV_CONSOLE Console = GuiData->Console;
+ PCONSOLE_SCREEN_BUFFER ActiveBuffer;
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
+ ActiveBuffer = GuiData->ActiveBuffer;
+
+ if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS)
+ {
+ WORD VirtualKeyCode = LOWORD(wParam);
+
+ if (msg != WM_KEYDOWN) goto Quit;
+
+ if (VirtualKeyCode == VK_RETURN)
+ {
+ /* Copy (and clear) selection if ENTER is pressed */
+ Copy(GuiData);
+ goto Quit;
+ }
+ else if ( VirtualKeyCode == VK_ESCAPE ||
+ (VirtualKeyCode == 'C' && (GetKeyState(VK_CONTROL) & 0x8000)) )
+ {
+ /* Cancel selection if ESC or Ctrl-C are pressed */
+ UpdateSelection(GuiData, NULL, NULL);
+ goto Quit;
+ }
+
+ if ((GuiData->Selection.dwFlags & CONSOLE_MOUSE_SELECTION) == 0)
+ {
+ /* Keyboard selection mode */
+ BOOL Interpreted = FALSE;
+ BOOL MajPressed = !!(GetKeyState(VK_SHIFT) & 0x8000);
+
+ switch (VirtualKeyCode)
+ {
+ case VK_LEFT:
+ {
+ Interpreted = TRUE;
+ if (GuiData->dwSelectionCursor.X > 0)
+ GuiData->dwSelectionCursor.X--;
+
+ break;
+ }
+
+ case VK_RIGHT:
+ {
+ Interpreted = TRUE;
+ if (GuiData->dwSelectionCursor.X < ActiveBuffer->ScreenBufferSize.X - 1)
+ GuiData->dwSelectionCursor.X++;
+
+ break;
+ }
+
+ case VK_UP:
+ {
+ Interpreted = TRUE;
+ if (GuiData->dwSelectionCursor.Y > 0)
+ GuiData->dwSelectionCursor.Y--;
+
+ break;
+ }
+
+ case VK_DOWN:
+ {
+ Interpreted = TRUE;
+ if (GuiData->dwSelectionCursor.Y < ActiveBuffer->ScreenBufferSize.Y - 1)
+ GuiData->dwSelectionCursor.Y++;
+
+ break;
+ }
+
+ case VK_HOME:
+ {
+ Interpreted = TRUE;
+ GuiData->dwSelectionCursor.X = 0;
+ GuiData->dwSelectionCursor.Y = 0;
+ break;
+ }
+
+ case VK_END:
+ {
+ Interpreted = TRUE;
+ GuiData->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
+ break;
+ }
+
+ case VK_PRIOR:
+ {
+ Interpreted = TRUE;
+ GuiData->dwSelectionCursor.Y -= ActiveBuffer->ViewSize.Y;
+ if (GuiData->dwSelectionCursor.Y < 0)
+ GuiData->dwSelectionCursor.Y = 0;
+
+ break;
+ }
+
+ case VK_NEXT:
+ {
+ Interpreted = TRUE;
+ GuiData->dwSelectionCursor.Y += ActiveBuffer->ViewSize.Y;
+ if (GuiData->dwSelectionCursor.Y >= ActiveBuffer->ScreenBufferSize.Y)
+ GuiData->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (Interpreted)
+ {
+ UpdateSelection(GuiData,
+ !MajPressed ? &GuiData->dwSelectionCursor : NULL,
+ &GuiData->dwSelectionCursor);
+ }
+ else if (!IsSystemKey(VirtualKeyCode))
+ {
+ /* Emit an error beep sound */
+ SendNotifyMessage(GuiData->hWindow, PM_CONSOLE_BEEP, 0, 0);
+ }
+
+ goto Quit;
+ }
+ else
+ {
+ /* Mouse selection mode */
+
+ if (!IsSystemKey(VirtualKeyCode))
+ {
+ /* Clear the selection and send the key into the input buffer */
+ UpdateSelection(GuiData, NULL, NULL);
+ }
+ else
+ {
+ goto Quit;
+ }
+ }
+ }
+
+ if ((GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) == 0)
+ {
+ MSG Message;
+
+ Message.hwnd = GuiData->hWindow;
+ Message.message = msg;
+ Message.wParam = wParam;
+ Message.lParam = lParam;
+
+ ConioProcessKey(Console, &Message);
+ }
+
+Quit:
+ LeaveCriticalSection(&Console->Lock);
+}
+
+
+// FIXME: Remove after fixing OnTimer
+VOID
+InvalidateCell(PGUI_CONSOLE_DATA GuiData,
+ SHORT x, SHORT y);
+
+static VOID
+OnTimer(PGUI_CONSOLE_DATA GuiData)
+{
+ PCONSRV_CONSOLE Console = GuiData->Console;
+ PCONSOLE_SCREEN_BUFFER Buff;
+
+ SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CURSOR_BLINK_TIME, NULL);
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
+ Buff = GuiData->ActiveBuffer;
+
+ if (GetType(Buff) == TEXTMODE_BUFFER)
+ {
+ InvalidateCell(GuiData, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+ Buff->CursorBlinkOn = !Buff->CursorBlinkOn;
+
+ if ((GuiData->OldCursor.x != Buff->CursorPosition.X) ||
+ (GuiData->OldCursor.y != Buff->CursorPosition.Y))
+ {
+ SCROLLINFO xScroll;
+ int OldScrollX = -1, OldScrollY = -1;
+ int NewScrollX = -1, NewScrollY = -1;
+
+ xScroll.cbSize = sizeof(SCROLLINFO);
+ xScroll.fMask = SIF_POS;
+ // Capture the original position of the scroll bars and save them.
+ if (GetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll)) OldScrollX = xScroll.nPos;
+ if (GetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll)) OldScrollY = xScroll.nPos;
+
+ // If we successfully got the info for the horizontal scrollbar
+ if (OldScrollX >= 0)
+ {
+ if ((Buff->CursorPosition.X < Buff->ViewOrigin.X) ||
+ (Buff->CursorPosition.X >= (Buff->ViewOrigin.X + Buff->ViewSize.X)))
+ {
+ // Handle the horizontal scroll bar
+ if (Buff->CursorPosition.X >= Buff->ViewSize.X)
+ NewScrollX = Buff->CursorPosition.X - Buff->ViewSize.X + 1;
+ else
+ NewScrollX = 0;
+ }
+ else
+ {
+ NewScrollX = OldScrollX;
+ }
+ }
+ // If we successfully got the info for the vertical scrollbar
+ if (OldScrollY >= 0)
+ {
+ if ((Buff->CursorPosition.Y < Buff->ViewOrigin.Y) ||
+ (Buff->CursorPosition.Y >= (Buff->ViewOrigin.Y + Buff->ViewSize.Y)))
+ {
+ // Handle the vertical scroll bar
+ if (Buff->CursorPosition.Y >= Buff->ViewSize.Y)
+ NewScrollY = Buff->CursorPosition.Y - Buff->ViewSize.Y + 1;
+ else
+ NewScrollY = 0;
+ }
+ else
+ {
+ NewScrollY = OldScrollY;
+ }
+ }
+
+ // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area
+ // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar
+ // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling)
+ // and their associated scrollbar is left alone.
+ if ((OldScrollX != NewScrollX) || (OldScrollY != NewScrollY))
+ {
+ Buff->ViewOrigin.X = NewScrollX;
+ Buff->ViewOrigin.Y = NewScrollY;
+ ScrollWindowEx(GuiData->hWindow,
+ (OldScrollX - NewScrollX) * GuiData->CharWidth,
+ (OldScrollY - NewScrollY) * GuiData->CharHeight,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ SW_INVALIDATE);
+ if (NewScrollX >= 0)
+ {
+ xScroll.nPos = NewScrollX;
+ SetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll, TRUE);
+ }
+ if (NewScrollY >= 0)
+ {
+ xScroll.nPos = NewScrollY;
+ SetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll, TRUE);
+ }
+ UpdateWindow(GuiData->hWindow);
+ // InvalidateRect(GuiData->hWindow, NULL, FALSE);
+ GuiData->OldCursor.x = Buff->CursorPosition.X;
+ GuiData->OldCursor.y = Buff->CursorPosition.Y;
+ }
+ }
+ }
+ else /* if (GetType(Buff) == GRAPHICS_BUFFER) */
+ {
+ }
+
+ LeaveCriticalSection(&Console->Lock);
+}
+
+static BOOL
+OnClose(PGUI_CONSOLE_DATA GuiData)
+{
+ PCONSRV_CONSOLE Console = GuiData->Console;
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+ return TRUE;
+
+ // TODO: Prompt for termination ? (Warn the user about possible apps running in this console)
+
+ /*
+ * FIXME: Windows will wait up to 5 seconds for the thread to exit.
+ * We shouldn't wait here, though, since the console lock is entered.
+ * A copy of the thread list probably needs to be made.
+ */
+ ConSrvConsoleProcessCtrlEvent(Console, 0, CTRL_CLOSE_EVENT);
+
+ LeaveCriticalSection(&Console->Lock);
+ return FALSE;
+}
+
+static LRESULT
+OnNcDestroy(HWND hWnd)
+{
+ PGUI_CONSOLE_DATA GuiData = GuiGetGuiData(hWnd);
+
+ KillTimer(hWnd, CONGUI_UPDATE_TIMER);
+ GetSystemMenu(hWnd, TRUE);
+
+ if (GuiData)
+ {
+ /* Free the terminal framebuffer */
+ if (GuiData->hMemDC ) DeleteDC(GuiData->hMemDC);
+ if (GuiData->hBitmap) DeleteObject(GuiData->hBitmap);
+ // if (GuiData->hSysPalette) DeleteObject(GuiData->hSysPalette);
+ DeleteFonts(GuiData);
+ }
+
+ /* Free the GuiData registration */
+ SetWindowLongPtrW(hWnd, GWLP_USERDATA, (DWORD_PTR)NULL);
+
+ return DefWindowProcW(hWnd, WM_NCDESTROY, 0, 0);
+}
+
+static COORD
+PointToCoord(PGUI_CONSOLE_DATA GuiData, LPARAM lParam)
+{
+ PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
+ COORD Coord;
+ UINT WidthUnit, HeightUnit;
+
+ GetScreenBufferSizeUnits(Buffer, GuiData, &WidthUnit, &HeightUnit);
+
+ Coord.X = Buffer->ViewOrigin.X + ((SHORT)LOWORD(lParam) / (int)WidthUnit );
+ Coord.Y = Buffer->ViewOrigin.Y + ((SHORT)HIWORD(lParam) / (int)HeightUnit);
+
+ /* Clip coordinate to ensure it's inside buffer */
+ if (Coord.X < 0)
+ Coord.X = 0;
+ else if (Coord.X >= Buffer->ScreenBufferSize.X)
+ Coord.X = Buffer->ScreenBufferSize.X - 1;
+
+ if (Coord.Y < 0)
+ Coord.Y = 0;
+ else if (Coord.Y >= Buffer->ScreenBufferSize.Y)
+ Coord.Y = Buffer->ScreenBufferSize.Y - 1;
+
+ return Coord;
+}
+
+static LRESULT
+OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL Err = FALSE;
+ PCONSRV_CONSOLE Console = GuiData->Console;
+
+ // FIXME: It's here that we need to check whether we has focus or not
+ // and whether we are in edit mode or not, to know if we need to deal
+ // with the mouse, or not.
+
+ if (GuiData->IgnoreNextMouseSignal)
+ {
+ if (msg != WM_LBUTTONDOWN &&
+ msg != WM_MBUTTONDOWN &&
+ msg != WM_RBUTTONDOWN)
+ {
+ /*
+ * If this mouse signal is not a button-down action
+ * then it is the last signal being ignored.
+ */
+ GuiData->IgnoreNextMouseSignal = FALSE;
+ }
+ else
+ {
+ /*
+ * This mouse signal is a button-down action.
+ * Ignore it and perform default action.
+ */
+ Err = TRUE;
+ }
+ goto Quit;
+ }
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+ {
+ Err = TRUE;
+ goto Quit;
+ }
+
+ if ( (GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) ||
+ (Console->QuickEdit) )
+ {
+ switch (msg)
+ {
+ case WM_LBUTTONDOWN:
+ {
+ /* Clear the old selection */
+ GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
+
+ /* Restart a new selection */
+ GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
+ SetCapture(GuiData->hWindow);
+ GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
+ UpdateSelection(GuiData,
+ &GuiData->dwSelectionCursor,
+ &GuiData->dwSelectionCursor);
+
+ break;
+ }
+
+ case WM_LBUTTONUP:
+ {
+ if (!(GuiData->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
+
+ // GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
+ GuiData->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN;
+ // UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
+ ReleaseCapture();
+
+ break;
+ }
+
+ case WM_LBUTTONDBLCLK:
+ {
+ PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
+
+ if (GetType(Buffer) == TEXTMODE_BUFFER)
+ {
+#define IS_WORD_SEP(c) \
+ ((c) == L'\0' || (c) == L' ' || (c) == L'\t' || (c) == L'\r' || (c) == L'\n')
+
+ PTEXTMODE_SCREEN_BUFFER TextBuffer = (PTEXTMODE_SCREEN_BUFFER)Buffer;
+ COORD cL, cR;
+ PCHAR_INFO ptrL, ptrR;
+
+ /* Starting point */
+ cL = cR = PointToCoord(GuiData, lParam);
+ ptrL = ptrR = ConioCoordToPointer(TextBuffer, cL.X, cL.Y);
+
+ /* Enlarge the selection by checking for whitespace */
+ while ((0 < cL.X) && !IS_WORD_SEP(ptrL->Char.UnicodeChar)
+ && !IS_WORD_SEP((ptrL-1)->Char.UnicodeChar))
+ {
+ --cL.X;
+ --ptrL;
+ }
+ while ((cR.X < TextBuffer->ScreenBufferSize.X - 1) &&
+ !IS_WORD_SEP(ptrR->Char.UnicodeChar) &&
+ !IS_WORD_SEP((ptrR+1)->Char.UnicodeChar))
+ {
+ ++cR.X;
+ ++ptrR;
+ }
+
+ /*
+ * Update the selection started with the single
+ * left-click that preceded this double-click.
+ */
+ GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
+ UpdateSelection(GuiData, &cL, &cR);
+
+ /* Ignore the next mouse move signal */
+ GuiData->IgnoreNextMouseSignal = TRUE;
+ }
+
+ break;
+ }
+
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONDBLCLK:
+ {
+ if (!(GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY))
+ {
+ Paste(GuiData);
+ }
+ else
+ {
+ Copy(GuiData);
+ }
+
+ /* Ignore the next mouse move signal */
+ GuiData->IgnoreNextMouseSignal = TRUE;
+ break;
+ }
+
+ case WM_MOUSEMOVE:
+ {
+ if (!(wParam & MK_LBUTTON)) break;
+ if (!(GuiData->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
+
+ // TODO: Scroll buffer to bring SelectionCursor into view
+ GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
+ UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
+
+ break;
+ }
+
+ default:
+ Err = FALSE; // TRUE;
+ break;
+ }
+ }
+ else if (Console->InputBuffer.Mode & ENABLE_MOUSE_INPUT)
+ {
+ INPUT_RECORD er;
+ WORD wKeyState = GET_KEYSTATE_WPARAM(wParam);
+ DWORD dwButtonState = 0;
+ DWORD dwControlKeyState = 0;
+ DWORD dwEventFlags = 0;
+
+ switch (msg)
+ {
+ case WM_LBUTTONDOWN:
+ SetCapture(GuiData->hWindow);
+ dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED;
+ dwEventFlags = 0;
+ break;
+
+ case WM_MBUTTONDOWN:
+ SetCapture(GuiData->hWindow);
+ dwButtonState = FROM_LEFT_2ND_BUTTON_PRESSED;
+ dwEventFlags = 0;
+ break;
+
+ case WM_RBUTTONDOWN:
+ SetCapture(GuiData->hWindow);
+ dwButtonState = RIGHTMOST_BUTTON_PRESSED;
+ dwEventFlags = 0;
+ break;
+
+ case WM_LBUTTONUP:
+ ReleaseCapture();
+ dwButtonState = 0;
+ dwEventFlags = 0;
+ break;
+
+ case WM_MBUTTONUP:
+ ReleaseCapture();
+ dwButtonState = 0;
+ dwEventFlags = 0;
+ break;
+
+ case WM_RBUTTONUP:
+ ReleaseCapture();
+ dwButtonState = 0;
+ dwEventFlags = 0;
+ break;
+
+ case WM_LBUTTONDBLCLK:
+ dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED;
+ dwEventFlags = DOUBLE_CLICK;
+ break;
+
+ case WM_MBUTTONDBLCLK:
+ dwButtonState = FROM_LEFT_2ND_BUTTON_PRESSED;
+ dwEventFlags = DOUBLE_CLICK;
+ break;
+
+ case WM_RBUTTONDBLCLK:
+ dwButtonState = RIGHTMOST_BUTTON_PRESSED;
+ dwEventFlags = DOUBLE_CLICK;
+ break;
+
+ case WM_MOUSEMOVE:
+ dwButtonState = 0;
+ dwEventFlags = MOUSE_MOVED;
+ break;
+
+ case WM_MOUSEWHEEL:
+ dwButtonState = GET_WHEEL_DELTA_WPARAM(wParam) << 16;
+ dwEventFlags = MOUSE_WHEELED;
+ break;
+
+ case WM_MOUSEHWHEEL:
+ dwButtonState = GET_WHEEL_DELTA_WPARAM(wParam) << 16;
+ dwEventFlags = MOUSE_HWHEELED;
+ break;
+
+ default:
+ Err = TRUE;
+ break;
+ }
+
+ /*
+ * HACK FOR CORE-8394: Ignore the next mouse move signal
+ * just after mouse down click actions.
+ */
+ switch (msg)
+ {
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ GuiData->IgnoreNextMouseSignal = TRUE;
+ default:
+ break;
+ }
+
+ if (!Err)
+ {
+ if (wKeyState & MK_LBUTTON)
+ dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
+ if (wKeyState & MK_MBUTTON)
+ dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
+ if (wKeyState & MK_RBUTTON)
+ dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
+
+ if (GetKeyState(VK_RMENU) & 0x8000)
+ dwControlKeyState |= RIGHT_ALT_PRESSED;
+ if (GetKeyState(VK_LMENU) & 0x8000)
+ dwControlKeyState |= LEFT_ALT_PRESSED;
+ if (GetKeyState(VK_RCONTROL) & 0x8000)
+ dwControlKeyState |= RIGHT_CTRL_PRESSED;
+ if (GetKeyState(VK_LCONTROL) & 0x8000)
+ dwControlKeyState |= LEFT_CTRL_PRESSED;
+ if (GetKeyState(VK_SHIFT) & 0x8000)
+ dwControlKeyState |= SHIFT_PRESSED;
+ if (GetKeyState(VK_NUMLOCK) & 0x0001)
+ dwControlKeyState |= NUMLOCK_ON;
+ if (GetKeyState(VK_SCROLL) & 0x0001)
+ dwControlKeyState |= SCROLLLOCK_ON;
+ if (GetKeyState(VK_CAPITAL) & 0x0001)
+ dwControlKeyState |= CAPSLOCK_ON;
+ /* See WM_CHAR MSDN documentation for instance */
+ if (lParam & 0x01000000)
+ dwControlKeyState |= ENHANCED_KEY;
+
+ er.EventType = MOUSE_EVENT;
+ er.Event.MouseEvent.dwMousePosition = PointToCoord(GuiData, lParam);
+ er.Event.MouseEvent.dwButtonState = dwButtonState;
+ er.Event.MouseEvent.dwControlKeyState = dwControlKeyState;
+ er.Event.MouseEvent.dwEventFlags = dwEventFlags;
+
+ ConioProcessInputEvent(Console, &er);
+ }
+ }
+ else
+ {
+ Err = TRUE;
+ }
+
+ LeaveCriticalSection(&Console->Lock);
+
+Quit:
+ if (Err)
+ return DefWindowProcW(GuiData->hWindow, msg, wParam, lParam);
+ else
+ return 0;
+}
+
+VOID
+GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
+ PGUI_CONSOLE_DATA GuiData);
+VOID
+GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
+ PGUI_CONSOLE_DATA GuiData);
+
+static VOID
+Copy(PGUI_CONSOLE_DATA GuiData)
+{
- if (OpenClipboard(GuiData->hWindow) == TRUE)
++ if (OpenClipboard(GuiData->hWindow))
+ {
+ PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
+
+ if (GetType(Buffer) == TEXTMODE_BUFFER)
+ {
+ GuiCopyFromTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)Buffer, GuiData);
+ }
+ else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
+ {
+ GuiCopyFromGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer, GuiData);
+ }
+
+ CloseClipboard();
+ }
+
+ /* Clear the selection */
+ UpdateSelection(GuiData, NULL, NULL);
+}
+
+VOID
+GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
+ PGUI_CONSOLE_DATA GuiData);
+VOID
+GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
+ PGUI_CONSOLE_DATA GuiData);
+
+static VOID
+Paste(PGUI_CONSOLE_DATA GuiData)
+{
++ if (OpenClipboard(GuiData->hWindow))
+ {
+ PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
+
+ if (GetType(Buffer) == TEXTMODE_BUFFER)
+ {
+ GuiPasteToTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)Buffer, GuiData);
+ }
+ else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
+ {
+ GuiPasteToGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer, GuiData);
+ }
+
+ CloseClipboard();
+ }
+}
+
+static VOID
+OnGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
+{
+ PCONSRV_CONSOLE Console = GuiData->Console;
+ PCONSOLE_SCREEN_BUFFER ActiveBuffer;
+ DWORD windx, windy;
+ UINT WidthUnit, HeightUnit;
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
+ ActiveBuffer = GuiData->ActiveBuffer;
+
+ GetScreenBufferSizeUnits(ActiveBuffer, GuiData, &WidthUnit, &HeightUnit);
+
+ windx = CONGUI_MIN_WIDTH * WidthUnit + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
+ windy = CONGUI_MIN_HEIGHT * HeightUnit + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
+
+ minMaxInfo->ptMinTrackSize.x = windx;
+ minMaxInfo->ptMinTrackSize.y = windy;
+
+ windx = (ActiveBuffer->ScreenBufferSize.X) * WidthUnit + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
+ windy = (ActiveBuffer->ScreenBufferSize.Y) * HeightUnit + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
+
+ if (ActiveBuffer->ViewSize.X < ActiveBuffer->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
+ if (ActiveBuffer->ViewSize.Y < ActiveBuffer->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
+
+ minMaxInfo->ptMaxTrackSize.x = windx;
+ minMaxInfo->ptMaxTrackSize.y = windy;
+
+ LeaveCriticalSection(&Console->Lock);
+}
+
+static VOID
+OnSize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
+{
+ PCONSRV_CONSOLE Console = GuiData->Console;
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
+ if ((GuiData->WindowSizeLock == FALSE) &&
+ (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED))
+ {
+ PCONSOLE_SCREEN_BUFFER Buff = GuiData->ActiveBuffer;
+ DWORD windx, windy, charx, chary;
+ UINT WidthUnit, HeightUnit;
+
+ GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
+
+ GuiData->WindowSizeLock = TRUE;
+
+ windx = LOWORD(lParam);
+ windy = HIWORD(lParam);
+
+ // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
+ if (Buff->ViewSize.X < Buff->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
+ if (Buff->ViewSize.Y < Buff->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
+
+ charx = windx / (int)WidthUnit ;
+ chary = windy / (int)HeightUnit;
+
+ // Character alignment (round size up or down)
+ if ((windx % WidthUnit ) >= (WidthUnit / 2)) ++charx;
+ if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary;
+
+ // Compensate for added scroll bars in new window
+ if (charx < Buff->ScreenBufferSize.X) windy -= GetSystemMetrics(SM_CYHSCROLL); // new window will have a horizontal scroll bar
+ if (chary < Buff->ScreenBufferSize.Y) windx -= GetSystemMetrics(SM_CXVSCROLL); // new window will have a vertical scroll bar
+
+ charx = windx / (int)WidthUnit ;
+ chary = windy / (int)HeightUnit;
+
+ // Character alignment (round size up or down)
+ if ((windx % WidthUnit ) >= (WidthUnit / 2)) ++charx;
+ if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary;
+
+ // Resize window
+ if ((charx != Buff->ViewSize.X) || (chary != Buff->ViewSize.Y))
+ {
+ Buff->ViewSize.X = (charx <= Buff->ScreenBufferSize.X) ? charx : Buff->ScreenBufferSize.X;
+ Buff->ViewSize.Y = (chary <= Buff->ScreenBufferSize.Y) ? chary : Buff->ScreenBufferSize.Y;
+ }
+
+ ResizeConWnd(GuiData, WidthUnit, HeightUnit);
+
+ // Adjust the start of the visible area if we are attempting to show nonexistent areas
+ if ((Buff->ScreenBufferSize.X - Buff->ViewOrigin.X) < Buff->ViewSize.X) Buff->ViewOrigin.X = Buff->ScreenBufferSize.X - Buff->ViewSize.X;
+ if ((Buff->ScreenBufferSize.Y - Buff->ViewOrigin.Y) < Buff->ViewSize.Y) Buff->ViewOrigin.Y = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y;
+ InvalidateRect(GuiData->hWindow, NULL, TRUE);
+
+ GuiData->WindowSizeLock = FALSE;
+ }
+
+ LeaveCriticalSection(&Console->Lock);
+}
+
+static VOID
+OnMove(PGUI_CONSOLE_DATA GuiData)
+{
+ RECT rcWnd;
+
+ // TODO: Simplify the code.
+ // See: GuiConsoleNotifyWndProc() PM_CREATE_CONSOLE.
+
+ /* Retrieve our real position */
+ GetWindowRect(GuiData->hWindow, &rcWnd);
+ GuiData->GuiInfo.WindowOrigin.x = rcWnd.left;
+ GuiData->GuiInfo.WindowOrigin.y = rcWnd.top;
+}
+
+/*
+// HACK: This functionality is standard for general scrollbars. Don't add it by hand.
+
+VOID
+GuiConsoleHandleScrollbarMenu(VOID)
+{
+ HMENU hMenu;
+
+ hMenu = CreatePopupMenu();
+ if (hMenu == NULL)
+ {
+ DPRINT("CreatePopupMenu failed\n");
+ return;
+ }
+
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
+ //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
+ //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
+ //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
+}
+*/
+
+static LRESULT
+OnScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
+{
+ PCONSRV_CONSOLE Console = GuiData->Console;
+ PCONSOLE_SCREEN_BUFFER Buff;
+ SCROLLINFO sInfo;
+ int fnBar;
+ int old_pos, Maximum;
+ PSHORT pShowXY;
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return 0;
+
+ Buff = GuiData->ActiveBuffer;
+
+ if (uMsg == WM_HSCROLL)
+ {
+ fnBar = SB_HORZ;
+ Maximum = Buff->ScreenBufferSize.X - Buff->ViewSize.X;
+ pShowXY = &Buff->ViewOrigin.X;
+ }
+ else
+ {
+ fnBar = SB_VERT;
+ Maximum = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y;
+ pShowXY = &Buff->ViewOrigin.Y;
+ }
+
+ /* set scrollbar sizes */
+ sInfo.cbSize = sizeof(SCROLLINFO);
+ sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
+
+ if (!GetScrollInfo(GuiData->hWindow, fnBar, &sInfo)) goto Quit;
+
+ old_pos = sInfo.nPos;
+
+ switch (LOWORD(wParam))
+ {
+ case SB_LINELEFT:
+ sInfo.nPos -= 1;
+ break;
+
+ case SB_LINERIGHT:
+ sInfo.nPos += 1;
+ break;
+
+ case SB_PAGELEFT:
+ sInfo.nPos -= sInfo.nPage;
+ break;
+
+ case SB_PAGERIGHT:
+ sInfo.nPos += sInfo.nPage;
+ break;
+
+ case SB_THUMBTRACK:
+ sInfo.nPos = sInfo.nTrackPos;
+ ConioPause(Console, PAUSED_FROM_SCROLLBAR);
+ break;
+
+ case SB_THUMBPOSITION:
+ ConioUnpause(Console, PAUSED_FROM_SCROLLBAR);
+ break;
+
+ case SB_TOP:
+ sInfo.nPos = sInfo.nMin;
+ break;
+
+ case SB_BOTTOM:
+ sInfo.nPos = sInfo.nMax;
+ break;
+
+ default:
+ break;
+ }
+
+ sInfo.nPos = max(sInfo.nPos, 0);
+ sInfo.nPos = min(sInfo.nPos, Maximum);
+
+ if (old_pos != sInfo.nPos)
+ {
+ USHORT OldX = Buff->ViewOrigin.X;
+ USHORT OldY = Buff->ViewOrigin.Y;
+ UINT WidthUnit, HeightUnit;
+
+ *pShowXY = sInfo.nPos;
+
+ GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
+
+ ScrollWindowEx(GuiData->hWindow,
+ (OldX - Buff->ViewOrigin.X) * WidthUnit ,
+ (OldY - Buff->ViewOrigin.Y) * HeightUnit,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ SW_INVALIDATE);
+
+ sInfo.fMask = SIF_POS;
+ SetScrollInfo(GuiData->hWindow, fnBar, &sInfo, TRUE);
+
+ UpdateWindow(GuiData->hWindow);
+ // InvalidateRect(GuiData->hWindow, NULL, FALSE);
+ }
+
+Quit:
+ LeaveCriticalSection(&Console->Lock);
+ return 0;
+}
+
+
+static LRESULT CALLBACK
+ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT Result = 0;
+ PGUI_CONSOLE_DATA GuiData = NULL;
+ PCONSRV_CONSOLE Console = NULL;
+
+ /*
+ * - If it's the first time we create a window for the terminal,
+ * just initialize it and return.
+ *
+ * - If we are destroying the window, just do it and return.
+ */
+ if (msg == WM_NCCREATE)
+ {
+ return (LRESULT)OnNcCreate(hWnd, (LPCREATESTRUCTW)lParam);
+ }
+ else if (msg == WM_NCDESTROY)
+ {
+ return OnNcDestroy(hWnd);
+ }
+
+ /*
+ * Now the terminal window is initialized.
+ * Get the terminal data via the window's data.
+ * If there is no data, just go away.
+ */
+ GuiData = GuiGetGuiData(hWnd);
+ if (GuiData == NULL) return DefWindowProcW(hWnd, msg, wParam, lParam);
+
+ // TEMPORARY HACK until all of the functions can deal with a NULL GuiData->ActiveBuffer ...
+ if (GuiData->ActiveBuffer == NULL) return DefWindowProcW(hWnd, msg, wParam, lParam);
+
+ /*
+ * Just retrieve a pointer to the console in case somebody needs it.
+ * It is not NULL because it was checked in GuiGetGuiData.
+ * Each helper function which needs the console has to validate and lock it.
+ */
+ Console = GuiData->Console;
+
+ /* We have a console, start message dispatching */
+ switch (msg)
+ {
+ case WM_ACTIVATE:
+ OnActivate(GuiData, wParam);
+ break;
+
+ case WM_CLOSE:
+ if (OnClose(GuiData)) goto Default;
+ break;
+
+ case WM_PAINT:
+ OnPaint(GuiData);
+ break;
+
+ case WM_TIMER:
+ OnTimer(GuiData);
+ break;
+
+ case WM_PALETTECHANGED:
+ {
+ DPRINT("WM_PALETTECHANGED called\n");
+
+ /*
+ * Protects against infinite loops:
+ * "... A window that receives this message must not realize
+ * its palette, unless it determines that wParam does not contain
+ * its own window handle." (WM_PALETTECHANGED description - MSDN)
+ *
+ * This message is sent to all windows, including the one that
+ * changed the system palette and caused this message to be sent.
+ * The wParam of this message contains the handle of the window
+ * that caused the system palette to change. To avoid an infinite
+ * loop, care must be taken to check that the wParam of this message
+ * does not match the window's handle.
+ */
+ if ((HWND)wParam == hWnd) break;
+
+ DPRINT("WM_PALETTECHANGED ok\n");
+ OnPaletteChanged(GuiData);
+ DPRINT("WM_PALETTECHANGED quit\n");
+ break;
+ }
+
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_CHAR:
+ case WM_DEADCHAR:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ case WM_SYSCHAR:
+ case WM_SYSDEADCHAR:
+ {
+ /* Detect Alt-Enter presses and switch back and forth to fullscreen mode */
+ if (msg == WM_SYSKEYDOWN && (HIWORD(lParam) & KF_ALTDOWN) && wParam == VK_RETURN)
+ {
+ /* Switch only at first Alt-Enter press, and ignore subsequent key repetitions */
+ if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT)
+ GuiConsoleSwitchFullScreen(GuiData);
+
+ break;
+ }
+ /* Detect Alt-Esc/Space/Tab presses defer to DefWindowProc */
+ if ( (HIWORD(lParam) & KF_ALTDOWN) && (wParam == VK_ESCAPE || wParam == VK_SPACE || wParam == VK_TAB))
+ {
+ return DefWindowProcW(hWnd, msg, wParam, lParam);
+ }
+
+ OnKey(GuiData, msg, wParam, lParam);
+ break;
+ }
+
+ case WM_SETCURSOR:
+ {
+ /*
+ * The message was sent because we are manually triggering a change.
+ * Check whether the mouse is indeed present on this console window
+ * and take appropriate decisions.
+ */
+ if (wParam == -1 && lParam == -1)
+ {
+ POINT mouseCoords;
+ HWND hWndHit;
+
+ /* Get the placement of the mouse */
+ GetCursorPos(&mouseCoords);
+
+ /* On which window is placed the mouse ? */
+ hWndHit = WindowFromPoint(mouseCoords);
+
+ /* It's our window. Perform the hit-test to be used later on. */
+ if (hWndHit == hWnd)
+ {
+ wParam = (WPARAM)hWnd;
+ lParam = DefWindowProcW(hWndHit, WM_NCHITTEST, 0,
+ MAKELPARAM(mouseCoords.x, mouseCoords.y));
+ }
+ }
+
+ /* Set the mouse cursor only when we are in the client area */
+ if ((HWND)wParam == hWnd && LOWORD(lParam) == HTCLIENT)
+ {
+ if (GuiData->MouseCursorRefCount >= 0)
+ {
+ /* Show the cursor */
+ SetCursor(GuiData->hCursor);
+ }
+ else
+ {
+ /* Hide the cursor if the reference count is negative */
+ SetCursor(NULL);
+ }
+ return TRUE;
+ }
+ else
+ {
+ goto Default;
+ }
+ }
+
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_MOUSEMOVE:
+ case WM_MOUSEWHEEL:
+ case WM_MOUSEHWHEEL:
+ {
+ Result = OnMouse(GuiData, msg, wParam, lParam);
+ break;
+ }
+
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ {
+ Result = OnScroll(GuiData, msg, wParam);
+ break;
+ }
+
+ case WM_CONTEXTMENU:
+ {
+ if (DefWindowProcW(hWnd /*GuiData->hWindow*/, WM_NCHITTEST, 0, lParam) == HTCLIENT)
+ {
+ HMENU hMenu = CreatePopupMenu();
+ if (hMenu != NULL)
+ {
+ AppendMenuItems(hMenu, GuiConsoleEditMenuItems);
+ TrackPopupMenuEx(hMenu,
+ TPM_RIGHTBUTTON,
+ GET_X_LPARAM(lParam),
+ GET_Y_LPARAM(lParam),
+ hWnd,
+ NULL);
+ DestroyMenu(hMenu);
+ }
+ break;
+ }
+ else
+ {
+ goto Default;
+ }
+ }
+
+ case WM_INITMENU:
+ {
+ HMENU hMenu = (HMENU)wParam;
+ if (hMenu != NULL)
+ {
+ /* Enable or disable the Close menu item */
+ EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND |
+ (GuiData->IsCloseButtonEnabled ? MF_ENABLED : MF_GRAYED));
+
+ /* Enable or disable the Copy and Paste items */
+ EnableMenuItem(hMenu, ID_SYSTEM_EDIT_COPY , MF_BYCOMMAND |
+ ((GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
+ (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY) ? MF_ENABLED : MF_GRAYED));
+ // FIXME: Following whether the active screen buffer is text-mode
+ // or graphics-mode, search for CF_UNICODETEXT or CF_BITMAP formats.
+ EnableMenuItem(hMenu, ID_SYSTEM_EDIT_PASTE, MF_BYCOMMAND |
+ (!(GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
+ IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED));
+ }
+
+ SendMenuEvent(Console, WM_INITMENU);
+ break;
+ }
+
+ case WM_MENUSELECT:
+ {
+ if (HIWORD(wParam) == 0xFFFF) // Allow all the menu flags
+ {
+ SendMenuEvent(Console, WM_MENUSELECT);
+ }
+ break;
+ }
+
+ case WM_COMMAND:
+ case WM_SYSCOMMAND:
+ {
+ Result = OnCommand(GuiData, wParam, lParam);
+ break;
+ }
+
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ OnFocus(GuiData, (msg == WM_SETFOCUS));
+ break;
+
+ case WM_GETMINMAXINFO:
+ OnGetMinMaxInfo(GuiData, (PMINMAXINFO)lParam);
+ break;
+
+ case WM_MOVE:
+ OnMove(GuiData);
+ break;
+
+#if 0 // This code is here to prepare & control dynamic console SB resizing.
+ case WM_SIZING:
+ {
+ PRECT dragRect = (PRECT)lParam;
+ switch (wParam)
+ {
+ case WMSZ_LEFT:
+ DPRINT1("WMSZ_LEFT\n");
+ break;
+ case WMSZ_RIGHT:
+ DPRINT1("WMSZ_RIGHT\n");
+ break;
+ case WMSZ_TOP:
+ DPRINT1("WMSZ_TOP\n");
+ break;
+ case WMSZ_TOPLEFT:
+ DPRINT1("WMSZ_TOPLEFT\n");
+ break;
+ case WMSZ_TOPRIGHT:
+ DPRINT1("WMSZ_TOPRIGHT\n");
+ break;
+ case WMSZ_BOTTOM:
+ DPRINT1("WMSZ_BOTTOM\n");
+ break;
+ case WMSZ_BOTTOMLEFT:
+ DPRINT1("WMSZ_BOTTOMLEFT\n");
+ break;
+ case WMSZ_BOTTOMRIGHT:
+ DPRINT1("WMSZ_BOTTOMRIGHT\n");
+ break;
+ default:
+ DPRINT1("wParam = %d\n", wParam);
+ break;
+ }
+ DPRINT1("dragRect = {.left = %d ; .top = %d ; .right = %d ; .bottom = %d}\n",
+ dragRect->left, dragRect->top, dragRect->right, dragRect->bottom);
+ break;
+ }
+#endif
+
+ case WM_SIZE:
+ OnSize(GuiData, wParam, lParam);
+ break;
+
+ case PM_RESIZE_TERMINAL:
+ {
+ PCONSOLE_SCREEN_BUFFER Buff = GuiData->ActiveBuffer;
+ HDC hDC;
+ HBITMAP hnew, hold;
+
+ DWORD Width, Height;
+ UINT WidthUnit, HeightUnit;
+
+ GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
+
+ Width = Buff->ScreenBufferSize.X * WidthUnit ;
+ Height = Buff->ScreenBufferSize.Y * HeightUnit;
+
+ /* Recreate the framebuffer */
+ hDC = GetDC(GuiData->hWindow);
+ hnew = CreateCompatibleBitmap(hDC, Width, Height);
+ ReleaseDC(GuiData->hWindow, hDC);
+ hold = SelectObject(GuiData->hMemDC, hnew);
+ if (GuiData->hBitmap)
+ {
+ if (hold == GuiData->hBitmap) DeleteObject(GuiData->hBitmap);
+ }
+ GuiData->hBitmap = hnew;
+
+ /* Resize the window to the user's values */
+ GuiData->WindowSizeLock = TRUE;
+ ResizeConWnd(GuiData, WidthUnit, HeightUnit);
+ GuiData->WindowSizeLock = FALSE;
+ break;
+ }
+
+ case PM_APPLY_CONSOLE_INFO:
+ {
+ GuiApplyUserSettings(GuiData, (HANDLE)wParam, (BOOL)lParam);
+ break;
+ }
+
+ /*
+ * Undocumented message sent by Windows' console.dll for applying console info.
+ * See http://www.catch22.net/sites/default/source/files/setconsoleinfo.c
+ * and http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf
+ * for more information.
+ */
+ case WM_SETCONSOLEINFO:
+ {
+ DPRINT1("WM_SETCONSOLEINFO message\n");
+ GuiApplyWindowsConsoleSettings(GuiData, (HANDLE)wParam);
+ break;
+ }
+
+ case PM_CONSOLE_BEEP:
+ DPRINT1("Beep\n");
+ Beep(800, 200);
+ break;
+
+ // case PM_CONSOLE_SET_TITLE:
+ // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
+ // break;
+
+ default: Default:
+ Result = DefWindowProcW(hWnd, msg, wParam, lParam);
+ break;
+ }
+
+ return Result;
+}
+
+/* EOF */
--- /dev/null
- if (OpenClipboard(GuiData->hWindow) == TRUE)
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Console Server DLL
+ * FILE: win32ss/user/winsrv/consrv/frontends/gui/guiterm.c
+ * PURPOSE: GUI Terminal Front-End
+ * PROGRAMMERS: Gé van Geldorp
+ * Johannes Anderwald
+ * Jeffrey Morlan
+ * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
+ */
+
+/* INCLUDES *******************************************************************/
+
+#define COBJMACROS
+#define NONAMELESSUNION
+
+#include "consrv.h"
+#include "include/conio.h"
+#include "include/console.h"
+#include "include/settings.h"
+#include "conoutput.h"
+#include "guiterm.h"
+#include "guisettings.h"
+#include "resource.h"
+
+#include <windowsx.h>
+
+#include <shlwapi.h>
+#include <shlobj.h>
+
+#define NDEBUG
+#include <debug.h>
+
+/* GUI Console Window Class name */
+#define GUI_CONSOLE_WINDOW_CLASS L"ConsoleWindowClass"
+
+#ifndef WM_APP
+ #define WM_APP 0x8000
+#endif
+#define PM_CREATE_CONSOLE (WM_APP + 1)
+#define PM_DESTROY_CONSOLE (WM_APP + 2)
+#define PM_RESIZE_TERMINAL (WM_APP + 3)
+#define PM_CONSOLE_BEEP (WM_APP + 4)
+#define PM_CONSOLE_SET_TITLE (WM_APP + 5)
+
+
+/* Not defined in any header file */
+extern VOID WINAPI PrivateCsrssManualGuiCheck(LONG Check);
+// See winsrv/usersrv/init.c line 234
+
+
+/* GLOBALS ********************************************************************/
+
+typedef struct _GUI_INIT_INFO
+{
+ PCONSOLE_INFO ConsoleInfo;
+ PCONSOLE_START_INFO ConsoleStartInfo;
+ ULONG ProcessId;
+} GUI_INIT_INFO, *PGUI_INIT_INFO;
+
+/**************************************************************\
+\** Define the Console Leader Process for the console window **/
+#define GWLP_CONSOLEWND_ALLOC (2 * sizeof(LONG_PTR))
+#define GWLP_CONSOLE_LEADER_PID 0
+#define GWLP_CONSOLE_LEADER_TID 4
+
+#define SetConsoleWndConsoleLeaderCID(GuiData) \
+do { \
+ PCONSOLE_PROCESS_DATA ProcessData; \
+ CLIENT_ID ConsoleLeaderCID; \
+ ProcessData = CONTAINING_RECORD((GuiData)->Console->ProcessList.Blink, \
+ CONSOLE_PROCESS_DATA, \
+ ConsoleLink); \
+ ConsoleLeaderCID = ProcessData->Process->ClientId; \
+ SetWindowLongPtrW((GuiData)->hWindow, GWLP_CONSOLE_LEADER_PID, (LONG_PTR)(ConsoleLeaderCID.UniqueProcess)); \
+ SetWindowLongPtrW((GuiData)->hWindow, GWLP_CONSOLE_LEADER_TID, (LONG_PTR)(ConsoleLeaderCID.UniqueThread )); \
+} while (0)
+/**************************************************************/
+
+static BOOL ConsInitialized = FALSE;
+static HICON ghDefaultIcon = NULL;
+static HICON ghDefaultIconSm = NULL;
+static HCURSOR ghDefaultCursor = NULL;
+static HWND NotifyWnd = NULL;
+
+typedef struct _GUICONSOLE_MENUITEM
+{
+ UINT uID;
+ const struct _GUICONSOLE_MENUITEM *SubMenu;
+ WORD wCmdID;
+} GUICONSOLE_MENUITEM, *PGUICONSOLE_MENUITEM;
+
+static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems[] =
+{
+ { IDS_MARK, NULL, ID_SYSTEM_EDIT_MARK },
+ { IDS_COPY, NULL, ID_SYSTEM_EDIT_COPY },
+ { IDS_PASTE, NULL, ID_SYSTEM_EDIT_PASTE },
+ { IDS_SELECTALL, NULL, ID_SYSTEM_EDIT_SELECTALL },
+ { IDS_SCROLL, NULL, ID_SYSTEM_EDIT_SCROLL },
+ { IDS_FIND, NULL, ID_SYSTEM_EDIT_FIND },
+
+ { 0, NULL, 0 } /* End of list */
+};
+
+static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems[] =
+{
+ { IDS_EDIT, GuiConsoleEditMenuItems, 0 },
+ { IDS_DEFAULTS, NULL, ID_SYSTEM_DEFAULTS },
+ { IDS_PROPERTIES, NULL, ID_SYSTEM_PROPERTIES },
+
+ { 0, NULL, 0 } /* End of list */
+};
+
+/*
+ * Default 16-color palette for foreground and background
+ * (corresponding flags in comments).
+ */
+const COLORREF s_Colors[16] =
+{
+ RGB(0, 0, 0), // (Black)
+ RGB(0, 0, 128), // BLUE
+ RGB(0, 128, 0), // GREEN
+ RGB(0, 128, 128), // BLUE | GREEN
+ RGB(128, 0, 0), // RED
+ RGB(128, 0, 128), // BLUE | RED
+ RGB(128, 128, 0), // GREEN | RED
+ RGB(192, 192, 192), // BLUE | GREEN | RED
+
+ RGB(128, 128, 128), // (Grey) INTENSITY
+ RGB(0, 0, 255), // BLUE | INTENSITY
+ RGB(0, 255, 0), // GREEN | INTENSITY
+ RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
+ RGB(255, 0, 0), // RED | INTENSITY
+ RGB(255, 0, 255), // BLUE | RED | INTENSITY
+ RGB(255, 255, 0), // GREEN | RED | INTENSITY
+ RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
+};
+
+/* FUNCTIONS ******************************************************************/
+
+static VOID
+GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer,
+ IN PGUI_CONSOLE_DATA GuiData,
+ OUT PUINT WidthUnit,
+ OUT PUINT HeightUnit)
+{
+ if (Buffer == NULL || GuiData == NULL ||
+ WidthUnit == NULL || HeightUnit == NULL)
+ {
+ return;
+ }
+
+ if (GetType(Buffer) == TEXTMODE_BUFFER)
+ {
+ *WidthUnit = GuiData->CharWidth ;
+ *HeightUnit = GuiData->CharHeight;
+ }
+ else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
+ {
+ *WidthUnit = 1;
+ *HeightUnit = 1;
+ }
+}
+
+
+
+static VOID
+GuiConsoleAppendMenuItems(HMENU hMenu,
+ const GUICONSOLE_MENUITEM *Items)
+{
+ UINT i = 0;
+ WCHAR szMenuString[255];
+ HMENU hSubMenu;
+
+ do
+ {
+ if (Items[i].uID != (UINT)-1)
+ {
+ if (LoadStringW(ConSrvDllInstance,
+ Items[i].uID,
+ szMenuString,
+ sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
+ {
+ if (Items[i].SubMenu != NULL)
+ {
+ hSubMenu = CreatePopupMenu();
+ if (hSubMenu != NULL)
+ {
+ GuiConsoleAppendMenuItems(hSubMenu,
+ Items[i].SubMenu);
+
+ if (!AppendMenuW(hMenu,
+ MF_STRING | MF_POPUP,
+ (UINT_PTR)hSubMenu,
+ szMenuString))
+ {
+ DestroyMenu(hSubMenu);
+ }
+ }
+ }
+ else
+ {
+ AppendMenuW(hMenu,
+ MF_STRING,
+ Items[i].wCmdID,
+ szMenuString);
+ }
+ }
+ }
+ else
+ {
+ AppendMenuW(hMenu,
+ MF_SEPARATOR,
+ 0,
+ NULL);
+ }
+ i++;
+ } while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
+}
+
+static VOID
+GuiConsoleCreateSysMenu(HWND hWnd)
+{
+ HMENU hMenu = GetSystemMenu(hWnd, FALSE);
+ if (hMenu != NULL)
+ {
+ GuiConsoleAppendMenuItems(hMenu, GuiConsoleMainMenuItems);
+ DrawMenuBar(hWnd);
+ }
+}
+
+static VOID
+GuiSendMenuEvent(PCONSOLE Console, UINT CmdId)
+{
+ INPUT_RECORD er;
+
+ er.EventType = MENU_EVENT;
+ er.Event.MenuEvent.dwCommandId = CmdId;
+
+ ConioProcessInputEvent(Console, &er);
+}
+
+static VOID
+GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData);
+static VOID
+GuiConsolePaste(PGUI_CONSOLE_DATA GuiData);
+static VOID
+GuiConsoleUpdateSelection(PCONSOLE Console, PCOORD coord);
+static VOID WINAPI
+GuiDrawRegion(IN OUT PFRONTEND This, SMALL_RECT* Region);
+static VOID
+GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData);
+
+
+static LRESULT
+GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT Ret = TRUE;
+ PCONSOLE Console = GuiData->Console;
+ PCONSOLE_SCREEN_BUFFER ActiveBuffer;
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+ {
+ Ret = FALSE;
+ goto Quit;
+ }
+ ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
+
+ /*
+ * In case the selected menu item belongs to the user-reserved menu id range,
+ * send to him a menu event and return directly. The user must handle those
+ * reserved menu commands...
+ */
+ if (GuiData->cmdIdLow <= (UINT)wParam && (UINT)wParam <= GuiData->cmdIdHigh)
+ {
+ GuiSendMenuEvent(Console, (UINT)wParam);
+ goto Unlock_Quit;
+ }
+
+ /* ... otherwise, perform actions. */
+ switch (wParam)
+ {
+ case ID_SYSTEM_EDIT_MARK:
+ {
+ LPWSTR WindowTitle = NULL;
+ SIZE_T Length = 0;
+
+ Console->dwSelectionCursor.X = ActiveBuffer->ViewOrigin.X;
+ Console->dwSelectionCursor.Y = ActiveBuffer->ViewOrigin.Y;
+ Console->Selection.dwSelectionAnchor = Console->dwSelectionCursor;
+ Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS;
+ GuiConsoleUpdateSelection(Console, &Console->Selection.dwSelectionAnchor);
+
+ Length = Console->Title.Length + sizeof(L"Mark - ")/sizeof(WCHAR) + 1;
+ WindowTitle = ConsoleAllocHeap(0, Length * sizeof(WCHAR));
+ wcscpy(WindowTitle, L"Mark - ");
+ wcscat(WindowTitle, Console->Title.Buffer);
+ SetWindowText(GuiData->hWindow, WindowTitle);
+ ConsoleFreeHeap(WindowTitle);
+
+ break;
+ }
+
+ case ID_SYSTEM_EDIT_COPY:
+ GuiConsoleCopy(GuiData);
+ break;
+
+ case ID_SYSTEM_EDIT_PASTE:
+ GuiConsolePaste(GuiData);
+ break;
+
+ case ID_SYSTEM_EDIT_SELECTALL:
+ {
+ LPWSTR WindowTitle = NULL;
+ SIZE_T Length = 0;
+
+ Console->Selection.dwSelectionAnchor.X = 0;
+ Console->Selection.dwSelectionAnchor.Y = 0;
+ Console->dwSelectionCursor.X = ActiveBuffer->ViewSize.X - 1;
+ Console->dwSelectionCursor.Y = ActiveBuffer->ViewSize.Y - 1;
+ Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS | CONSOLE_MOUSE_SELECTION;
+ GuiConsoleUpdateSelection(Console, &Console->dwSelectionCursor);
+
+ Length = Console->Title.Length + sizeof(L"Selection - ")/sizeof(WCHAR) + 1;
+ WindowTitle = ConsoleAllocHeap(0, Length * sizeof(WCHAR));
+ wcscpy(WindowTitle, L"Selection - ");
+ wcscat(WindowTitle, Console->Title.Buffer);
+ SetWindowText(GuiData->hWindow, WindowTitle);
+ ConsoleFreeHeap(WindowTitle);
+
+ break;
+ }
+
+ case ID_SYSTEM_EDIT_SCROLL:
+ DPRINT1("Scrolling is not handled yet\n");
+ break;
+
+ case ID_SYSTEM_EDIT_FIND:
+ DPRINT1("Finding is not handled yet\n");
+ break;
+
+ case ID_SYSTEM_DEFAULTS:
+ GuiConsoleShowConsoleProperties(GuiData, TRUE);
+ break;
+
+ case ID_SYSTEM_PROPERTIES:
+ GuiConsoleShowConsoleProperties(GuiData, FALSE);
+ break;
+
+ default:
+ Ret = FALSE;
+ break;
+ }
+
+Unlock_Quit:
+ LeaveCriticalSection(&Console->Lock);
+Quit:
+ if (!Ret)
+ Ret = DefWindowProcW(GuiData->hWindow, WM_SYSCOMMAND, wParam, lParam);
+
+ return Ret;
+}
+
+static PGUI_CONSOLE_DATA
+GuiGetGuiData(HWND hWnd)
+{
+ /* This function ensures that the console pointer is not NULL */
+ PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
+ return ( ((GuiData == NULL) || (GuiData->hWindow == hWnd && GuiData->Console != NULL)) ? GuiData : NULL );
+}
+
+VOID
+GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData)
+{
+ /* Move the window if needed (not positioned by the system) */
+ if (!GuiData->GuiInfo.AutoPosition)
+ {
+ SetWindowPos(GuiData->hWindow,
+ NULL,
+ GuiData->GuiInfo.WindowOrigin.x,
+ GuiData->GuiInfo.WindowOrigin.y,
+ 0,
+ 0,
+ SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+ }
+}
+
+static VOID
+GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData)
+{
+ PCONSOLE Console = GuiData->Console;
+ PCONSOLE_SCREEN_BUFFER Buff = ConDrvGetActiveScreenBuffer(Console);
+ SCROLLINFO sInfo;
+
+ DWORD Width, Height;
+ UINT WidthUnit, HeightUnit;
+
+ GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
+
+ Width = Buff->ViewSize.X * WidthUnit +
+ 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
+ Height = Buff->ViewSize.Y * HeightUnit +
+ 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
+
+ /* Set scrollbar sizes */
+ sInfo.cbSize = sizeof(SCROLLINFO);
+ sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ sInfo.nMin = 0;
+ if (Buff->ScreenBufferSize.Y > Buff->ViewSize.Y)
+ {
+ sInfo.nMax = Buff->ScreenBufferSize.Y - 1;
+ sInfo.nPage = Buff->ViewSize.Y;
+ sInfo.nPos = Buff->ViewOrigin.Y;
+ SetScrollInfo(GuiData->hWindow, SB_VERT, &sInfo, TRUE);
+ Width += GetSystemMetrics(SM_CXVSCROLL);
+ ShowScrollBar(GuiData->hWindow, SB_VERT, TRUE);
+ }
+ else
+ {
+ ShowScrollBar(GuiData->hWindow, SB_VERT, FALSE);
+ }
+
+ if (Buff->ScreenBufferSize.X > Buff->ViewSize.X)
+ {
+ sInfo.nMax = Buff->ScreenBufferSize.X - 1;
+ sInfo.nPage = Buff->ViewSize.X;
+ sInfo.nPos = Buff->ViewOrigin.X;
+ SetScrollInfo(GuiData->hWindow, SB_HORZ, &sInfo, TRUE);
+ Height += GetSystemMetrics(SM_CYHSCROLL);
+ ShowScrollBar(GuiData->hWindow, SB_HORZ, TRUE);
+ }
+ else
+ {
+ ShowScrollBar(GuiData->hWindow, SB_HORZ, FALSE);
+ }
+
+ /* Resize the window */
+ SetWindowPos(GuiData->hWindow, NULL, 0, 0, Width, Height,
+ SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS);
+ // NOTE: The SWP_NOCOPYBITS flag can be replaced by a subsequent call
+ // to: InvalidateRect(GuiData->hWindow, NULL, TRUE);
+}
+
+static VOID
+GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData)
+{
+ PCONSOLE Console = GuiData->Console;
+ // DEVMODE dmScreenSettings;
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
+ /* Switch to full-screen or to windowed mode */
+ GuiData->GuiInfo.FullScreen = !GuiData->GuiInfo.FullScreen;
+ DPRINT1("GuiConsoleSwitchFullScreen - Switch to %s ...\n",
+ (GuiData->GuiInfo.FullScreen ? "full-screen" : "windowed mode"));
+
+ // TODO: Change window appearance.
+ // See:
+ // http://stackoverflow.com/questions/2382464/win32-full-screen-and-hiding-taskbar
+ // http://stackoverflow.com/questions/3549148/fullscreen-management-with-winapi
+ // http://blogs.msdn.com/b/oldnewthing/archive/2010/04/12/9994016.aspx
+ // http://stackoverflow.com/questions/1400654/how-do-i-put-my-opengl-app-into-fullscreen-mode
+ // http://nehe.gamedev.net/tutorial/creating_an_opengl_window_win32/13001/
+#if 0
+ if (GuiData->GuiInfo.FullScreen)
+ {
+ memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
+ dmScreenSettings.dmSize = sizeof(dmScreenSettings);
+ dmScreenSettings.dmDisplayFixedOutput = DMDFO_CENTER; // DMDFO_STRETCH // DMDFO_DEFAULT
+ dmScreenSettings.dmPelsWidth = 640; // Console->ActiveBuffer->ViewSize.X * GuiData->CharWidth;
+ dmScreenSettings.dmPelsHeight = 480; // Console->ActiveBuffer->ViewSize.Y * GuiData->CharHeight;
+ dmScreenSettings.dmBitsPerPel = 32;
+ dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
+ ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
+ }
+ else
+ {
+ }
+#endif
+
+ LeaveCriticalSection(&Console->Lock);
+}
+
+static BOOL
+GuiConsoleHandleNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
+{
+ PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)Create->lpCreateParams;
+ PCONSOLE Console;
+ HDC Dc;
+ HFONT OldFont;
+ TEXTMETRICW Metrics;
+ SIZE CharSize;
+
+ DPRINT("GuiConsoleHandleNcCreate\n");
+
+ if (NULL == GuiData)
+ {
+ DPRINT1("GuiConsoleNcCreate: No GUI data\n");
+ return FALSE;
+ }
+
+ Console = GuiData->Console;
+
+ GuiData->hWindow = hWnd;
+
+ GuiData->Font = CreateFontW(LOWORD(GuiData->GuiInfo.FontSize),
+ 0, // HIWORD(GuiData->GuiInfo.FontSize),
+ 0,
+ TA_BASELINE,
+ GuiData->GuiInfo.FontWeight,
+ FALSE,
+ FALSE,
+ FALSE,
+ OEM_CHARSET,
+ OUT_DEFAULT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ NONANTIALIASED_QUALITY,
+ FIXED_PITCH | GuiData->GuiInfo.FontFamily /* FF_DONTCARE */,
+ GuiData->GuiInfo.FaceName);
+
+ if (NULL == GuiData->Font)
+ {
+ DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
+ GuiData->hWindow = NULL;
+ SetEvent(GuiData->hGuiInitEvent);
+ return FALSE;
+ }
+ Dc = GetDC(GuiData->hWindow);
+ if (NULL == Dc)
+ {
+ DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
+ DeleteObject(GuiData->Font);
+ GuiData->hWindow = NULL;
+ SetEvent(GuiData->hGuiInitEvent);
+ return FALSE;
+ }
+ OldFont = SelectObject(Dc, GuiData->Font);
+ if (NULL == OldFont)
+ {
+ DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
+ ReleaseDC(GuiData->hWindow, Dc);
+ DeleteObject(GuiData->Font);
+ GuiData->hWindow = NULL;
+ SetEvent(GuiData->hGuiInitEvent);
+ return FALSE;
+ }
+ if (!GetTextMetricsW(Dc, &Metrics))
+ {
+ DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
+ SelectObject(Dc, OldFont);
+ ReleaseDC(GuiData->hWindow, Dc);
+ DeleteObject(GuiData->Font);
+ GuiData->hWindow = NULL;
+ SetEvent(GuiData->hGuiInitEvent);
+ return FALSE;
+ }
+ GuiData->CharWidth = Metrics.tmMaxCharWidth;
+ GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
+
+ /* Measure real char width more precisely if possible. */
+ if (GetTextExtentPoint32W(Dc, L"R", 1, &CharSize))
+ GuiData->CharWidth = CharSize.cx;
+
+ SelectObject(Dc, OldFont);
+
+ ReleaseDC(GuiData->hWindow, Dc);
+
+ // FIXME: Keep these instructions here ? ///////////////////////////////////
+ Console->ActiveBuffer->CursorBlinkOn = TRUE;
+ Console->ActiveBuffer->ForceCursorOff = FALSE;
+ ////////////////////////////////////////////////////////////////////////////
+
+ SetWindowLongPtrW(GuiData->hWindow, GWLP_USERDATA, (DWORD_PTR)GuiData);
+
+ SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
+ GuiConsoleCreateSysMenu(GuiData->hWindow);
+
+ DPRINT("GuiConsoleHandleNcCreate - setting start event\n");
+ SetEvent(GuiData->hGuiInitEvent);
+
+ return (BOOL)DefWindowProcW(GuiData->hWindow, WM_NCCREATE, 0, (LPARAM)Create);
+}
+
+static VOID
+SmallRectToRect(PGUI_CONSOLE_DATA GuiData, PRECT Rect, PSMALL_RECT SmallRect)
+{
+ PCONSOLE Console = GuiData->Console;
+ PCONSOLE_SCREEN_BUFFER Buffer = ConDrvGetActiveScreenBuffer(Console);
+ UINT WidthUnit, HeightUnit;
+
+ GetScreenBufferSizeUnits(Buffer, GuiData, &WidthUnit, &HeightUnit);
+
+ Rect->left = (SmallRect->Left - Buffer->ViewOrigin.X) * WidthUnit ;
+ Rect->top = (SmallRect->Top - Buffer->ViewOrigin.Y) * HeightUnit;
+ Rect->right = (SmallRect->Right + 1 - Buffer->ViewOrigin.X) * WidthUnit ;
+ Rect->bottom = (SmallRect->Bottom + 1 - Buffer->ViewOrigin.Y) * HeightUnit;
+}
+
+static VOID
+GuiConsoleUpdateSelection(PCONSOLE Console, PCOORD coord)
+{
+ PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data;
+ RECT oldRect, newRect;
+
+ SmallRectToRect(GuiData, &oldRect, &Console->Selection.srSelection);
+
+ if (coord != NULL)
+ {
+ SMALL_RECT rc;
+ /* exchange left/top with right/bottom if required */
+ rc.Left = min(Console->Selection.dwSelectionAnchor.X, coord->X);
+ rc.Top = min(Console->Selection.dwSelectionAnchor.Y, coord->Y);
+ rc.Right = max(Console->Selection.dwSelectionAnchor.X, coord->X);
+ rc.Bottom = max(Console->Selection.dwSelectionAnchor.Y, coord->Y);
+
+ SmallRectToRect(GuiData, &newRect, &rc);
+
+ if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
+ {
+ if (memcmp(&rc, &Console->Selection.srSelection, sizeof(SMALL_RECT)) != 0)
+ {
+ HRGN rgn1, rgn2;
+
+ /* calculate the region that needs to be updated */
+ if ((rgn1 = CreateRectRgnIndirect(&oldRect)))
+ {
+ if ((rgn2 = CreateRectRgnIndirect(&newRect)))
+ {
+ if (CombineRgn(rgn1, rgn2, rgn1, RGN_XOR) != ERROR)
+ {
+ InvalidateRgn(GuiData->hWindow, rgn1, FALSE);
+ }
+ DeleteObject(rgn2);
+ }
+ DeleteObject(rgn1);
+ }
+ }
+ }
+ else
+ {
+ InvalidateRect(GuiData->hWindow, &newRect, FALSE);
+ }
+ Console->Selection.dwFlags |= CONSOLE_SELECTION_NOT_EMPTY;
+ Console->Selection.srSelection = rc;
+ Console->dwSelectionCursor = *coord;
+ ConioPause(Console, PAUSED_FROM_SELECTION);
+ }
+ else
+ {
+ /* clear the selection */
+ if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
+ {
+ InvalidateRect(GuiData->hWindow, &oldRect, FALSE);
+ }
+ Console->Selection.dwFlags = CONSOLE_NO_SELECTION;
+ ConioUnpause(Console, PAUSED_FROM_SELECTION);
+ }
+}
+
+
+VOID
+GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
+ PGUI_CONSOLE_DATA GuiData,
+ HDC hDC,
+ PRECT rc);
+VOID
+GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
+ PGUI_CONSOLE_DATA GuiData,
+ HDC hDC,
+ PRECT rc);
+
+static VOID
+GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData)
+{
+ BOOL Success = TRUE;
+ PCONSOLE Console = GuiData->Console;
+ PCONSOLE_SCREEN_BUFFER ActiveBuffer;
+ HDC hDC;
+ PAINTSTRUCT ps;
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+ {
+ Success = FALSE;
+ goto Quit;
+ }
+ ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
+
+ hDC = BeginPaint(GuiData->hWindow, &ps);
+ if (hDC != NULL &&
+ ps.rcPaint.left < ps.rcPaint.right &&
+ ps.rcPaint.top < ps.rcPaint.bottom)
+ {
+ EnterCriticalSection(&GuiData->Lock);
+
+ if (GetType(ActiveBuffer) == TEXTMODE_BUFFER)
+ {
+ GuiPaintTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)ActiveBuffer,
+ GuiData, hDC, &ps.rcPaint);
+ }
+ else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
+ {
+ GuiPaintGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)ActiveBuffer,
+ GuiData, hDC, &ps.rcPaint);
+ }
+
+ if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
+ {
+ RECT rc;
+ SmallRectToRect(GuiData, &rc, &Console->Selection.srSelection);
+
+ /* invert the selection */
+ if (IntersectRect(&rc, &ps.rcPaint, &rc))
+ {
+ PatBlt(hDC,
+ rc.left,
+ rc.top,
+ rc.right - rc.left,
+ rc.bottom - rc.top,
+ DSTINVERT);
+ }
+ }
+
+ LeaveCriticalSection(&GuiData->Lock);
+ }
+ EndPaint(GuiData->hWindow, &ps);
+
+Quit:
+ if (Success)
+ LeaveCriticalSection(&Console->Lock);
+ else
+ DefWindowProcW(GuiData->hWindow, WM_PAINT, 0, 0);
+
+ return;
+}
+
+static BOOL
+IsSystemKey(WORD VirtualKeyCode)
+{
+ switch (VirtualKeyCode)
+ {
+ /* From MSDN, "Virtual-Key Codes" */
+ case VK_RETURN:
+ case VK_SHIFT:
+ case VK_CONTROL:
+ case VK_MENU:
+ case VK_PAUSE:
+ case VK_CAPITAL:
+ case VK_ESCAPE:
+ case VK_LWIN:
+ case VK_RWIN:
+ case VK_NUMLOCK:
+ case VK_SCROLL:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static VOID
+GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ PCONSOLE Console = GuiData->Console;
+ PCONSOLE_SCREEN_BUFFER ActiveBuffer;
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
+ ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
+
+ if (Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS)
+ {
+ WORD VirtualKeyCode = LOWORD(wParam);
+
+ if (msg != WM_KEYDOWN) goto Quit;
+
+ if (VirtualKeyCode == VK_RETURN)
+ {
+ /* Copy (and clear) selection if ENTER is pressed */
+ GuiConsoleCopy(GuiData);
+ goto Quit;
+ }
+ else if ( VirtualKeyCode == VK_ESCAPE ||
+ (VirtualKeyCode == 'C' && GetKeyState(VK_CONTROL) & 0x8000) )
+ {
+ /* Cancel selection if ESC or Ctrl-C are pressed */
+ GuiConsoleUpdateSelection(Console, NULL);
+ SetWindowText(GuiData->hWindow, Console->Title.Buffer);
+
+ goto Quit;
+ }
+
+ if ((Console->Selection.dwFlags & CONSOLE_MOUSE_SELECTION) == 0)
+ {
+ /* Keyboard selection mode */
+ BOOL Interpreted = FALSE;
+ BOOL MajPressed = (GetKeyState(VK_SHIFT) & 0x8000);
+
+ switch (VirtualKeyCode)
+ {
+ case VK_LEFT:
+ {
+ Interpreted = TRUE;
+ if (Console->dwSelectionCursor.X > 0)
+ Console->dwSelectionCursor.X--;
+
+ break;
+ }
+
+ case VK_RIGHT:
+ {
+ Interpreted = TRUE;
+ if (Console->dwSelectionCursor.X < ActiveBuffer->ScreenBufferSize.X - 1)
+ Console->dwSelectionCursor.X++;
+
+ break;
+ }
+
+ case VK_UP:
+ {
+ Interpreted = TRUE;
+ if (Console->dwSelectionCursor.Y > 0)
+ Console->dwSelectionCursor.Y--;
+
+ break;
+ }
+
+ case VK_DOWN:
+ {
+ Interpreted = TRUE;
+ if (Console->dwSelectionCursor.Y < ActiveBuffer->ScreenBufferSize.Y - 1)
+ Console->dwSelectionCursor.Y++;
+
+ break;
+ }
+
+ case VK_HOME:
+ {
+ Interpreted = TRUE;
+ Console->dwSelectionCursor.X = 0;
+ Console->dwSelectionCursor.Y = 0;
+ break;
+ }
+
+ case VK_END:
+ {
+ Interpreted = TRUE;
+ Console->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
+ break;
+ }
+
+ case VK_PRIOR:
+ {
+ Interpreted = TRUE;
+ Console->dwSelectionCursor.Y -= ActiveBuffer->ViewSize.Y;
+ if (Console->dwSelectionCursor.Y < 0)
+ Console->dwSelectionCursor.Y = 0;
+
+ break;
+ }
+
+ case VK_NEXT:
+ {
+ Interpreted = TRUE;
+ Console->dwSelectionCursor.Y += ActiveBuffer->ViewSize.Y;
+ if (Console->dwSelectionCursor.Y >= ActiveBuffer->ScreenBufferSize.Y)
+ Console->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (Interpreted)
+ {
+ if (!MajPressed)
+ Console->Selection.dwSelectionAnchor = Console->dwSelectionCursor;
+
+ GuiConsoleUpdateSelection(Console, &Console->dwSelectionCursor);
+ }
+ else if (!IsSystemKey(VirtualKeyCode))
+ {
+ /* Emit an error beep sound */
+ SendNotifyMessage(GuiData->hWindow, PM_CONSOLE_BEEP, 0, 0);
+ }
+
+ goto Quit;
+ }
+ else
+ {
+ /* Mouse selection mode */
+
+ if (!IsSystemKey(VirtualKeyCode))
+ {
+ /* Clear the selection and send the key into the input buffer */
+ GuiConsoleUpdateSelection(Console, NULL);
+ SetWindowText(GuiData->hWindow, Console->Title.Buffer);
+ }
+ else
+ {
+ goto Quit;
+ }
+ }
+ }
+
+ if ((Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) == 0)
+ {
+ MSG Message;
+
+ Message.hwnd = GuiData->hWindow;
+ Message.message = msg;
+ Message.wParam = wParam;
+ Message.lParam = lParam;
+
+ ConioProcessKey(Console, &Message);
+ }
+
+Quit:
+ LeaveCriticalSection(&Console->Lock);
+}
+
+static VOID
+GuiInvalidateCell(IN OUT PFRONTEND This, SHORT x, SHORT y)
+{
+ SMALL_RECT CellRect = { x, y, x, y };
+ GuiDrawRegion(This, &CellRect);
+}
+
+static VOID
+GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData)
+{
+ PCONSOLE Console = GuiData->Console;
+ PCONSOLE_SCREEN_BUFFER Buff;
+
+ SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CURSOR_BLINK_TIME, NULL);
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
+ Buff = ConDrvGetActiveScreenBuffer(Console);
+
+ if (GetType(Buff) == TEXTMODE_BUFFER)
+ {
+ GuiInvalidateCell(&Console->TermIFace, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+ Buff->CursorBlinkOn = !Buff->CursorBlinkOn;
+
+ if ((GuiData->OldCursor.x != Buff->CursorPosition.X) || (GuiData->OldCursor.y != Buff->CursorPosition.Y))
+ {
+ SCROLLINFO xScroll;
+ int OldScrollX = -1, OldScrollY = -1;
+ int NewScrollX = -1, NewScrollY = -1;
+
+ xScroll.cbSize = sizeof(SCROLLINFO);
+ xScroll.fMask = SIF_POS;
+ // Capture the original position of the scroll bars and save them.
+ if (GetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll)) OldScrollX = xScroll.nPos;
+ if (GetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll)) OldScrollY = xScroll.nPos;
+
+ // If we successfully got the info for the horizontal scrollbar
+ if (OldScrollX >= 0)
+ {
+ if ((Buff->CursorPosition.X < Buff->ViewOrigin.X) || (Buff->CursorPosition.X >= (Buff->ViewOrigin.X + Buff->ViewSize.X)))
+ {
+ // Handle the horizontal scroll bar
+ if (Buff->CursorPosition.X >= Buff->ViewSize.X) NewScrollX = Buff->CursorPosition.X - Buff->ViewSize.X + 1;
+ else NewScrollX = 0;
+ }
+ else
+ {
+ NewScrollX = OldScrollX;
+ }
+ }
+ // If we successfully got the info for the vertical scrollbar
+ if (OldScrollY >= 0)
+ {
+ if ((Buff->CursorPosition.Y < Buff->ViewOrigin.Y) || (Buff->CursorPosition.Y >= (Buff->ViewOrigin.Y + Buff->ViewSize.Y)))
+ {
+ // Handle the vertical scroll bar
+ if (Buff->CursorPosition.Y >= Buff->ViewSize.Y) NewScrollY = Buff->CursorPosition.Y - Buff->ViewSize.Y + 1;
+ else NewScrollY = 0;
+ }
+ else
+ {
+ NewScrollY = OldScrollY;
+ }
+ }
+
+ // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area
+ // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar
+ // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling)
+ // and their associated scrollbar is left alone.
+ if ((OldScrollX != NewScrollX) || (OldScrollY != NewScrollY))
+ {
+ Buff->ViewOrigin.X = NewScrollX;
+ Buff->ViewOrigin.Y = NewScrollY;
+ ScrollWindowEx(GuiData->hWindow,
+ (OldScrollX - NewScrollX) * GuiData->CharWidth,
+ (OldScrollY - NewScrollY) * GuiData->CharHeight,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ SW_INVALIDATE);
+ if (NewScrollX >= 0)
+ {
+ xScroll.nPos = NewScrollX;
+ SetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll, TRUE);
+ }
+ if (NewScrollY >= 0)
+ {
+ xScroll.nPos = NewScrollY;
+ SetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll, TRUE);
+ }
+ UpdateWindow(GuiData->hWindow);
+ GuiData->OldCursor.x = Buff->CursorPosition.X;
+ GuiData->OldCursor.y = Buff->CursorPosition.Y;
+ }
+ }
+ }
+ else /* if (GetType(Buff) == GRAPHICS_BUFFER) */
+ {
+ }
+
+ LeaveCriticalSection(&Console->Lock);
+}
+
+static BOOL
+GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData)
+{
+ PCONSOLE Console = GuiData->Console;
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+ return TRUE;
+
+ // TODO: Prompt for termination ? (Warn the user about possible apps running in this console)
+
+ /*
+ * FIXME: Windows will wait up to 5 seconds for the thread to exit.
+ * We shouldn't wait here, though, since the console lock is entered.
+ * A copy of the thread list probably needs to be made.
+ */
+ ConDrvConsoleProcessCtrlEvent(Console, 0, CTRL_CLOSE_EVENT);
+
+ LeaveCriticalSection(&Console->Lock);
+ return FALSE;
+}
+
+static LRESULT
+GuiConsoleHandleNcDestroy(HWND hWnd)
+{
+ KillTimer(hWnd, CONGUI_UPDATE_TIMER);
+ GetSystemMenu(hWnd, TRUE);
+
+ /* Free the GuiData registration */
+ SetWindowLongPtrW(hWnd, GWLP_USERDATA, (DWORD_PTR)NULL);
+
+ return DefWindowProcW(hWnd, WM_NCDESTROY, 0, 0);
+}
+
+static COORD
+PointToCoord(PGUI_CONSOLE_DATA GuiData, LPARAM lParam)
+{
+ PCONSOLE Console = GuiData->Console;
+ PCONSOLE_SCREEN_BUFFER Buffer = ConDrvGetActiveScreenBuffer(Console);
+ COORD Coord;
+ UINT WidthUnit, HeightUnit;
+
+ GetScreenBufferSizeUnits(Buffer, GuiData, &WidthUnit, &HeightUnit);
+
+ Coord.X = Buffer->ViewOrigin.X + ((SHORT)LOWORD(lParam) / (int)WidthUnit );
+ Coord.Y = Buffer->ViewOrigin.Y + ((SHORT)HIWORD(lParam) / (int)HeightUnit);
+
+ /* Clip coordinate to ensure it's inside buffer */
+ if (Coord.X < 0)
+ Coord.X = 0;
+ else if (Coord.X >= Buffer->ScreenBufferSize.X)
+ Coord.X = Buffer->ScreenBufferSize.X - 1;
+
+ if (Coord.Y < 0)
+ Coord.Y = 0;
+ else if (Coord.Y >= Buffer->ScreenBufferSize.Y)
+ Coord.Y = Buffer->ScreenBufferSize.Y - 1;
+
+ return Coord;
+}
+
+static LRESULT
+GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL Err = FALSE;
+ PCONSOLE Console = GuiData->Console;
+
+ if (GuiData->IgnoreNextMouseSignal)
+ {
+ if (msg != WM_LBUTTONDOWN &&
+ msg != WM_MBUTTONDOWN &&
+ msg != WM_RBUTTONDOWN)
+ {
+ /*
+ * If this mouse signal is not a button-down action,
+ * then it is the last signal being ignored.
+ */
+ GuiData->IgnoreNextMouseSignal = FALSE;
+ }
+ else
+ {
+ /*
+ * This mouse signal is a button-down action.
+ * Ignore it and perform default action.
+ */
+ Err = TRUE;
+ }
+ goto Quit;
+ }
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+ {
+ Err = TRUE;
+ goto Quit;
+ }
+
+ if ( (Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) ||
+ (Console->QuickEdit) )
+ {
+ switch (msg)
+ {
+ case WM_LBUTTONDOWN:
+ {
+ LPWSTR WindowTitle = NULL;
+ SIZE_T Length = 0;
+
+ Console->Selection.dwSelectionAnchor = PointToCoord(GuiData, lParam);
+ SetCapture(GuiData->hWindow);
+ Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS | CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
+ GuiConsoleUpdateSelection(Console, &Console->Selection.dwSelectionAnchor);
+
+ Length = Console->Title.Length + sizeof(L"Selection - ")/sizeof(WCHAR) + 1;
+ WindowTitle = ConsoleAllocHeap(0, Length * sizeof(WCHAR));
+ wcscpy(WindowTitle, L"Selection - ");
+ wcscat(WindowTitle, Console->Title.Buffer);
+ SetWindowText(GuiData->hWindow, WindowTitle);
+ ConsoleFreeHeap(WindowTitle);
+
+ break;
+ }
+
+ case WM_LBUTTONUP:
+ {
+ COORD c;
+
+ if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
+
+ c = PointToCoord(GuiData, lParam);
+ Console->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN;
+ GuiConsoleUpdateSelection(Console, &c);
+ ReleaseCapture();
+
+ break;
+ }
+
+ case WM_LBUTTONDBLCLK:
+ {
+ DPRINT1("Handle left-double-click for selecting a word\n");
+ break;
+ }
+
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONDBLCLK:
+ {
+ if (!(Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY))
+ {
+ GuiConsolePaste(GuiData);
+ }
+ else
+ {
+ GuiConsoleCopy(GuiData);
+ }
+
+ GuiData->IgnoreNextMouseSignal = TRUE;
+ break;
+ }
+
+ case WM_MOUSEMOVE:
+ {
+ COORD c;
+
+ if (!(wParam & MK_LBUTTON)) break;
+ if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
+
+ c = PointToCoord(GuiData, lParam); /* TODO: Scroll buffer to bring c into view */
+ GuiConsoleUpdateSelection(Console, &c);
+
+ break;
+ }
+
+ default:
+ Err = FALSE; // TRUE;
+ break;
+ }
+ }
+ else if (Console->InputBuffer.Mode & ENABLE_MOUSE_INPUT)
+ {
+ INPUT_RECORD er;
+ WORD wKeyState = GET_KEYSTATE_WPARAM(wParam);
+ DWORD dwButtonState = 0;
+ DWORD dwControlKeyState = 0;
+ DWORD dwEventFlags = 0;
+
+ switch (msg)
+ {
+ case WM_LBUTTONDOWN:
+ SetCapture(GuiData->hWindow);
+ dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED;
+ dwEventFlags = 0;
+ break;
+
+ case WM_MBUTTONDOWN:
+ SetCapture(GuiData->hWindow);
+ dwButtonState = FROM_LEFT_2ND_BUTTON_PRESSED;
+ dwEventFlags = 0;
+ break;
+
+ case WM_RBUTTONDOWN:
+ SetCapture(GuiData->hWindow);
+ dwButtonState = RIGHTMOST_BUTTON_PRESSED;
+ dwEventFlags = 0;
+ break;
+
+ case WM_LBUTTONUP:
+ ReleaseCapture();
+ dwButtonState = 0;
+ dwEventFlags = 0;
+ break;
+
+ case WM_MBUTTONUP:
+ ReleaseCapture();
+ dwButtonState = 0;
+ dwEventFlags = 0;
+ break;
+
+ case WM_RBUTTONUP:
+ ReleaseCapture();
+ dwButtonState = 0;
+ dwEventFlags = 0;
+ break;
+
+ case WM_LBUTTONDBLCLK:
+ dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED;
+ dwEventFlags = DOUBLE_CLICK;
+ break;
+
+ case WM_MBUTTONDBLCLK:
+ dwButtonState = FROM_LEFT_2ND_BUTTON_PRESSED;
+ dwEventFlags = DOUBLE_CLICK;
+ break;
+
+ case WM_RBUTTONDBLCLK:
+ dwButtonState = RIGHTMOST_BUTTON_PRESSED;
+ dwEventFlags = DOUBLE_CLICK;
+ break;
+
+ case WM_MOUSEMOVE:
+ dwButtonState = 0;
+ dwEventFlags = MOUSE_MOVED;
+ break;
+
+ case WM_MOUSEWHEEL:
+ dwButtonState = GET_WHEEL_DELTA_WPARAM(wParam) << 16;
+ dwEventFlags = MOUSE_WHEELED;
+ break;
+
+ case WM_MOUSEHWHEEL:
+ dwButtonState = GET_WHEEL_DELTA_WPARAM(wParam) << 16;
+ dwEventFlags = MOUSE_HWHEELED;
+ break;
+
+ default:
+ Err = TRUE;
+ break;
+ }
+
+ if (!Err)
+ {
+ if (wKeyState & MK_LBUTTON)
+ dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
+ if (wKeyState & MK_MBUTTON)
+ dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
+ if (wKeyState & MK_RBUTTON)
+ dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
+
+ if (GetKeyState(VK_RMENU) & 0x8000)
+ dwControlKeyState |= RIGHT_ALT_PRESSED;
+ if (GetKeyState(VK_LMENU) & 0x8000)
+ dwControlKeyState |= LEFT_ALT_PRESSED;
+ if (GetKeyState(VK_RCONTROL) & 0x8000)
+ dwControlKeyState |= RIGHT_CTRL_PRESSED;
+ if (GetKeyState(VK_LCONTROL) & 0x8000)
+ dwControlKeyState |= LEFT_CTRL_PRESSED;
+ if (GetKeyState(VK_SHIFT) & 0x8000)
+ dwControlKeyState |= SHIFT_PRESSED;
+ if (GetKeyState(VK_NUMLOCK) & 0x0001)
+ dwControlKeyState |= NUMLOCK_ON;
+ if (GetKeyState(VK_SCROLL) & 0x0001)
+ dwControlKeyState |= SCROLLLOCK_ON;
+ if (GetKeyState(VK_CAPITAL) & 0x0001)
+ dwControlKeyState |= CAPSLOCK_ON;
+ /* See WM_CHAR MSDN documentation for instance */
+ if (lParam & 0x01000000)
+ dwControlKeyState |= ENHANCED_KEY;
+
+ er.EventType = MOUSE_EVENT;
+ er.Event.MouseEvent.dwMousePosition = PointToCoord(GuiData, lParam);
+ er.Event.MouseEvent.dwButtonState = dwButtonState;
+ er.Event.MouseEvent.dwControlKeyState = dwControlKeyState;
+ er.Event.MouseEvent.dwEventFlags = dwEventFlags;
+
+ ConioProcessInputEvent(Console, &er);
+ }
+ }
+ else
+ {
+ Err = TRUE;
+ }
+
+ LeaveCriticalSection(&Console->Lock);
+
+Quit:
+ if (Err)
+ return DefWindowProcW(GuiData->hWindow, msg, wParam, lParam);
+ else
+ return 0;
+}
+
+VOID GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer);
+VOID GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer);
+
+static VOID
+GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData)
+{
- if (OpenClipboard(GuiData->hWindow) == TRUE)
++ if (OpenClipboard(GuiData->hWindow))
+ {
+ PCONSOLE Console = GuiData->Console;
+ PCONSOLE_SCREEN_BUFFER Buffer = ConDrvGetActiveScreenBuffer(Console);
+
+ if (GetType(Buffer) == TEXTMODE_BUFFER)
+ {
+ GuiCopyFromTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)Buffer);
+ }
+ else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
+ {
+ GuiCopyFromGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer);
+ }
+
+ CloseClipboard();
+
+ /* Clear the selection */
+ GuiConsoleUpdateSelection(Console, NULL);
+ SetWindowText(GuiData->hWindow, Console->Title.Buffer);
+ }
+}
+
+VOID GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer);
+VOID GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer);
+
+static VOID
+GuiConsolePaste(PGUI_CONSOLE_DATA GuiData)
+{
++ if (OpenClipboard(GuiData->hWindow))
+ {
+ PCONSOLE Console = GuiData->Console;
+ PCONSOLE_SCREEN_BUFFER Buffer = ConDrvGetActiveScreenBuffer(Console);
+
+ if (GetType(Buffer) == TEXTMODE_BUFFER)
+ {
+ GuiPasteToTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)Buffer);
+ }
+ else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
+ {
+ GuiPasteToGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer);
+ }
+
+ CloseClipboard();
+ }
+}
+
+static VOID
+GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
+{
+ PCONSOLE Console = GuiData->Console;
+ PCONSOLE_SCREEN_BUFFER ActiveBuffer;
+ DWORD windx, windy;
+ UINT WidthUnit, HeightUnit;
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
+ ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
+
+ GetScreenBufferSizeUnits(ActiveBuffer, GuiData, &WidthUnit, &HeightUnit);
+
+ windx = CONGUI_MIN_WIDTH * WidthUnit + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
+ windy = CONGUI_MIN_HEIGHT * HeightUnit + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
+
+ minMaxInfo->ptMinTrackSize.x = windx;
+ minMaxInfo->ptMinTrackSize.y = windy;
+
+ windx = (ActiveBuffer->ScreenBufferSize.X) * WidthUnit + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
+ windy = (ActiveBuffer->ScreenBufferSize.Y) * HeightUnit + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
+
+ if (ActiveBuffer->ViewSize.X < ActiveBuffer->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
+ if (ActiveBuffer->ViewSize.Y < ActiveBuffer->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
+
+ minMaxInfo->ptMaxTrackSize.x = windx;
+ minMaxInfo->ptMaxTrackSize.y = windy;
+
+ LeaveCriticalSection(&Console->Lock);
+}
+
+static VOID
+GuiConsoleResize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
+{
+ PCONSOLE Console = GuiData->Console;
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
+ if ((GuiData->WindowSizeLock == FALSE) &&
+ (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED))
+ {
+ PCONSOLE_SCREEN_BUFFER Buff = ConDrvGetActiveScreenBuffer(Console);
+ DWORD windx, windy, charx, chary;
+ UINT WidthUnit, HeightUnit;
+
+ GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
+
+ GuiData->WindowSizeLock = TRUE;
+
+ windx = LOWORD(lParam);
+ windy = HIWORD(lParam);
+
+ // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
+ if (Buff->ViewSize.X < Buff->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
+ if (Buff->ViewSize.Y < Buff->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
+
+ charx = windx / (int)WidthUnit ;
+ chary = windy / (int)HeightUnit;
+
+ // Character alignment (round size up or down)
+ if ((windx % WidthUnit ) >= (WidthUnit / 2)) ++charx;
+ if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary;
+
+ // Compensate for added scroll bars in new window
+ if (charx < Buff->ScreenBufferSize.X) windy -= GetSystemMetrics(SM_CYHSCROLL); // new window will have a horizontal scroll bar
+ if (chary < Buff->ScreenBufferSize.Y) windx -= GetSystemMetrics(SM_CXVSCROLL); // new window will have a vertical scroll bar
+
+ charx = windx / (int)WidthUnit ;
+ chary = windy / (int)HeightUnit;
+
+ // Character alignment (round size up or down)
+ if ((windx % WidthUnit ) >= (WidthUnit / 2)) ++charx;
+ if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary;
+
+ // Resize window
+ if ((charx != Buff->ViewSize.X) || (chary != Buff->ViewSize.Y))
+ {
+ Buff->ViewSize.X = (charx <= Buff->ScreenBufferSize.X) ? charx : Buff->ScreenBufferSize.X;
+ Buff->ViewSize.Y = (chary <= Buff->ScreenBufferSize.Y) ? chary : Buff->ScreenBufferSize.Y;
+ }
+
+ GuiConsoleResizeWindow(GuiData);
+
+ // Adjust the start of the visible area if we are attempting to show nonexistent areas
+ if ((Buff->ScreenBufferSize.X - Buff->ViewOrigin.X) < Buff->ViewSize.X) Buff->ViewOrigin.X = Buff->ScreenBufferSize.X - Buff->ViewSize.X;
+ if ((Buff->ScreenBufferSize.Y - Buff->ViewOrigin.Y) < Buff->ViewSize.Y) Buff->ViewOrigin.Y = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y;
+ InvalidateRect(GuiData->hWindow, NULL, TRUE);
+
+ GuiData->WindowSizeLock = FALSE;
+ }
+
+ LeaveCriticalSection(&Console->Lock);
+}
+
+/*
+// HACK: This functionality is standard for general scrollbars. Don't add it by hand.
+
+VOID
+FASTCALL
+GuiConsoleHandleScrollbarMenu(VOID)
+{
+ HMENU hMenu;
+
+ hMenu = CreatePopupMenu();
+ if (hMenu == NULL)
+ {
+ DPRINT("CreatePopupMenu failed\n");
+ return;
+ }
+
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
+ //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
+ //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
+ //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
+}
+*/
+
+static LRESULT
+GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
+{
+ PCONSOLE Console = GuiData->Console;
+ PCONSOLE_SCREEN_BUFFER Buff;
+ SCROLLINFO sInfo;
+ int fnBar;
+ int old_pos, Maximum;
+ PSHORT pShowXY;
+
+ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return 0;
+
+ Buff = ConDrvGetActiveScreenBuffer(Console);
+
+ if (uMsg == WM_HSCROLL)
+ {
+ fnBar = SB_HORZ;
+ Maximum = Buff->ScreenBufferSize.X - Buff->ViewSize.X;
+ pShowXY = &Buff->ViewOrigin.X;
+ }
+ else
+ {
+ fnBar = SB_VERT;
+ Maximum = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y;
+ pShowXY = &Buff->ViewOrigin.Y;
+ }
+
+ /* set scrollbar sizes */
+ sInfo.cbSize = sizeof(SCROLLINFO);
+ sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
+
+ if (!GetScrollInfo(GuiData->hWindow, fnBar, &sInfo)) goto Quit;
+
+ old_pos = sInfo.nPos;
+
+ switch (LOWORD(wParam))
+ {
+ case SB_LINELEFT:
+ sInfo.nPos -= 1;
+ break;
+
+ case SB_LINERIGHT:
+ sInfo.nPos += 1;
+ break;
+
+ case SB_PAGELEFT:
+ sInfo.nPos -= sInfo.nPage;
+ break;
+
+ case SB_PAGERIGHT:
+ sInfo.nPos += sInfo.nPage;
+ break;
+
+ case SB_THUMBTRACK:
+ sInfo.nPos = sInfo.nTrackPos;
+ ConioPause(Console, PAUSED_FROM_SCROLLBAR);
+ break;
+
+ case SB_THUMBPOSITION:
+ ConioUnpause(Console, PAUSED_FROM_SCROLLBAR);
+ break;
+
+ case SB_TOP:
+ sInfo.nPos = sInfo.nMin;
+ break;
+
+ case SB_BOTTOM:
+ sInfo.nPos = sInfo.nMax;
+ break;
+
+ default:
+ break;
+ }
+
+ sInfo.nPos = max(sInfo.nPos, 0);
+ sInfo.nPos = min(sInfo.nPos, Maximum);
+
+ if (old_pos != sInfo.nPos)
+ {
+ USHORT OldX = Buff->ViewOrigin.X;
+ USHORT OldY = Buff->ViewOrigin.Y;
+ UINT WidthUnit, HeightUnit;
+
+ *pShowXY = sInfo.nPos;
+
+ GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
+
+ ScrollWindowEx(GuiData->hWindow,
+ (OldX - Buff->ViewOrigin.X) * WidthUnit ,
+ (OldY - Buff->ViewOrigin.Y) * HeightUnit,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ SW_INVALIDATE);
+
+ sInfo.fMask = SIF_POS;
+ SetScrollInfo(GuiData->hWindow, fnBar, &sInfo, TRUE);
+
+ UpdateWindow(GuiData->hWindow);
+ }
+
+Quit:
+ LeaveCriticalSection(&Console->Lock);
+ return 0;
+}
+
+static LRESULT CALLBACK
+GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT Result = 0;
+ PGUI_CONSOLE_DATA GuiData = NULL;
+ PCONSOLE Console = NULL;
+
+ /*
+ * - If it's the first time we create a window for the terminal,
+ * just initialize it and return.
+ *
+ * - If we are destroying the window, just do it and return.
+ */
+ if (msg == WM_NCCREATE)
+ {
+ return (LRESULT)GuiConsoleHandleNcCreate(hWnd, (LPCREATESTRUCTW)lParam);
+ }
+ else if (msg == WM_NCDESTROY)
+ {
+ return GuiConsoleHandleNcDestroy(hWnd);
+ }
+
+ /*
+ * Now the terminal window is initialized.
+ * Get the terminal data via the window's data.
+ * If there is no data, just go away.
+ */
+ GuiData = GuiGetGuiData(hWnd);
+ if (GuiData == NULL) return DefWindowProcW(hWnd, msg, wParam, lParam);
+
+ /*
+ * Just retrieve a pointer to the console in case somebody needs it.
+ * It is not NULL because it was checked in GuiGetGuiData.
+ * Each helper function which needs the console has to validate and lock it.
+ */
+ Console = GuiData->Console;
+
+ /* We have a console, start message dispatching */
+ switch (msg)
+ {
+ case WM_ACTIVATE:
+ {
+ if (LOWORD(wParam) == WA_CLICKACTIVE) GuiData->IgnoreNextMouseSignal = TRUE;
+ break;
+ }
+
+ case WM_CLOSE:
+ if (GuiConsoleHandleClose(GuiData)) goto Default;
+ break;
+
+ case WM_PAINT:
+ GuiConsoleHandlePaint(GuiData);
+ break;
+
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_CHAR:
+ case WM_DEADCHAR:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ case WM_SYSCHAR:
+ case WM_SYSDEADCHAR:
+ {
+ /* Detect Alt-Enter presses and switch back and forth to fullscreen mode */
+ if (msg == WM_SYSKEYDOWN && (HIWORD(lParam) & KF_ALTDOWN) && wParam == VK_RETURN)
+ {
+ /* Switch only at first Alt-Enter press, and ignore subsequent key repetitions */
+ if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT) GuiConsoleSwitchFullScreen(GuiData);
+ break;
+ }
+
+ GuiConsoleHandleKey(GuiData, msg, wParam, lParam);
+ break;
+ }
+
+ case WM_TIMER:
+ GuiConsoleHandleTimer(GuiData);
+ break;
+
+ case WM_SETCURSOR:
+ {
+ /*
+ * The message was sent because we are manually triggering a change.
+ * Check whether the mouse is indeed present on this console window
+ * and take appropriate decisions.
+ */
+ if (wParam == -1 && lParam == -1)
+ {
+ POINT mouseCoords;
+ HWND hWndHit;
+
+ /* Get the placement of the mouse */
+ GetCursorPos(&mouseCoords);
+
+ /* On which window is placed the mouse ? */
+ hWndHit = WindowFromPoint(mouseCoords);
+
+ /* It's our window. Perform the hit-test to be used later on. */
+ if (hWndHit == hWnd)
+ {
+ wParam = (WPARAM)hWnd;
+ lParam = DefWindowProcW(hWndHit, WM_NCHITTEST, 0,
+ MAKELPARAM(mouseCoords.x, mouseCoords.y));
+ }
+ }
+
+ /* Set the mouse cursor only when we are in the client area */
+ if ((HWND)wParam == hWnd && LOWORD(lParam) == HTCLIENT)
+ {
+ if (GuiData->MouseCursorRefCount >= 0)
+ {
+ /* Show the cursor */
+ SetCursor(GuiData->hCursor);
+ }
+ else
+ {
+ /* Hide the cursor if the reference count is negative */
+ SetCursor(NULL);
+ }
+ return TRUE;
+ }
+ else
+ {
+ goto Default;
+ }
+ }
+
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_MOUSEMOVE:
+ case WM_MOUSEWHEEL:
+ case WM_MOUSEHWHEEL:
+ {
+ Result = GuiConsoleHandleMouse(GuiData, msg, wParam, lParam);
+ break;
+ }
+
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ {
+ Result = GuiConsoleHandleScroll(GuiData, msg, wParam);
+ break;
+ }
+
+ case WM_NCRBUTTONDOWN:
+ {
+ DPRINT1("WM_NCRBUTTONDOWN\n");
+ /*
+ * HACK: !! Because, when we deal with WM_RBUTTON* and we do not
+ * call after that DefWindowProc, on ReactOS, right-clicks on the
+ * (non-client) application title-bar does not display the system
+ * menu and does not trigger a WM_NCRBUTTONUP message too.
+ * See: http://git.reactos.org/?p=reactos.git;a=blob;f=reactos/win32ss/user/user32/windows/defwnd.c;hb=HEAD#l1103
+ * and line 1135 too.
+ */
+ if (DefWindowProcW(hWnd, WM_NCHITTEST, 0, lParam) == HTCAPTION)
+ {
+ /* Call DefWindowProcW with the WM_CONTEXTMENU message */
+ msg = WM_CONTEXTMENU;
+ }
+ goto Default;
+ }
+ // case WM_NCRBUTTONUP:
+ // DPRINT1("WM_NCRBUTTONUP\n");
+ // goto Default;
+
+ case WM_CONTEXTMENU:
+ {
+ if (DefWindowProcW(hWnd /*GuiData->hWindow*/, WM_NCHITTEST, 0, lParam) == HTCLIENT)
+ {
+ HMENU hMenu = CreatePopupMenu();
+ if (hMenu != NULL)
+ {
+ GuiConsoleAppendMenuItems(hMenu, GuiConsoleEditMenuItems);
+ TrackPopupMenuEx(hMenu,
+ TPM_RIGHTBUTTON,
+ GET_X_LPARAM(lParam),
+ GET_Y_LPARAM(lParam),
+ hWnd,
+ NULL);
+ DestroyMenu(hMenu);
+ }
+ break;
+ }
+ else
+ {
+ goto Default;
+ }
+ }
+
+ case WM_INITMENU:
+ {
+ HMENU hMenu = (HMENU)wParam;
+ if (hMenu != NULL)
+ {
+ /* Enable or disable the Close menu item */
+ EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND |
+ (GuiData->IsCloseButtonEnabled ? MF_ENABLED : MF_GRAYED));
+
+ /* Enable or disable the Copy and Paste items */
+ EnableMenuItem(hMenu, ID_SYSTEM_EDIT_COPY , MF_BYCOMMAND |
+ ((Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
+ (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY) ? MF_ENABLED : MF_GRAYED));
+ EnableMenuItem(hMenu, ID_SYSTEM_EDIT_PASTE, MF_BYCOMMAND |
+ (!(Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
+ IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED));
+ }
+
+ if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+ {
+ GuiSendMenuEvent(Console, WM_INITMENU);
+ LeaveCriticalSection(&Console->Lock);
+ }
+ break;
+ }
+
+ case WM_MENUSELECT:
+ {
+ if (HIWORD(wParam) == 0xFFFF) // Allow all the menu flags
+ {
+ if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+ {
+ GuiSendMenuEvent(Console, WM_MENUSELECT);
+ LeaveCriticalSection(&Console->Lock);
+ }
+ }
+ break;
+ }
+
+ case WM_COMMAND:
+ case WM_SYSCOMMAND:
+ {
+ Result = GuiConsoleHandleSysMenuCommand(GuiData, wParam, lParam);
+ break;
+ }
+
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ {
+ if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+ {
+ INPUT_RECORD er;
+ er.EventType = FOCUS_EVENT;
+ er.Event.FocusEvent.bSetFocus = (msg == WM_SETFOCUS);
+ ConioProcessInputEvent(Console, &er);
+
+ if (msg == WM_SETFOCUS)
+ DPRINT1("TODO: Create console caret\n");
+ else // if (msg == WM_KILLFOCUS)
+ DPRINT1("TODO: Destroy console caret\n");
+
+ LeaveCriticalSection(&Console->Lock);
+ }
+ break;
+ }
+
+ case WM_GETMINMAXINFO:
+ GuiConsoleGetMinMaxInfo(GuiData, (PMINMAXINFO)lParam);
+ break;
+
+ case WM_SIZE:
+ GuiConsoleResize(GuiData, wParam, lParam);
+ break;
+
+ case PM_RESIZE_TERMINAL:
+ {
+ /* Resize the window to the user's values */
+ GuiData->WindowSizeLock = TRUE;
+ GuiConsoleResizeWindow(GuiData);
+ GuiData->WindowSizeLock = FALSE;
+ break;
+ }
+
+ case PM_APPLY_CONSOLE_INFO:
+ {
+ if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+ {
+ GuiApplyUserSettings(GuiData, (HANDLE)wParam, (BOOL)lParam);
+ LeaveCriticalSection(&Console->Lock);
+ }
+ break;
+ }
+
+ case PM_CONSOLE_BEEP:
+ DPRINT1("Beep !!\n");
+ Beep(800, 200);
+ break;
+
+ // case PM_CONSOLE_SET_TITLE:
+ // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
+ // break;
+
+ default: Default:
+ Result = DefWindowProcW(hWnd, msg, wParam, lParam);
+ break;
+ }
+
+ return Result;
+}
+
+
+
+/******************************************************************************
+ * GUI Terminal Initialization *
+ ******************************************************************************/
+
+static LRESULT CALLBACK
+GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND NewWindow;
+ LONG WindowCount;
+ MSG Msg;
+
+ switch (msg)
+ {
+ case WM_CREATE:
+ {
+ SetWindowLongW(hWnd, GWL_USERDATA, 0);
+ return 0;
+ }
+
+ case PM_CREATE_CONSOLE:
+ {
+ PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
+ PCONSOLE Console = GuiData->Console;
+
+ NewWindow = CreateWindowExW(WS_EX_CLIENTEDGE,
+ GUI_CONSOLE_WINDOW_CLASS,
+ Console->Title.Buffer,
+ WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ ConSrvDllInstance,
+ (PVOID)GuiData);
+ if (NULL != NewWindow)
+ {
+ WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
+ WindowCount++;
+ SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
+
+ DPRINT("Set icons via PM_CREATE_CONSOLE\n");
+ if (GuiData->hIcon == NULL)
+ {
+ DPRINT("Not really /o\\...\n");
+ GuiData->hIcon = ghDefaultIcon;
+ GuiData->hIconSm = ghDefaultIconSm;
+ }
+ else if (GuiData->hIcon != ghDefaultIcon)
+ {
+ DPRINT("Yes \\o/\n");
+ SendMessageW(GuiData->hWindow, WM_SETICON, ICON_BIG, (LPARAM)GuiData->hIcon);
+ SendMessageW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
+ }
+
+ /* Move and resize the window to the user's values */
+ /* CAN WE DEADLOCK ?? */
+ GuiConsoleMoveWindow(GuiData);
+ GuiData->WindowSizeLock = TRUE;
+ GuiConsoleResizeWindow(GuiData);
+ GuiData->WindowSizeLock = FALSE;
+
+ // ShowWindow(NewWindow, (int)wParam);
+ ShowWindowAsync(NewWindow, (int)wParam);
+ DPRINT("Window showed\n");
+ }
+
+ return (LRESULT)NewWindow;
+ }
+
+ case PM_DESTROY_CONSOLE:
+ {
+ PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
+
+ /*
+ * Window creation is done using a PostMessage(), so it's possible
+ * that the window that we want to destroy doesn't exist yet.
+ * So first empty the message queue.
+ */
+ /*
+ while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&Msg);
+ DispatchMessageW(&Msg);
+ }*/
+ while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE)) ;
+
+ if (GuiData->hWindow != NULL) /* && DestroyWindow(GuiData->hWindow) */
+ {
+ DestroyWindow(GuiData->hWindow);
+
+ WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
+ WindowCount--;
+ SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
+ if (0 == WindowCount)
+ {
+ NotifyWnd = NULL;
+ DestroyWindow(hWnd);
+ DPRINT("CONSRV: Going to quit the Gui Thread!!\n");
+ PostQuitMessage(0);
+ }
+ }
+
+ return 0;
+ }
+
+ default:
+ return DefWindowProcW(hWnd, msg, wParam, lParam);
+ }
+}
+
+static DWORD WINAPI
+GuiConsoleGuiThread(PVOID Data)
+{
+ MSG msg;
+ PHANDLE GraphicsStartupEvent = (PHANDLE)Data;
+
+ /*
+ * This thread dispatches all the console notifications to the notify window.
+ * It is common for all the console windows.
+ */
+
+ PrivateCsrssManualGuiCheck(+1);
+
+ NotifyWnd = CreateWindowW(L"ConSrvCreateNotify",
+ L"",
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ ConSrvDllInstance,
+ NULL);
+ if (NULL == NotifyWnd)
+ {
+ PrivateCsrssManualGuiCheck(-1);
+ SetEvent(*GraphicsStartupEvent);
+ return 1;
+ }
+
+ SetEvent(*GraphicsStartupEvent);
+
+ while (GetMessageW(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+
+ DPRINT("CONSRV: Quit the Gui Thread!!\n");
+ PrivateCsrssManualGuiCheck(-1);
+
+ return 1;
+}
+
+static BOOL
+GuiInit(VOID)
+{
+ WNDCLASSEXW wc;
+ ATOM ConsoleClassAtom;
+
+ /* Exit if we were already initialized */
+ // if (ConsInitialized) return TRUE;
+
+ /*
+ * Initialize and register the different window classes, if needed.
+ */
+ if (!ConsInitialized)
+ {
+ /* Initialize the notification window class */
+ wc.cbSize = sizeof(WNDCLASSEXW);
+ wc.lpszClassName = L"ConSrvCreateNotify";
+ wc.lpfnWndProc = GuiConsoleNotifyWndProc;
+ wc.style = 0;
+ wc.hInstance = ConSrvDllInstance;
+ wc.hIcon = NULL;
+ wc.hIconSm = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ if (RegisterClassExW(&wc) == 0)
+ {
+ DPRINT1("Failed to register GUI notify wndproc\n");
+ return FALSE;
+ }
+
+ /* Initialize the console window class */
+ ghDefaultIcon = LoadImageW(ConSrvDllInstance,
+ MAKEINTRESOURCEW(IDI_TERMINAL),
+ IMAGE_ICON,
+ GetSystemMetrics(SM_CXICON),
+ GetSystemMetrics(SM_CYICON),
+ LR_SHARED);
+ ghDefaultIconSm = LoadImageW(ConSrvDllInstance,
+ MAKEINTRESOURCEW(IDI_TERMINAL),
+ IMAGE_ICON,
+ GetSystemMetrics(SM_CXSMICON),
+ GetSystemMetrics(SM_CYSMICON),
+ LR_SHARED);
+ ghDefaultCursor = LoadCursorW(NULL, IDC_ARROW);
+ wc.cbSize = sizeof(WNDCLASSEXW);
+ wc.lpszClassName = GUI_CONSOLE_WINDOW_CLASS;
+ wc.lpfnWndProc = GuiConsoleWndProc;
+ wc.style = CS_DBLCLKS /* | CS_HREDRAW | CS_VREDRAW */;
+ wc.hInstance = ConSrvDllInstance;
+ wc.hIcon = ghDefaultIcon;
+ wc.hIconSm = ghDefaultIconSm;
+ wc.hCursor = ghDefaultCursor;
+ wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // The color of a terminal when it is switch off.
+ wc.lpszMenuName = NULL;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = GWLP_CONSOLEWND_ALLOC;
+
+ ConsoleClassAtom = RegisterClassExW(&wc);
+ if (ConsoleClassAtom == 0)
+ {
+ DPRINT1("Failed to register GUI console wndproc\n");
+ return FALSE;
+ }
+ else
+ {
+ NtUserConsoleControl(GuiConsoleWndClassAtom, &ConsoleClassAtom, sizeof(ATOM));
+ }
+
+ ConsInitialized = TRUE;
+ }
+
+ /*
+ * Set-up the notification window
+ */
+ if (NULL == NotifyWnd)
+ {
+ HANDLE ThreadHandle;
+ HANDLE GraphicsStartupEvent;
+
+ GraphicsStartupEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+ if (NULL == GraphicsStartupEvent) return FALSE;
+
+ ThreadHandle = CreateThread(NULL,
+ 0,
+ GuiConsoleGuiThread,
+ (PVOID)&GraphicsStartupEvent,
+ 0,
+ NULL);
+ if (NULL == ThreadHandle)
+ {
+ CloseHandle(GraphicsStartupEvent);
+ DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
+ return FALSE;
+ }
+ SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
+ CloseHandle(ThreadHandle);
+
+ WaitForSingleObject(GraphicsStartupEvent, INFINITE);
+ CloseHandle(GraphicsStartupEvent);
+
+ if (NULL == NotifyWnd)
+ {
+ DPRINT1("CONSRV: Failed to create notification window.\n");
+ return FALSE;
+ }
+ }
+
+ // ConsInitialized = TRUE;
+
+ return TRUE;
+}
+
+
+
+/******************************************************************************
+ * GUI Console Driver *
+ ******************************************************************************/
+
+static VOID WINAPI
+GuiDeinitFrontEnd(IN OUT PFRONTEND This);
+
+NTSTATUS NTAPI
+GuiInitFrontEnd(IN OUT PFRONTEND This,
+ IN PCONSOLE Console)
+{
+ PGUI_INIT_INFO GuiInitInfo;
+ PCONSOLE_INFO ConsoleInfo;
+ PCONSOLE_START_INFO ConsoleStartInfo;
+
+ PGUI_CONSOLE_DATA GuiData;
+ GUI_CONSOLE_INFO TermInfo;
+
+ SIZE_T Length = 0;
+ LPWSTR IconPath = NULL;
+ INT IconIndex = 0;
+
+ if (This == NULL || Console == NULL || This->OldData == NULL)
+ return STATUS_INVALID_PARAMETER;
+
+ ASSERT(This->Console == Console);
+
+ GuiInitInfo = This->OldData;
+
+ if (GuiInitInfo->ConsoleInfo == NULL || GuiInitInfo->ConsoleStartInfo == NULL)
+ return STATUS_INVALID_PARAMETER;
+
+ ConsoleInfo = GuiInitInfo->ConsoleInfo;
+ ConsoleStartInfo = GuiInitInfo->ConsoleStartInfo;
+
+ IconPath = ConsoleStartInfo->IconPath;
+ IconIndex = ConsoleStartInfo->IconIndex;
+
+
+ /* Terminal data allocation */
+ GuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(GUI_CONSOLE_DATA));
+ if (!GuiData)
+ {
+ DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+ /* HACK */ Console->TermIFace.Data = (PVOID)GuiData; /* HACK */
+ GuiData->Console = Console;
+ GuiData->hWindow = NULL;
+
+ /* The console can be resized */
+ Console->FixedSize = FALSE;
+
+ InitializeCriticalSection(&GuiData->Lock);
+
+
+ /*
+ * Load terminal settings
+ */
+
+ /* 1. Load the default settings */
+ GuiConsoleGetDefaultSettings(&TermInfo, GuiInitInfo->ProcessId);
+
+ /* 3. Load the remaining console settings via the registry. */
+ if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
+ {
+ /* Load the terminal infos from the registry. */
+ GuiConsoleReadUserSettings(&TermInfo,
+ ConsoleInfo->ConsoleTitle,
+ GuiInitInfo->ProcessId);
+
+ /*
+ * Now, update them with the properties the user might gave to us
+ * via the STARTUPINFO structure before calling CreateProcess
+ * (and which was transmitted via the ConsoleStartInfo structure).
+ * We therefore overwrite the values read in the registry.
+ */
+ if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW)
+ {
+ TermInfo.ShowWindow = ConsoleStartInfo->ShowWindow;
+ }
+ if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION)
+ {
+ TermInfo.AutoPosition = FALSE;
+ TermInfo.WindowOrigin = ConsoleStartInfo->ConsoleWindowOrigin;
+ }
+ if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
+ {
+ TermInfo.FullScreen = TRUE;
+ }
+ }
+
+
+ /*
+ * Set up GUI data
+ */
+
+ Length = min(wcslen(TermInfo.FaceName) + 1, LF_FACESIZE); // wcsnlen
+ wcsncpy(GuiData->GuiInfo.FaceName, TermInfo.FaceName, LF_FACESIZE);
+ GuiData->GuiInfo.FaceName[Length] = L'\0';
+ GuiData->GuiInfo.FontFamily = TermInfo.FontFamily;
+ GuiData->GuiInfo.FontSize = TermInfo.FontSize;
+ GuiData->GuiInfo.FontWeight = TermInfo.FontWeight;
+ GuiData->GuiInfo.UseRasterFonts = TermInfo.UseRasterFonts;
+ GuiData->GuiInfo.FullScreen = TermInfo.FullScreen;
+ GuiData->GuiInfo.ShowWindow = TermInfo.ShowWindow;
+ GuiData->GuiInfo.AutoPosition = TermInfo.AutoPosition;
+ GuiData->GuiInfo.WindowOrigin = TermInfo.WindowOrigin;
+
+ /* Initialize the icon handles to their default values */
+ GuiData->hIcon = ghDefaultIcon;
+ GuiData->hIconSm = ghDefaultIconSm;
+
+ /* Get the associated icon, if any */
+ if (IconPath == NULL || IconPath[0] == L'\0')
+ {
+ IconPath = ConsoleStartInfo->AppPath;
+ IconIndex = 0;
+ }
+ DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath ? IconPath : L"n/a"), IconIndex);
+ if (IconPath && IconPath[0] != L'\0')
+ {
+ HICON hIcon = NULL, hIconSm = NULL;
+ PrivateExtractIconExW(IconPath,
+ IconIndex,
+ &hIcon,
+ &hIconSm,
+ 1);
+ DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon, hIconSm);
+ if (hIcon != NULL)
+ {
+ DPRINT("Effectively set the icons\n");
+ GuiData->hIcon = hIcon;
+ GuiData->hIconSm = hIconSm;
+ }
+ }
+
+ /* Mouse is shown by default with its default cursor shape */
+ GuiData->hCursor = ghDefaultCursor;
+ GuiData->MouseCursorRefCount = 0;
+
+ /* A priori don't ignore mouse signals */
+ GuiData->IgnoreNextMouseSignal = FALSE;
+
+ /* Close button and the corresponding system menu item are enabled by default */
+ GuiData->IsCloseButtonEnabled = TRUE;
+
+ /* There is no user-reserved menu id range by default */
+ GuiData->cmdIdLow = GuiData->cmdIdHigh = 0;
+
+ /*
+ * We need to wait until the GUI has been fully initialized
+ * to retrieve custom settings i.e. WindowSize etc...
+ * Ideally we could use SendNotifyMessage for this but its not
+ * yet implemented.
+ */
+ GuiData->hGuiInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+
+ DPRINT("GUI - Checkpoint\n");
+
+ /* Create the terminal window */
+ PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, GuiData->GuiInfo.ShowWindow, (LPARAM)GuiData);
+
+ /* Wait until initialization has finished */
+ WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE);
+ DPRINT("OK we created the console window\n");
+ CloseHandle(GuiData->hGuiInitEvent);
+ GuiData->hGuiInitEvent = NULL;
+
+ /* Check whether we really succeeded in initializing the terminal window */
+ if (GuiData->hWindow == NULL)
+ {
+ DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
+ GuiDeinitFrontEnd(This);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ /* Finally, finish to initialize the frontend structure */
+ This->Data = GuiData;
+ if (This->OldData) ConsoleFreeHeap(This->OldData);
+ This->OldData = NULL;
+
+ return STATUS_SUCCESS;
+}
+
+static VOID WINAPI
+GuiDeinitFrontEnd(IN OUT PFRONTEND This)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+
+ SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData);
+
+ DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
+ GuiData->hIcon, ghDefaultIcon, GuiData->hIconSm, ghDefaultIconSm);
+ if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
+ {
+ DPRINT("Destroy hIcon\n");
+ DestroyIcon(GuiData->hIcon);
+ }
+ if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
+ {
+ DPRINT("Destroy hIconSm\n");
+ DestroyIcon(GuiData->hIconSm);
+ }
+
+ This->Data = NULL;
+ DeleteCriticalSection(&GuiData->Lock);
+ ConsoleFreeHeap(GuiData);
+
+ DPRINT("Quit GuiDeinitFrontEnd\n");
+}
+
+static VOID WINAPI
+GuiDrawRegion(IN OUT PFRONTEND This,
+ SMALL_RECT* Region)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+ RECT RegionRect;
+
+ SmallRectToRect(GuiData, &RegionRect, Region);
+ /* Do not erase the background: it speeds up redrawing and reduce flickering */
+ InvalidateRect(GuiData->hWindow, &RegionRect, FALSE);
+}
+
+static VOID WINAPI
+GuiWriteStream(IN OUT PFRONTEND This,
+ SMALL_RECT* Region,
+ SHORT CursorStartX,
+ SHORT CursorStartY,
+ UINT ScrolledLines,
+ PWCHAR Buffer,
+ UINT Length)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+ PCONSOLE_SCREEN_BUFFER Buff;
+ SHORT CursorEndX, CursorEndY;
+ RECT ScrollRect;
+
+ if (NULL == GuiData || NULL == GuiData->hWindow) return;
+
+ Buff = ConDrvGetActiveScreenBuffer(GuiData->Console);
+ if (GetType(Buff) != TEXTMODE_BUFFER) return;
+
+ if (0 != ScrolledLines)
+ {
+ ScrollRect.left = 0;
+ ScrollRect.top = 0;
+ ScrollRect.right = Buff->ViewSize.X * GuiData->CharWidth;
+ ScrollRect.bottom = Region->Top * GuiData->CharHeight;
+
+ ScrollWindowEx(GuiData->hWindow,
+ 0,
+ -(int)(ScrolledLines * GuiData->CharHeight),
+ &ScrollRect,
+ NULL,
+ NULL,
+ NULL,
+ SW_INVALIDATE);
+ }
+
+ GuiDrawRegion(This, Region);
+
+ if (CursorStartX < Region->Left || Region->Right < CursorStartX
+ || CursorStartY < Region->Top || Region->Bottom < CursorStartY)
+ {
+ GuiInvalidateCell(This, CursorStartX, CursorStartY);
+ }
+
+ CursorEndX = Buff->CursorPosition.X;
+ CursorEndY = Buff->CursorPosition.Y;
+ if ((CursorEndX < Region->Left || Region->Right < CursorEndX
+ || CursorEndY < Region->Top || Region->Bottom < CursorEndY)
+ && (CursorEndX != CursorStartX || CursorEndY != CursorStartY))
+ {
+ GuiInvalidateCell(This, CursorEndX, CursorEndY);
+ }
+
+ // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
+ // repaint the window without having it just freeze up and stay on the screen permanently.
+ Buff->CursorBlinkOn = TRUE;
+ SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
+}
+
+static BOOL WINAPI
+GuiSetCursorInfo(IN OUT PFRONTEND This,
+ PCONSOLE_SCREEN_BUFFER Buff)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+
+ if (ConDrvGetActiveScreenBuffer(GuiData->Console) == Buff)
+ {
+ GuiInvalidateCell(This, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+ }
+
+ return TRUE;
+}
+
+static BOOL WINAPI
+GuiSetScreenInfo(IN OUT PFRONTEND This,
+ PCONSOLE_SCREEN_BUFFER Buff,
+ SHORT OldCursorX,
+ SHORT OldCursorY)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+
+ if (ConDrvGetActiveScreenBuffer(GuiData->Console) == Buff)
+ {
+ /* Redraw char at old position (remove cursor) */
+ GuiInvalidateCell(This, OldCursorX, OldCursorY);
+ /* Redraw char at new position (show cursor) */
+ GuiInvalidateCell(This, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+ }
+
+ return TRUE;
+}
+
+static VOID WINAPI
+GuiResizeTerminal(IN OUT PFRONTEND This)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+
+ /* Resize the window to the user's values */
+ // GuiData->WindowSizeLock = TRUE;
+ // GuiConsoleResizeWindow(GuiData);
+ // GuiData->WindowSizeLock = FALSE;
+ // NOTE: This code ^^ causes deadlocks...
+
+ PostMessageW(GuiData->hWindow, PM_RESIZE_TERMINAL, 0, 0);
+}
+
+static BOOL WINAPI
+GuiProcessKeyCallback(IN OUT PFRONTEND This,
+ MSG* msg,
+ BYTE KeyStateMenu,
+ DWORD ShiftState,
+ UINT VirtualKeyCode,
+ BOOL Down)
+{
+ if ((ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED) || KeyStateMenu & 0x80) &&
+ (VirtualKeyCode == VK_ESCAPE || VirtualKeyCode == VK_TAB || VirtualKeyCode == VK_SPACE))
+ {
+ DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static BOOL WINAPI
+GuiSetMouseCursor(IN OUT PFRONTEND This,
+ HCURSOR hCursor);
+
+static VOID WINAPI
+GuiRefreshInternalInfo(IN OUT PFRONTEND This)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+
+ /* Update the console leader information held by the window */
+ SetConsoleWndConsoleLeaderCID(GuiData);
+
+ /*
+ * HACK:
+ * We reset the cursor here so that, when a console app quits, we reset
+ * the cursor to the default one. It's quite a hack since it doesn't proceed
+ * per - console process... This must be fixed.
+ *
+ * See GuiInitConsole(...) for more information.
+ */
+
+ /* Mouse is shown by default with its default cursor shape */
+ GuiData->MouseCursorRefCount = 0; // Reinitialize the reference counter
+ GuiSetMouseCursor(This, NULL);
+}
+
+static VOID WINAPI
+GuiChangeTitle(IN OUT PFRONTEND This)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+ // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
+ SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
+}
+
+static BOOL WINAPI
+GuiChangeIcon(IN OUT PFRONTEND This,
+ HICON hWindowIcon)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+ HICON hIcon, hIconSm;
+
+ if (hWindowIcon == NULL)
+ {
+ hIcon = ghDefaultIcon;
+ hIconSm = ghDefaultIconSm;
+ }
+ else
+ {
+ hIcon = CopyIcon(hWindowIcon);
+ hIconSm = CopyIcon(hWindowIcon);
+ }
+
+ if (hIcon == NULL)
+ {
+ return FALSE;
+ }
+
+ if (hIcon != GuiData->hIcon)
+ {
+ if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
+ {
+ DestroyIcon(GuiData->hIcon);
+ }
+ if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
+ {
+ DestroyIcon(GuiData->hIconSm);
+ }
+
+ GuiData->hIcon = hIcon;
+ GuiData->hIconSm = hIconSm;
+
+ DPRINT("Set icons in GuiChangeIcon\n");
+ PostMessageW(GuiData->hWindow, WM_SETICON, ICON_BIG, (LPARAM)GuiData->hIcon);
+ PostMessageW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
+ }
+
+ return TRUE;
+}
+
+static HWND WINAPI
+GuiGetConsoleWindowHandle(IN OUT PFRONTEND This)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+ return GuiData->hWindow;
+}
+
+static VOID WINAPI
+GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This,
+ PCOORD pSize)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+ PCONSOLE_SCREEN_BUFFER ActiveBuffer;
+ RECT WorkArea;
+ LONG width, height;
+ UINT WidthUnit, HeightUnit;
+
+ if (!pSize) return;
+
+ if (!SystemParametersInfoW(SPI_GETWORKAREA, 0, &WorkArea, 0))
+ {
+ DPRINT1("SystemParametersInfoW failed - What to do ??\n");
+ return;
+ }
+
+ ActiveBuffer = ConDrvGetActiveScreenBuffer(GuiData->Console);
+ if (ActiveBuffer)
+ {
+ GetScreenBufferSizeUnits(ActiveBuffer, GuiData, &WidthUnit, &HeightUnit);
+ }
+ else
+ {
+ /* Default: text mode */
+ WidthUnit = GuiData->CharWidth ;
+ HeightUnit = GuiData->CharHeight;
+ }
+
+ width = WorkArea.right;
+ height = WorkArea.bottom;
+
+ width -= (2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)));
+ height -= (2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION));
+
+ if (width < 0) width = 0;
+ if (height < 0) height = 0;
+
+ pSize->X = (SHORT)(width / (int)WidthUnit ) /* HACK */ + 2;
+ pSize->Y = (SHORT)(height / (int)HeightUnit) /* HACK */ + 1;
+}
+
+static ULONG WINAPI
+GuiGetDisplayMode(IN OUT PFRONTEND This)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+ ULONG DisplayMode = 0;
+
+ if (GuiData->GuiInfo.FullScreen)
+ DisplayMode |= CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN
+ else
+ DisplayMode |= CONSOLE_WINDOWED;
+
+ return DisplayMode;
+}
+
+static BOOL WINAPI
+GuiSetDisplayMode(IN OUT PFRONTEND This,
+ ULONG NewMode)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+
+ if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE))
+ return FALSE;
+
+ GuiData->GuiInfo.FullScreen = (NewMode & CONSOLE_FULLSCREEN_MODE);
+ // TODO: Change the display mode
+ return TRUE;
+}
+
+static INT WINAPI
+GuiShowMouseCursor(IN OUT PFRONTEND This,
+ BOOL Show)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+
+ /* Set the reference count */
+ if (Show) ++GuiData->MouseCursorRefCount;
+ else --GuiData->MouseCursorRefCount;
+
+ /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
+ PostMessageW(GuiData->hWindow, WM_SETCURSOR, -1, -1);
+
+ return GuiData->MouseCursorRefCount;
+}
+
+static BOOL WINAPI
+GuiSetMouseCursor(IN OUT PFRONTEND This,
+ HCURSOR hCursor)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+
+ /*
+ * Set the cursor's handle. If the given handle is NULL,
+ * then restore the default cursor.
+ */
+ GuiData->hCursor = (hCursor ? hCursor : ghDefaultCursor);
+
+ /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
+ PostMessageW(GuiData->hWindow, WM_SETCURSOR, -1, -1);
+
+ return TRUE;
+}
+
+static HMENU WINAPI
+GuiMenuControl(IN OUT PFRONTEND This,
+ UINT cmdIdLow,
+ UINT cmdIdHigh)
+{
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+
+ GuiData->cmdIdLow = cmdIdLow ;
+ GuiData->cmdIdHigh = cmdIdHigh;
+
+ return GetSystemMenu(GuiData->hWindow, FALSE);
+}
+
+static BOOL WINAPI
+GuiSetMenuClose(IN OUT PFRONTEND This,
+ BOOL Enable)
+{
+ /*
+ * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
+ * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
+ * for more information.
+ */
+
+ PGUI_CONSOLE_DATA GuiData = This->Data;
+ HMENU hSysMenu = GetSystemMenu(GuiData->hWindow, FALSE);
+
+ if (hSysMenu == NULL) return FALSE;
+
+ GuiData->IsCloseButtonEnabled = Enable;
+ EnableMenuItem(hSysMenu, SC_CLOSE, MF_BYCOMMAND | (Enable ? MF_ENABLED : MF_GRAYED));
+
+ return TRUE;
+}
+
+static FRONTEND_VTBL GuiVtbl =
+{
+ GuiInitFrontEnd,
+ GuiDeinitFrontEnd,
+ GuiDrawRegion,
+ GuiWriteStream,
+ GuiSetCursorInfo,
+ GuiSetScreenInfo,
+ GuiResizeTerminal,
+ GuiProcessKeyCallback,
+ GuiRefreshInternalInfo,
+ GuiChangeTitle,
+ GuiChangeIcon,
+ GuiGetConsoleWindowHandle,
+ GuiGetLargestConsoleWindowSize,
+ GuiGetDisplayMode,
+ GuiSetDisplayMode,
+ GuiShowMouseCursor,
+ GuiSetMouseCursor,
+ GuiMenuControl,
+ GuiSetMenuClose,
+};
+
+
+static BOOL
+LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
+ IN OUT PCONSOLE_INFO ConsoleInfo)
+{
+#define PATH_SEPARATOR L'\\'
+
+ BOOL RetVal = FALSE;
+ HRESULT hRes = S_OK;
+ LPWSTR LinkName = NULL;
+ SIZE_T Length = 0;
+
+ if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
+ return FALSE;
+
+ ConsoleStartInfo->IconPath[0] = L'\0';
+ ConsoleStartInfo->IconIndex = 0;
+
+ /* 1- Find the last path separator if any */
+ LinkName = wcsrchr(ConsoleStartInfo->ConsoleTitle, PATH_SEPARATOR);
+ if (LinkName == NULL)
+ {
+ LinkName = ConsoleStartInfo->ConsoleTitle;
+ }
+ else
+ {
+ /* Skip the path separator */
+ ++LinkName;
+ }
+
+ /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
+ Length = wcslen(LinkName);
+ if ( (Length <= 4) || (wcsicmp(LinkName + (Length - 4), L".lnk") != 0) )
+ return FALSE;
+
+ /* 3- It may be a link. Try to retrieve some properties */
+ hRes = CoInitialize(NULL);
+ if (SUCCEEDED(hRes))
+ {
+ /* Get a pointer to the IShellLink interface */
+ IShellLinkW* pshl = NULL;
+ hRes = CoCreateInstance(&CLSID_ShellLink,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ &IID_IShellLinkW,
+ (LPVOID*)&pshl);
+ if (SUCCEEDED(hRes))
+ {
+ /* Get a pointer to the IPersistFile interface */
+ IPersistFile* ppf = NULL;
+ hRes = IPersistFile_QueryInterface(pshl, &IID_IPersistFile, (LPVOID*)&ppf);
+ if (SUCCEEDED(hRes))
+ {
+ /* Load the shortcut */
+ hRes = IPersistFile_Load(ppf, ConsoleStartInfo->ConsoleTitle, STGM_READ);
+ if (SUCCEEDED(hRes))
+ {
+ /*
+ * Finally we can get the properties !
+ * Update the old ones if needed.
+ */
+ INT ShowCmd = 0;
+ // WORD HotKey = 0;
+
+ /* Reset the name of the console with the name of the shortcut */
+ Length = min(/*Length*/ Length - 4, // 4 == len(".lnk")
+ sizeof(ConsoleInfo->ConsoleTitle) / sizeof(ConsoleInfo->ConsoleTitle[0]) - 1);
+ wcsncpy(ConsoleInfo->ConsoleTitle, LinkName, Length);
+ ConsoleInfo->ConsoleTitle[Length] = L'\0';
+
+ /* Get the window showing command */
+ hRes = IShellLinkW_GetShowCmd(pshl, &ShowCmd);
+ if (SUCCEEDED(hRes)) ConsoleStartInfo->ShowWindow = (WORD)ShowCmd;
+
+ /* Get the hotkey */
+ // hRes = pshl->GetHotkey(&ShowCmd);
+ // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
+
+ /* Get the icon location, if any */
+
+ hRes = IShellLinkW_GetIconLocation(pshl,
+ ConsoleStartInfo->IconPath,
+ sizeof(ConsoleStartInfo->IconPath)/sizeof(ConsoleStartInfo->IconPath[0]) - 1, // == MAX_PATH
+ &ConsoleStartInfo->IconIndex);
+ if (!SUCCEEDED(hRes))
+ {
+ ConsoleStartInfo->IconPath[0] = L'\0';
+ ConsoleStartInfo->IconIndex = 0;
+ }
+
+ // FIXME: Since we still don't load console properties from the shortcut,
+ // return false. When this will be done, we will return true instead.
+ RetVal = FALSE;
+ }
+ IPersistFile_Release(ppf);
+ }
+ IShellLinkW_Release(pshl);
+ }
+ }
+ CoUninitialize();
+
+ return RetVal;
+}
+
+NTSTATUS NTAPI
+GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
+ IN OUT PCONSOLE_INFO ConsoleInfo,
+ IN OUT PVOID ExtraConsoleInfo,
+ IN ULONG ProcessId)
+{
+ PCONSOLE_START_INFO ConsoleStartInfo = ExtraConsoleInfo;
+ PGUI_INIT_INFO GuiInitInfo;
+
+ if (FrontEnd == NULL || ConsoleInfo == NULL || ConsoleStartInfo == NULL)
+ return STATUS_INVALID_PARAMETER;
+
+ /* Initialize GUI terminal emulator common functionalities */
+ if (!GuiInit()) return STATUS_UNSUCCESSFUL;
+
+ /*
+ * Load per-application terminal settings.
+ *
+ * Check whether the process creating the console was launched via
+ * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
+ * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
+ */
+ if (ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME)
+ {
+ if (!LoadShellLinkConsoleInfo(ConsoleStartInfo, ConsoleInfo))
+ {
+ ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME;
+ }
+ }
+
+ /*
+ * Initialize a private initialization info structure for later use.
+ * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
+ */
+ GuiInitInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(GUI_INIT_INFO));
+ if (GuiInitInfo == NULL) return STATUS_NO_MEMORY;
+
+ // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
+ GuiInitInfo->ConsoleInfo = ConsoleInfo;
+ GuiInitInfo->ConsoleStartInfo = ConsoleStartInfo;
+ GuiInitInfo->ProcessId = ProcessId;
+
+ /* Finally, initialize the frontend structure */
+ FrontEnd->Vtbl = &GuiVtbl;
+ FrontEnd->Data = NULL;
+ FrontEnd->OldData = GuiInitInfo;
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS NTAPI
+GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd)
+{
+ if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER;
+
+ if (FrontEnd->Data) GuiDeinitFrontEnd(FrontEnd);
+ if (FrontEnd->OldData) ConsoleFreeHeap(FrontEnd->OldData);
+
+ return STATUS_SUCCESS;
+}
+
+/* EOF */
--- /dev/null
- if (ServicesProcessIdValid == TRUE)
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS User API Server DLL
+ * FILE: win32ss/user/winsrv/usersrv/register.c
+ * PURPOSE: Register logon window and services process
+ * PROGRAMMERS: Eric Kohl
+ * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include "usersrv.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS ********************************************************************/
+
+static BOOLEAN ServicesProcessIdValid = FALSE;
+static ULONG_PTR ServicesProcessId = 0;
+
+ULONG_PTR LogonProcessId = 0;
+
+/* PUBLIC SERVER APIS *********************************************************/
+
+CSR_API(SrvRegisterLogonProcess)
+{
+ PUSER_REGISTER_LOGON_PROCESS RegisterLogonProcessRequest = &((PUSER_API_MESSAGE)ApiMessage)->Data.RegisterLogonProcessRequest;
+
+ if (RegisterLogonProcessRequest->Register)
+ {
+ if (LogonProcessId != 0)
+ return STATUS_LOGON_SESSION_EXISTS;
+
+ LogonProcessId = RegisterLogonProcessRequest->ProcessId;
+ }
+ else
+ {
+ if (ApiMessage->Header.ClientId.UniqueProcess != (HANDLE)LogonProcessId)
+ {
+ DPRINT1("Current logon process 0x%x, can't deregister from process 0x%x\n",
+ LogonProcessId, ApiMessage->Header.ClientId.UniqueProcess);
+ return STATUS_NOT_LOGON_PROCESS;
+ }
+
+ LogonProcessId = 0;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(SrvRegisterServicesProcess)
+{
+ PUSER_REGISTER_SERVICES_PROCESS RegisterServicesProcessRequest = &((PUSER_API_MESSAGE)ApiMessage)->Data.RegisterServicesProcessRequest;
+
++ if (ServicesProcessIdValid)
+ {
+ /* Only accept a single call */
+ return STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ ServicesProcessId = RegisterServicesProcessRequest->ProcessId;
+ ServicesProcessIdValid = TRUE;
+ return STATUS_SUCCESS;
+ }
+}
+
+/* EOF */