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;
}
+ /* 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(),
}
/* Get the short application name */
- if (!GetShortPathNameW(ApplicationName, ShortAppName, Length))
+ if (GetShortPathNameW(ApplicationName, ShortAppName, Length) == 0)
{
/* Try to determine which error occurred */
switch (GetLastError())
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;
+
+ /* 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);
if (StartupInfo->dwFlags & STARTF_USESTDHANDLES)
{
/* Set the standard handles */
- CheckVdm->StdIn = StartupInfo->hStdInput;
+ CheckVdm->StdIn = StartupInfo->hStdInput;
CheckVdm->StdOut = StartupInfo->hStdOutput;
CheckVdm->StdErr = StartupInfo->hStdError;
}
/* Allocate memory for the ANSI strings */
- AnsiCmdLine = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->CmdLen);
+ // We need to add the newline characters '\r\n' to the command line
+ 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(),
CheckVdm->CmdLen,
NULL,
NULL);
+ /* Add the needed newline and NULL-terminate */
+ CheckVdm->CmdLen--; // Rewind back to the NULL character
+ AnsiCmdLine[CheckVdm->CmdLen++] = '\r';
+ AnsiCmdLine[CheckVdm->CmdLen++] = '\n';
+ AnsiCmdLine[CheckVdm->CmdLen++] = 0;
/* Convert the short application name into an ANSI string */
WideCharToMultiByte(CP_ACP,
/* 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;
}
{
BOOL Result;
ULONG RegionSize, EnvironmentSize = 0;
- PWCHAR p, Environment, NewEnvironment = NULL;
+ PWCHAR SourcePtr, DestPtr, Environment, NewEnvironment = NULL;
+ WCHAR PathBuffer[MAX_PATH];
NTSTATUS Status;
/* Make sure we have both strings */
}
/* Count how much space the whole environment takes */
- p = Environment;
- while ((*p++ != UNICODE_NULL) && (*p != UNICODE_NULL)) EnvironmentSize++;
+ SourcePtr = Environment;
+ while ((*SourcePtr++ != UNICODE_NULL) && (*SourcePtr != UNICODE_NULL)) EnvironmentSize++;
EnvironmentSize += sizeof(UNICODE_NULL);
/* Allocate a new copy */
}
/* Begin parsing the new environment */
- p = NewEnvironment;
+ SourcePtr = Environment;
+ DestPtr = NewEnvironment;
+
+ while (*SourcePtr != UNICODE_NULL)
+ {
+ while (*SourcePtr != UNICODE_NULL)
+ {
+ if (*SourcePtr == L'=')
+ {
+ /* Store the '=' sign */
+ *DestPtr++ = *SourcePtr++;
+
+ /* Check if this is likely a full path */
+ if (isalphaW(SourcePtr[0])
+ && (SourcePtr[1] == L':')
+ && ((SourcePtr[2] == '\\') || (SourcePtr[2] == '/')))
+ {
+ PWCHAR Delimiter = wcschr(SourcePtr, L';');
+ ULONG NumChars;
+
+ if (Delimiter != NULL)
+ {
+ wcsncpy(PathBuffer,
+ SourcePtr,
+ min(Delimiter - SourcePtr, MAX_PATH));
+
+ /* Seek to the part after the delimiter */
+ SourcePtr = Delimiter + 1;
+ }
+ else
+ {
+ wcsncpy(PathBuffer, SourcePtr, MAX_PATH);
- /* FIXME: Code here */
- DPRINT1("BaseCreateVDMEnvironment is half-plemented!\n");
+ /* Seek to the end of the string */
+ SourcePtr = wcschr(SourcePtr, UNICODE_NULL);
+ }
+
+ /* Convert the path into a short path */
+ NumChars = GetShortPathNameW(PathBuffer,
+ DestPtr,
+ EnvironmentSize - (DestPtr - NewEnvironment));
+ if (NumChars)
+ {
+ /*
+ * If it failed, this block won't be executed, so it
+ * will continue from the character after the '=' sign.
+ */
+ DestPtr += NumChars;
+
+ /* Append the delimiter */
+ if (Delimiter != NULL) *DestPtr++ = L';';
+ }
+ }
+ }
+ else if (islowerW(*SourcePtr)) *DestPtr++ = toupperW(*SourcePtr++);
+ else *DestPtr++ = *SourcePtr++;
+ }
+
+ /* Copy the terminating NULL character */
+ *DestPtr++ = *SourcePtr++;
+ }
/* Terminate it */
- *p++ = UNICODE_NULL;
+ *DestPtr++ = UNICODE_NULL;
/* Initialize the unicode string to hold it */
- EnvironmentSize = (p - NewEnvironment) * sizeof(WCHAR);
+ EnvironmentSize = (DestPtr - NewEnvironment) * sizeof(WCHAR);
RtlInitEmptyUnicodeString(UnicodeEnv, NewEnvironment, (USHORT)EnvironmentSize);
UnicodeEnv->Length = (USHORT)EnvironmentSize;
if (!NT_SUCCESS(Status))
{
+ /* Store the correct lengths */
+ CommandData->CmdLen = GetNextVdmCommand->CmdLen;
+ CommandData->AppLen = GetNextVdmCommand->AppLen;
+ CommandData->PifLen = GetNextVdmCommand->PifLen;
+ CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
+ CommandData->EnvLen = GetNextVdmCommand->EnvLen;
+ CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
+ CommandData->TitleLen = GetNextVdmCommand->TitleLen;
+ CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
+
BaseSetLastNTError(Status);
goto Cleanup;
}