Implement GdiGetCharDimensions by Robert Shearman rob(a)codeweavers.com.
Modified: trunk/reactos/lib/gdi32/misc/stubs.c
Modified: trunk/reactos/lib/gdi32/objects/font.c
Modified: trunk/reactos/lib/gdi32/objects/text.c
_____
Modified: trunk/reactos/lib/gdi32/misc/stubs.c
--- trunk/reactos/lib/gdi32/misc/stubs.c 2005-07-19 03:13:11 UTC
(rev 16640)
+++ trunk/reactos/lib/gdi32/misc/stubs.c 2005-07-19 11:18:40 UTC
(rev 16641)
@@ -2772,17 +2772,6 @@
return 0;
}
-/*
- * @unimplemented
- */
-DWORD
-STDCALL
-GdiGetCharDimensions(HDC hdc,LPTEXTMETRICW lptm,BOOL unk)
-{
- UNIMPLEMENTED;
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return 0;
-}
/*
* @unimplemented
_____
Modified: trunk/reactos/lib/gdi32/objects/font.c
--- trunk/reactos/lib/gdi32/objects/font.c 2005-07-19 03:13:11 UTC
(rev 16640)
+++ trunk/reactos/lib/gdi32/objects/font.c 2005-07-19 11:18:40 UTC
(rev 16641)
@@ -782,3 +782,49 @@
return rc;
}
+
+/**********************************************************************
*
+ * GdiGetCharDimensions
+ *
+ * Gets the average width of the characters in the English alphabet.
+ *
+ * PARAMS
+ * hdc [I] Handle to the device context to measure on.
+ * lptm [O] Pointer to memory to store the text metrics into.
+ * height [O] On exit, the maximum height of characters in the English
alphabet.
+ *
+ * RETURNS
+ * The average width of characters in the English alphabet.
+ *
+ * NOTES
+ * This function is used by the dialog manager to get the size of a
dialog
+ * unit. It should also be used by other pieces of code that need to
know
+ * the size of a dialog unit in logical units without having access to
the
+ * window handle of the dialog.
+ * Windows caches the font metrics from this function, but we don't
and
+ * there doesn't appear to be an immediate advantage to do so.
+ *
+ * SEE ALSO
+ * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
+ */
+/*
+ * @implemented
+ */
+DWORD
+STDCALL
+GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, DWORD *height)
+{
+ SIZE sz;
+ static const WCHAR alphabet[] = {
+
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
+
'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
+
'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
0};
+
+ if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
+
+ if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
+
+ if (height) *height = sz.cy;
+ return (sz.cx / 26 + 1) / 2;
+}
+
_____
Modified: trunk/reactos/lib/gdi32/objects/text.c
--- trunk/reactos/lib/gdi32/objects/text.c 2005-07-19 03:13:11 UTC
(rev 16640)
+++ trunk/reactos/lib/gdi32/objects/text.c 2005-07-19 11:18:40 UTC
(rev 16641)
@@ -309,3 +309,5 @@
HeapFree( GetProcessHeap(), 0, nameW );
return res;
}
+
+
make GetRootPath bit smarter
Modified: trunk/reactos/subsys/system/cmd/internal.c
_____
Modified: trunk/reactos/subsys/system/cmd/internal.c
--- trunk/reactos/subsys/system/cmd/internal.c 2005-07-18 23:04:39 UTC
(rev 16637)
+++ trunk/reactos/subsys/system/cmd/internal.c 2005-07-19 01:36:54 UTC
(rev 16638)
@@ -159,33 +159,44 @@
INT GetRootPath(TCHAR *InPath,TCHAR *OutPath,INT size)
{
INT retcode = 1;
- INT t;
+
if (_tcslen(InPath)>1)
{
- if (InPath[1]==_T(':'))
+ if (InPath[1]==_T(':'))
{
- for (t=0;t<32;t++)
- {
- if (_tgetdcwd(t,OutPath,size) != NULL)
- {
- if (_tcsncicmp(InPath,OutPath,2))
- {
- retcode = 0;
- return retcode;
- }
- }
- }
- }
- }
+ TCHAR num[2];
+ INT t=0;
+
+ num[1] = _T('\0');
+ num[0] = InPath[0];
+ _tcslwr(num);
+
+ if ((InPath[0] >= _T('0')) && (InPath[0] <= _T('9')))
+ {
+ t = (InPath[0] - _T('0')) +28;
+ }
+
+ if ((InPath[0] >= _T('a')) && (InPath[0] <= _T('z')))
+ {
+ t = (InPath[0] - _T('a')) +1;
+ }
+
+ if (_tgetdcwd(t,OutPath,size) != NULL)
+ {
+ return 0;
+ }
+ }
+ }
- /* fail to getting path devic did not exists */
+ /* fail */
if (_tcslen(InPath)>1)
{
if (InPath[1]==_T(':'))
return 1;
}
+ /* Get current directory */
retcode = GetCurrentDirectory(size,OutPath);
if (retcode==0)
return 1;
@@ -220,6 +231,7 @@
nErrorLevel = 0;
+
/* The whole param string is our parameter these days. The only
thing we do is eliminating every quotation mark */
/* Is it safe to change the characters param is pointing to? I
presume it is, as there doesn't seem to be any
post-processing of it after the function call (what would that
accomplish?) */
make GetRootPath bit faster if it does not get a drive name with :
Modified: trunk/reactos/subsys/system/cmd/internal.c
_____
Modified: trunk/reactos/subsys/system/cmd/internal.c
--- trunk/reactos/subsys/system/cmd/internal.c 2005-07-18 22:44:13 UTC
(rev 16636)
+++ trunk/reactos/subsys/system/cmd/internal.c 2005-07-18 23:04:39 UTC
(rev 16637)
@@ -148,10 +148,10 @@
free (lpLastPath);
}
-/* help functions for getting current path from driver
- without changing driver. Return code 0 = ok, 1 = fail.
+/* help functions for getting current path from drive
+ without changing drive. Return code 0 = ok, 1 = fail.
INT GetRootPath("C:",outbuffer,chater size of outbuffer);
- the frist param can have any size, if the the two frist
+ the first param can have any size, if the the two frist
letter are not a drive with : it will get Currentpath on
current drive exacly as GetCurrentDirectory does.
*/
@@ -161,17 +161,23 @@
INT retcode = 1;
INT t;
- for (t=0;t<32;t++)
- {
- if (_tgetdcwd(t,OutPath,size) != NULL)
- {
- if (_tcsncicmp(InPath,OutPath,2))
- {
- retcode = 0;
- return retcode;
- }
- }
- }
+ if (_tcslen(InPath)>1)
+ {
+ if (InPath[1]==_T(':'))
+ {
+ for (t=0;t<32;t++)
+ {
+ if (_tgetdcwd(t,OutPath,size) != NULL)
+ {
+ if (_tcsncicmp(InPath,OutPath,2))
+ {
+ retcode = 0;
+ return retcode;
+ }
+ }
+ }
+ }
+ }
/* fail to getting path devic did not exists */
if (_tcslen(InPath)>1)
add a new interal function call GetRootPath(TCHAR *InPath,TCHAR
*OutPath,INT size) it get the a driver current path without change the
current driver directory, it is not in use yet, prep for copy, cd, rm,
and all other commands.
Modified: trunk/reactos/subsys/system/cmd/cmd.h
Modified: trunk/reactos/subsys/system/cmd/internal.c
Modified: trunk/reactos/subsys/system/cmd/precomp.h
_____
Modified: trunk/reactos/subsys/system/cmd/cmd.h
--- trunk/reactos/subsys/system/cmd/cmd.h 2005-07-18 19:50:23 UTC
(rev 16635)
+++ trunk/reactos/subsys/system/cmd/cmd.h 2005-07-18 22:44:13 UTC
(rev 16636)
@@ -291,6 +291,7 @@
/* Prototypes for MISC.C */
+INT GetRootPath(TCHAR *InPath,TCHAR *OutPath,INT size);
TCHAR cgetchar (VOID);
BOOL CheckCtrlBreak (INT);
LPTSTR *split (LPTSTR, LPINT, BOOL);
_____
Modified: trunk/reactos/subsys/system/cmd/internal.c
--- trunk/reactos/subsys/system/cmd/internal.c 2005-07-18 19:50:23 UTC
(rev 16635)
+++ trunk/reactos/subsys/system/cmd/internal.c 2005-07-18 22:44:13 UTC
(rev 16636)
@@ -148,6 +148,46 @@
free (lpLastPath);
}
+/* help functions for getting current path from driver
+ without changing driver. Return code 0 = ok, 1 = fail.
+ INT GetRootPath("C:",outbuffer,chater size of outbuffer);
+ the frist param can have any size, if the the two frist
+ letter are not a drive with : it will get Currentpath on
+ current drive exacly as GetCurrentDirectory does.
+ */
+
+INT GetRootPath(TCHAR *InPath,TCHAR *OutPath,INT size)
+{
+ INT retcode = 1;
+ INT t;
+
+ for (t=0;t<32;t++)
+ {
+ if (_tgetdcwd(t,OutPath,size) != NULL)
+ {
+ if (_tcsncicmp(InPath,OutPath,2))
+ {
+ retcode = 0;
+ return retcode;
+ }
+ }
+ }
+
+ /* fail to getting path devic did not exists */
+ if (_tcslen(InPath)>1)
+ {
+ if (InPath[1]==_T(':'))
+ return 1;
+ }
+
+ retcode = GetCurrentDirectory(size,OutPath);
+ if (retcode==0)
+ return 1;
+
+ return 0;
+}
+
+
/*
* CD / CHDIR
*
_____
Modified: trunk/reactos/subsys/system/cmd/precomp.h
--- trunk/reactos/subsys/system/cmd/precomp.h 2005-07-18 19:50:23 UTC
(rev 16635)
+++ trunk/reactos/subsys/system/cmd/precomp.h 2005-07-18 22:44:13 UTC
(rev 16636)
@@ -4,6 +4,8 @@
#include <shellapi.h>
#include <tchar.h>
+#include <direct.h>
+
#include <ctype.h>
#include <string.h>
#include <stdio.h>
@@ -15,3 +17,4 @@
#include "cmd.h"
#include "config.h"
#include "batch.h"
+
- Fix nasty APC delivery bug (in case a Kernel-Mode Special APC still
returned with a Normal Routine, the Normal Routine was called with
incorrect values (Special Routines take PVOID* arguments, while Normal
Routines do not!))
- Remove APC from list before setting it to non-inserted.
- Do proper thread termination piggybacking; terminate threads in
user-mode as Hartmut correctly fixed.
Modified: trunk/reactos/ntoskrnl/ke/apc.c
Modified: trunk/reactos/ntoskrnl/ps/kill.c
_____
Modified: trunk/reactos/ntoskrnl/ke/apc.c
--- trunk/reactos/ntoskrnl/ke/apc.c 2005-07-18 15:05:58 UTC (rev
16634)
+++ trunk/reactos/ntoskrnl/ke/apc.c 2005-07-18 19:50:23 UTC (rev
16635)
@@ -567,9 +567,9 @@
Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);
/* Save Parameters so that it's safe to free the Object in
Kernel Routine*/
- NormalRoutine = Apc->NormalRoutine;
- KernelRoutine = Apc->KernelRoutine;
- NormalContext = Apc->NormalContext;
+ NormalRoutine = Apc->NormalRoutine;
+ KernelRoutine = Apc->KernelRoutine;
+ NormalContext = Apc->NormalContext;
SystemArgument1 = Apc->SystemArgument1;
SystemArgument2 = Apc->SystemArgument2;
@@ -577,8 +577,8 @@
if (NormalRoutine == NULL) {
/* Remove the APC from the list */
+ RemoveEntryList(ApcListEntry);
Apc->Inserted = FALSE;
- RemoveEntryList(ApcListEntry);
/* Go back to APC_LEVEL */
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
@@ -586,10 +586,10 @@
/* Call the Special APC */
DPRINT("Delivering a Special APC: %x\n", Apc);
KernelRoutine(Apc,
- &NormalRoutine,
- &NormalContext,
- &SystemArgument1,
- &SystemArgument2);
+ &NormalRoutine,
+ &NormalContext,
+ &SystemArgument1,
+ &SystemArgument2);
/* Raise IRQL and Lock again */
KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
@@ -612,8 +612,8 @@
}
/* Dequeue the APC */
+ Apc->Inserted = FALSE;
RemoveEntryList(ApcListEntry);
- Apc->Inserted = FALSE;
/* Go back to APC_LEVEL */
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
@@ -621,10 +621,10 @@
/* Call the Kernel APC */
DPRINT("Delivering a Normal APC: %x\n", Apc);
KernelRoutine(Apc,
- &NormalRoutine,
- &NormalContext,
- &SystemArgument1,
- &SystemArgument2);
+ &NormalRoutine,
+ &NormalContext,
+ &SystemArgument1,
+ &SystemArgument2);
/* If There still is a Normal Routine, then we need to call
this at PASSIVE_LEVEL */
if (NormalRoutine != NULL) {
@@ -635,7 +635,7 @@
/* Call and Raise IRQ back to APC_LEVEL */
DPRINT("Calling the Normal Routine for a Normal APC:
%x\n", Apc);
- NormalRoutine(&NormalContext, &SystemArgument1,
&SystemArgument2);
+ NormalRoutine(NormalContext, SystemArgument1,
SystemArgument2);
KeRaiseIrql(APC_LEVEL, &OldIrql);
}
@@ -657,23 +657,23 @@
Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);
/* Save Parameters so that it's safe to free the Object in
Kernel Routine*/
- NormalRoutine = Apc->NormalRoutine;
- KernelRoutine = Apc->KernelRoutine;
- NormalContext = Apc->NormalContext;
+ NormalRoutine = Apc->NormalRoutine;
+ KernelRoutine = Apc->KernelRoutine;
+ NormalContext = Apc->NormalContext;
SystemArgument1 = Apc->SystemArgument1;
SystemArgument2 = Apc->SystemArgument2;
/* Remove the APC from Queue, restore IRQL and call the APC */
RemoveEntryList(ApcListEntry);
Apc->Inserted = FALSE;
+ KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
- KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
DPRINT("Calling the Kernel Routine for for a User APC: %x\n",
Apc);
KernelRoutine(Apc,
- &NormalRoutine,
- &NormalContext,
- &SystemArgument1,
- &SystemArgument2);
+ &NormalRoutine,
+ &NormalContext,
+ &SystemArgument1,
+ &SystemArgument2);
if (NormalRoutine == NULL) {
@@ -685,11 +685,11 @@
/* Set up the Trap Frame and prepare for Execution in
NTDLL.DLL */
DPRINT("Delivering a User APC: %x\n", Apc);
KiInitializeUserApc(Reserved,
- TrapFrame,
- NormalRoutine,
- NormalContext,
- SystemArgument1,
- SystemArgument2);
+ TrapFrame,
+ NormalRoutine,
+ NormalContext,
+ SystemArgument1,
+ SystemArgument2);
}
} else {
_____
Modified: trunk/reactos/ntoskrnl/ps/kill.c
--- trunk/reactos/ntoskrnl/ps/kill.c 2005-07-18 15:05:58 UTC (rev
16634)
+++ trunk/reactos/ntoskrnl/ps/kill.c 2005-07-18 19:50:23 UTC (rev
16635)
@@ -346,18 +346,23 @@
PVOID* SystemArgument1,
PVOID* SystemArguemnt2)
{
- NTSTATUS ExitStatus = (NTSTATUS)Apc->NormalContext;
+ DPRINT1("PsExitSpecialApc called: 0x%x (proc: 0x%x)\n",
+ PsGetCurrentThread(), PsGetCurrentProcess());
- DPRINT("PsExitSpecialApc called: 0x%x (proc: 0x%x)\n",
PsGetCurrentThread(), PsGetCurrentProcess());
+ /* Don't do anything unless we are in User-Mode */
+ if (Apc->SystemArgument2)
+ {
+ NTSTATUS ExitStatus = (NTSTATUS)Apc->NormalContext;
- /* Free the APC */
- ExFreePool(Apc);
+ /* Free the APC */
+ ExFreePool(Apc);
- /* Terminate the Thread */
- PspExitThread(ExitStatus);
+ /* Terminate the Thread */
+ PspExitThread(ExitStatus);
- /* we should never reach this point! */
- KEBUGCHECK(0);
+ /* we should never reach this point! */
+ KEBUGCHECK(0);
+ }
}
VOID
@@ -366,14 +371,46 @@
PVOID SystemArgument1,
PVOID SystemArgument2)
{
- /* Not fully supported yet... must work out some issues that
- * I don't understand yet -- Alex
- */
- DPRINT1("APC2\n");
- PspExitThread((NTSTATUS)NormalContext);
+ PKAPC Apc = (PKAPC)SystemArgument1;
+ PETHREAD Thread = PsGetCurrentThread();
+ NTSTATUS ExitStatus;
+
+ DPRINT1("PspExitNormalApc called: 0x%x (proc: 0x%x)\n",
+ PsGetCurrentThread(), PsGetCurrentProcess());
- /* we should never reach this point! */
- KEBUGCHECK(0);
+ /* This should never happen */
+ ASSERT(!SystemArgument2);
+
+ /* If this is a system thread, we can safely kill it from
Kernel-Mode */
+ if (PsIsSystemThread(Thread))
+ {
+ /* Get the Exit Status */
+ DPRINT1("Killing System Thread\n");
+ ExitStatus = (NTSTATUS)Apc->NormalContext;
+
+ /* Free the APC */
+ ExFreePool(Apc);
+
+ /* Exit the Thread */
+ PspExitThread(ExitStatus);
+ }
+
+ /* If we're here, this is not a System Thread, so kill it from
User-Mode */
+ DPRINT1("Initializing User-Mode APC\n");
+ KeInitializeApc(Apc,
+ &Thread->Tcb,
+ OriginalApcEnvironment,
+ PsExitSpecialApc,
+ NULL,
+ PspExitNormalApc,
+ UserMode,
+ NormalContext);
+
+ /* Now insert the APC with the User-Mode Flag */
+ KeInsertQueueApc(Apc, Apc, (PVOID)UserMode, 2);
+
+ /* Forcefully resume the thread */
+ KeForceResumeThread(&Thread->Tcb);
}
/*
@@ -402,14 +439,14 @@
/* Allocate the APC */
Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC),
TAG_TERMINATE_APC);
- /* Initialize a User Mode APC to Kill the Thread */
+ /* Initialize a Kernel Mode APC to Kill the Thread */
KeInitializeApc(Apc,
&Thread->Tcb,
OriginalApcEnvironment,
PsExitSpecialApc,
NULL,
PspExitNormalApc,
- UserMode,
+ KernelMode,
(PVOID)ExitStatus);
/* Insert it into the APC Queue */
Removed the message also from the senders queue (in
MsqCleanupMessageQueue).
Modified: trunk/reactos/subsys/win32k/ntuser/msgqueue.c
_____
Modified: trunk/reactos/subsys/win32k/ntuser/msgqueue.c
--- trunk/reactos/subsys/win32k/ntuser/msgqueue.c 2005-07-18
14:10:56 UTC (rev 16633)
+++ trunk/reactos/subsys/win32k/ntuser/msgqueue.c 2005-07-18
15:05:58 UTC (rev 16634)
@@ -1423,6 +1423,13 @@
CurrentSentMessage = CONTAINING_RECORD(CurrentEntry,
USER_SENT_MESSAGE,
ListEntry);
+ IntLockMessageQueue(CurrentSentMessage->SenderQueue);
+ /* remove the message from the dispatching list */
+ if(CurrentSentMessage->DispatchingListEntry.Flink != NULL)
+ {
+ RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
+ }
+
DPRINT("Notify the sender, the thread has been terminated while
dispatching a message!\n");
/* wake the sender's thread */
@@ -1430,7 +1437,8 @@
{
KeSetEvent(CurrentSentMessage->CompletionEvent,
IO_NO_INCREMENT, FALSE);
}
-
+ IntUnLockMessageQueue(CurrentSentMessage->SenderQueue);
+
/* dereference our and the sender's message queue */
IntDereferenceMessageQueue(MessageQueue);
IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue);