rundll32: Rewrite command line parsing.

Windows doesn't do any fancy unescaping.
This commit is contained in:
Alexandre Julliard 2024-11-14 11:53:36 +01:00
parent c20bf25556
commit 5c597119a0

View file

@ -191,90 +191,33 @@ static void *get_entry_point32( HMODULE module, LPCWSTR entry, BOOL *unicode )
return ret; return ret;
} }
static LPWSTR get_next_arg(LPWSTR *cmdline) static WCHAR *parse_arguments( WCHAR *cmdline, WCHAR **dll, WCHAR **entrypoint )
{ {
LPWSTR s; WCHAR *p;
LPWSTR arg,d;
BOOL in_quotes;
int bcount,len=0;
/* count the chars */ if (cmdline[0] == '"')
bcount=0; p = wcschr( ++cmdline, '"' );
in_quotes=FALSE; else
s=*cmdline; p = wcspbrk( cmdline, L" ,\t" );
while (1) {
if (*s==0 || ((*s=='\t' || *s==' ') && !in_quotes)) {
/* end of this command line argument */
break;
} else if (*s=='\\') {
/* '\', count them */
bcount++;
} else if ((*s=='"') && ((bcount & 1)==0)) {
/* unescaped '"' */
in_quotes=!in_quotes;
bcount=0;
} else {
/* a regular character */
bcount=0;
}
s++;
len++;
}
arg=malloc( (len+1)*sizeof(WCHAR) );
if (!arg)
return NULL;
bcount=0; if (!p) return NULL;
in_quotes=FALSE; *p++ = 0;
d=arg; *dll = cmdline;
s=*cmdline; /* skip spaces and commas */
while (*s) { p += wcsspn( p, L" ,\t" );
if ((*s=='\t' || *s==' ') && !in_quotes) { if (!*p) return NULL;
/* end of this command line argument */ *entrypoint = p;
break; /* find end of entry point string */
} else if (*s=='\\') { p += wcscspn( p, L" \t" );
/* '\\' */ if (*p) *p++ = 0;
*d++=*s++; p += wcsspn( p, L" \t" );
bcount++; return p;
} else if (*s=='"') {
/* '"' */
if ((bcount & 1)==0) {
/* Preceded by an even number of '\', this is half that
* number of '\', plus a quote which we erase.
*/
d-=bcount/2;
in_quotes=!in_quotes;
s++;
} else {
/* Preceded by an odd number of '\', this is half that
* number of '\' followed by a '"'
*/
d=d-bcount/2-1;
*d++='"';
s++;
}
bcount=0;
} else {
/* a regular character */
*d++=*s++;
bcount=0;
}
}
*d=0;
*cmdline=s;
/* skip the remaining spaces */
while (**cmdline=='\t' || **cmdline==' ') {
(*cmdline)++;
}
return arg;
} }
int WINAPI wWinMain(HINSTANCE instance, HINSTANCE hOldInstance, LPWSTR szCmdLine, int nCmdShow) int WINAPI wWinMain(HINSTANCE instance, HINSTANCE hOldInstance, LPWSTR szCmdLine, int nCmdShow)
{ {
HWND hWnd; HWND hWnd;
LPWSTR szDllName,szEntryPoint; LPWSTR szDllName, szEntryPoint, args;
void *entry_point = NULL; void *entry_point = NULL;
BOOL unicode = FALSE, win16 = FALSE; BOOL unicode = FALSE, win16 = FALSE;
HMODULE hDll, hCtx; HMODULE hDll, hCtx;
@ -289,16 +232,11 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE hOldInstance, LPWSTR szCmdLine
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, NULL, NULL); CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, NULL, NULL);
/* Get the dll name and API EntryPoint */ /* Get the dll name and API EntryPoint */
WINE_TRACE("CmdLine=%s\n",wine_dbgstr_w(szCmdLine)); args = parse_arguments( wcsdup(szCmdLine), &szDllName, &szEntryPoint );
szDllName = get_next_arg(&szCmdLine); if (!args) return 0;
if (!szDllName || *szDllName==0)
return 0; TRACE( "dll %s entry %s cmdline %s\n", wine_dbgstr_w(szDllName),
WINE_TRACE("DllName=%s\n",wine_dbgstr_w(szDllName)); wine_dbgstr_w(szEntryPoint), wine_dbgstr_w(args) );
if ((szEntryPoint = wcschr(szDllName, ',' )))
*szEntryPoint++=0;
else
szEntryPoint = get_next_arg(&szCmdLine);
WINE_TRACE("EntryPoint=%s\n",wine_dbgstr_w(szEntryPoint));
/* Activate context before DllMain() is called */ /* Activate context before DllMain() is called */
if (SearchPathW(NULL, szDllName, NULL, ARRAY_SIZE(path), path, NULL)) if (SearchPathW(NULL, szDllName, NULL, ARRAY_SIZE(path), path, NULL))
@ -347,19 +285,19 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE hOldInstance, LPWSTR szCmdLine
if (unicode) if (unicode)
{ {
WINE_TRACE( "Calling %s (%p,%p,%s,%d)\n", wine_dbgstr_w(szEntryPoint), WINE_TRACE( "Calling %s (%p,%p,%s,%d)\n", wine_dbgstr_w(szEntryPoint),
hWnd, instance, wine_dbgstr_w(szCmdLine), info.wShowWindow ); hWnd, instance, wine_dbgstr_w(args), info.wShowWindow );
call_entry_point( entry_point, hWnd, instance, szCmdLine, info.wShowWindow ); call_entry_point( entry_point, hWnd, instance, args, info.wShowWindow );
} }
else else
{ {
DWORD len = WideCharToMultiByte( CP_ACP, 0, szCmdLine, -1, NULL, 0, NULL, NULL ); DWORD len = WideCharToMultiByte( CP_ACP, 0, args, -1, NULL, 0, NULL, NULL );
char *cmdline = malloc( len ); char *cmdline = malloc( len );
if (!cmdline) if (!cmdline)
return 0; return 0;
WideCharToMultiByte( CP_ACP, 0, szCmdLine, -1, cmdline, len, NULL, NULL ); WideCharToMultiByte( CP_ACP, 0, args, -1, cmdline, len, NULL, NULL );
WINE_TRACE( "Calling %s (%p,%p,%s,%d)\n", wine_dbgstr_w(szEntryPoint), WINE_TRACE( "Calling %s (%p,%p,%s,%d)\n", wine_dbgstr_w(szEntryPoint),
hWnd, instance, wine_dbgstr_a(cmdline), info.wShowWindow ); hWnd, instance, wine_dbgstr_a(cmdline), info.wShowWindow );