[KERNEL32]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 18 May 2014 22:10:45 +0000 (22:10 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 18 May 2014 22:10:45 +0000 (22:10 +0000)
Usually the command line is made of the application name and its parameters. When launching a DOS program, BaseCheckVDM builds suitable ApplicationName and CommandLine strings "DOS-compatible". ApplicationName is left-trimmed for whitespace and then converted to short-path format, and CommandLine sees the application name part (its first token) removed. We didn't do it before, we do it now. Care is taken when quotes are present in ApplicationName. Finally DOS command lines usually receive a newline character, so we also add it there. This is how behave Windows: just put our ntvdm in Windows, and observe what it receives...

svn path=/trunk/; revision=63361

reactos/dll/win32/kernel32/client/vdm.c

index e6fa9c3..ca68383 100644 (file)
@@ -93,26 +93,25 @@ BaseCheckVDM(IN ULONG BinaryType,
     STARTUPINFOA AnsiStartupInfo;
     ULONG NumStrings = 5;
 
-    if (CurrentDirectory == NULL)
+    /* Parameters validation */
+    if (ApplicationName == NULL || CommandLine == NULL)
     {
-        /* Allocate memory for the current directory path */
-        Length = GetCurrentDirectoryW(0, NULL);
-        CurrentDir = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
-                                             HEAP_ZERO_MEMORY,
-                                             Length * sizeof(WCHAR));
-        if (CurrentDir == NULL)
-        {
-            Status = STATUS_NO_MEMORY;
-            goto Cleanup;
-        }
-
-        /* Get the current directory */
-        GetCurrentDirectoryW(Length, CurrentDir);
-        CurrentDirectory = CurrentDir;
+        return STATUS_INVALID_PARAMETER;
     }
 
+    DPRINT1("Before: ApplicationName = '%S' ; CommandLine = '%S'\n", ApplicationName, CommandLine);
+
+    /* Trim leading whitespace from ApplicationName */
+    while (*ApplicationName == L' ' || *ApplicationName == L'\t')
+        ++ApplicationName;
+
     /* Calculate the size of the short application name */
     Length = GetShortPathNameW(ApplicationName, NULL, 0);
+    if (Length == 0)
+    {
+        Status = STATUS_OBJECT_PATH_INVALID;
+        goto Cleanup;
+    }
 
     /* Allocate memory for the short application name */
     ShortAppName = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
@@ -125,7 +124,7 @@ BaseCheckVDM(IN ULONG BinaryType,
     }
 
     /* Get the short application name */
-    if (!GetShortPathNameW(ApplicationName, ShortAppName, Length))
+    if (GetShortPathNameW(ApplicationName, ShortAppName, Length) == 0)
     {
         /* Try to determine which error occurred */
         switch (GetLastError())
@@ -151,6 +150,83 @@ BaseCheckVDM(IN ULONG BinaryType,
         goto Cleanup;
     }
 
+    /* Trim leading whitespace from CommandLine */
+    while (*CommandLine == L' ' || *CommandLine == L'\t')
+        ++CommandLine;
+
+    /*
+     * CommandLine is usually formatted as: 'ApplicationName param0 ...'.
+     * So we want to strip the first token (ApplicationName) from it.
+     * Two cases are in fact possible:
+     * - either the first token is indeed ApplicationName, so we just skip it;
+     * - or the first token is not exactly ApplicationName, because it happened
+     *   that somebody else already preprocessed CommandLine. Therefore we
+     *   suppose that the first token corresponds to an application name and
+     *   we skip it. Care should be taken when quotes are present in this token.
+     */
+
+     if (*CommandLine)
+     {
+        /* The first part of CommandLine should be the ApplicationName... */
+        Length = wcslen(ApplicationName);
+        if (Length <= wcslen(CommandLine) &&
+            _wcsnicmp(ApplicationName, CommandLine, Length) == 0)
+        {
+            /* Skip it */
+            CommandLine += Length;
+        }
+        /*
+         * ... but it is not, however we still have a token. We suppose that
+         * it corresponds to some sort of application name, so we skip it too.
+         */
+        else
+        {
+            /* Get rid of the first token. We stop when we see whitespace. */
+            while (*CommandLine && !(*CommandLine == L' ' || *CommandLine == L'\t'))
+            {
+                if (*CommandLine == L'\"')
+                {
+                    /* We enter a quoted part, skip it */
+                    ++CommandLine;
+                    while (*CommandLine && *CommandLine++ != L'\"') ;
+                }
+                else
+                {
+                    /* Go to the next character */
+                    ++CommandLine;
+                }
+            }
+        }
+    }
+
+    /*
+     * Trim remaining whitespace from CommandLine that may be
+     * present between the application name and the parameters.
+     */
+    while (*CommandLine == L' ' || *CommandLine == L'\t')
+        ++CommandLine;
+
+    DPRINT1("After: ApplicationName = '%S' ; CommandLine = '%S'\n", ApplicationName, CommandLine);
+
+    /* Get the current directory */
+    if (CurrentDirectory == NULL)
+    {
+        /* Allocate memory for the current directory path */
+        Length = GetCurrentDirectoryW(0, NULL);
+        CurrentDir = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
+                                             HEAP_ZERO_MEMORY,
+                                             Length * sizeof(WCHAR));
+        if (CurrentDir == NULL)
+        {
+            Status = STATUS_NO_MEMORY;
+            goto Cleanup;
+        }
+
+        /* Get the current directory */
+        GetCurrentDirectoryW(Length, CurrentDir);
+        CurrentDirectory = CurrentDir;
+    }
+
     /* Calculate the size of the short current directory path */
     Length = GetShortPathNameW(CurrentDirectory, NULL, 0);
 
@@ -214,7 +290,9 @@ BaseCheckVDM(IN ULONG BinaryType,
     }
 
     /* Allocate memory for the ANSI strings */
-    AnsiCmdLine = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->CmdLen);
+
+    /* For the command line we need to add two characters needed for newline '\r\n' */
+    AnsiCmdLine = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->CmdLen + 2);
     AnsiAppName = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->AppLen);
     AnsiCurDirectory = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->CurDirectoryLen);
     if (StartupInfo->lpDesktop) AnsiDesktop = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
@@ -247,6 +325,11 @@ BaseCheckVDM(IN ULONG BinaryType,
                         CheckVdm->CmdLen,
                         NULL,
                         NULL);
+    /* Add a needed newline '\r\n' */
+    CheckVdm->CmdLen--; // FIXME....
+    AnsiCmdLine[CheckVdm->CmdLen    ] = '\r';
+    AnsiCmdLine[CheckVdm->CmdLen + 1] = '\n';
+    CheckVdm->CmdLen += 2;
 
     /* Convert the short application name into an ANSI string */
     WideCharToMultiByte(CP_ACP,
@@ -417,13 +500,13 @@ Cleanup:
     /* Free the capture buffer */
     CsrFreeCaptureBuffer(CaptureBuffer);
 
-    /* Free the short paths */
-    if (ShortAppName) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortAppName);
+    /* Free the current directory, if it was allocated here, and its short path */
     if (ShortCurrentDir) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortCurrentDir);
-
-    /* Free the current directory, if it was allocated here */
     if (CurrentDir) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDir);
 
+    /* Free the short app name */
+    if (ShortAppName) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortAppName);
+
     return Status;
 }