ChangeLog: * rundll32 requires a window for some functions to work, so create one
Index: programs/rundll32/Makefile.in =================================================================== RCS file: /home/wine/wine/programs/rundll32/Makefile.in,v retrieving revision 1.1 diff -u -u -w -r1.1 Makefile.in --- programs/rundll32/Makefile.in 15 Nov 2002 01:41:20 -0000 1.1 +++ programs/rundll32/Makefile.in 17 Jul 2003 21:06:09 -0000 @@ -4,7 +4,7 @@ VPATH = @srcdir@ MODULE = rundll32.exe APPMODE = cui -IMPORTS = kernel32 +IMPORTS = kernel32 user32 C_SRCS = \ rundll32.c Index: programs/rundll32/rundll32.c =================================================================== RCS file: /home/wine/wine/programs/rundll32/rundll32.c,v retrieving revision 1.3 diff -u -u -w -r1.3 rundll32.c --- programs/rundll32/rundll32.c 18 Nov 2002 19:42:13 -0000 1.3 +++ programs/rundll32/rundll32.c 17 Jul 2003 21:06:09 -0000 @@ -2,6 +2,8 @@ * PURPOSE: Load a DLL and run an entry point with the specified parameters * * Copyright 2002 Alberto Massari + * Copyright (c) Aric Steward for Codeweavers 2001-2003 + * Copyright (c) Mike McCormack for Codeweavers 2003 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,102 +29,256 @@ * */ -/** - * FIXME - currently receives command-line parameters in ASCII only and later - * converts to Unicode. Ideally the function should have wWinMain entry point - * and then work in Unicode only, but it seems Wine does not have necessary - * support. - */ - -#include "config.h" -#include "wine/port.h" - #include <stdio.h> #include <string.h> +#include <stdlib.h> + +/* Exclude rarely-used stuff from Windows headers */ +#define WIN32_LEAN_AND_MEAN #include <windows.h> +#include <wine/debug.h> -typedef void (*EntryPointW) (HWND hWnd, HINSTANCE hInst, LPWSTR lpszCmdLine, int nCmdShow); -typedef void (*EntryPointA) (HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow); +WINE_DEFAULT_DEBUG_CHANNEL(rundll32); -/** - * Loads procedure. - * - * Parameters: - * strDll - name of the dll. - * procName - name of the procedure to load from dll - * pDllHanlde - output variable receives handle of the loaded dll. + +/* + * Control_RunDLL has these parameters */ -static FARPROC LoadProc(char* strDll, char* procName, HMODULE* DllHandle) -{ - FARPROC proc; +typedef void (WINAPI *EntryPointW)(HWND hWnd, HINSTANCE hInst, LPWSTR lpszCmdLine, int nCmdShow); +typedef void (WINAPI *EntryPointA)(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow); + +/* + * Control_RunDLL needs to have a window. So lets make us a very + * simple window class. + */ +static TCHAR *szTitle = "rundll32"; +static TCHAR *szWindowClass = "class_rundll32"; - *DllHandle = LoadLibrary(strDll); - if(!*DllHandle) +static ATOM MyRegisterClass(HINSTANCE hInstance) { - exit(-1); + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)DefWindowProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = NULL; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = NULL; + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = NULL; + + return RegisterClassEx(&wcex); } - proc = GetProcAddress(*DllHandle, procName); - if(!proc) + +static LPWSTR GetNextArg(LPCWSTR *cmdline) { - FreeLibrary(*DllHandle); + LPCWSTR s; + LPWSTR arg,d; + int in_quotes,bcount,len=0; + + /* count the chars */ + bcount=0; + in_quotes=0; + s=*cmdline; + while (1) { + if (*s==0 || ((*s==0x0009 || *s==0x0020) && !in_quotes)) { + /* end of this command line argument */ + break; + } else if (*s==0x005c) { + /* '\', count them */ + bcount++; + } else if ((*s==0x0022) && ((bcount & 1)==0)) { + /* unescaped '"' */ + in_quotes=!in_quotes; + bcount=0; + } else { + /* a regular character */ + bcount=0; + } + s++; + len++; + } + arg=HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR)); + if (!arg) return NULL; + + bcount=0; + in_quotes=0; + d=arg; + s=*cmdline; + while (*s) { + if ((*s==0x0009 || *s==0x0020) && !in_quotes) { + /* end of this command line argument */ + break; + } else if (*s==0x005c) { + /* '\\' */ + *d++=*s++; + bcount++; + } else if (*s==0x0022) { + /* '"' */ + if ((bcount & 1)==0) { + /* Preceeded 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 { + /* Preceeded 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; } - return proc; + } + *d=0; + *cmdline=s; + + /* skip the remaining spaces */ + while (**cmdline==0x0009 || **cmdline==0x0020) { + (*cmdline)++; + } + + return arg; } int main(int argc, char* argv[]) { - char szDllName[MAX_PATH],szEntryPoint[64],szCmdLine[2048]; - char* comma; - EntryPointW pfEntryPointW; - EntryPointA pfEntryPointA; - HMODULE DllHandle=NULL; - - if(argc<2) - return 0; - comma=strchr(argv[1],','); - if(comma==NULL) - return 0; - /* Extract the name of the DLL */ - memset(szDllName,0,MAX_PATH); - strncpy(szDllName,argv[1],(comma-argv[1])); - /* Merge the other paramters into one big command line */ - memset(szCmdLine,0,2048); - if(argc>2) - { - int i; - for(i=2;i<argc;i++) - { - strcat(szCmdLine,argv[i]); - if(i+1<argc) strcat(szCmdLine," "); - } + HWND hWnd; + LPCWSTR szCmdLine; + LPWSTR szDllName,szEntryPoint; + char* szProcName; + HMODULE hDll; + EntryPointW pEntryPointW; + EntryPointA pEntryPointA; + int len; + + hWnd=NULL; + hDll=NULL; + szDllName=NULL; + szProcName=NULL; + + /* Initialize the rundll32 class */ + MyRegisterClass( NULL ); + hWnd = CreateWindow(szWindowClass, szTitle, + WS_OVERLAPPEDWINDOW|WS_VISIBLE, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, NULL, NULL); + + /* Skip the rundll32.exe path */ + szCmdLine=GetCommandLineW(); + WINE_TRACE("CmdLine=%s\n",wine_dbgstr_w(szCmdLine)); + szDllName=GetNextArg(&szCmdLine); + if (!szDllName || *szDllName==0) + goto CLEANUP; + HeapFree(GetProcessHeap(),0,szDllName); + + /* Get the dll name and API EntryPoint */ + szDllName=GetNextArg(&szCmdLine); + if (!szDllName || *szDllName==0) + goto CLEANUP; + WINE_TRACE("DllName=%s\n",wine_dbgstr_w(szDllName)); + szEntryPoint=szDllName; + while (*szEntryPoint!=0 && *szEntryPoint!=0x002c /* ',' */) + szEntryPoint++; + if (*szEntryPoint==0) + goto CLEANUP; + *szEntryPoint++=0; + WINE_TRACE("EntryPoint=%s\n",wine_dbgstr_w(szEntryPoint)); + + /* Load the library */ + hDll=LoadLibraryW(szDllName); + if (!hDll) + { + /* Windows has a MessageBox here... */ + WINE_WARN("Unable to load %s\n",wine_dbgstr_w(szDllName)); + goto CLEANUP; } - /* try loading the UNICODE version first */ - strcpy(szEntryPoint,comma+1); - strcat(szEntryPoint,"W"); - pfEntryPointW=(EntryPointW)LoadProc(szDllName, szEntryPoint, &DllHandle); - if(pfEntryPointW!=NULL) - { - WCHAR wszCmdLine[2048]; - MultiByteToWideChar(CP_ACP,0,szCmdLine,-1,wszCmdLine,2048); - pfEntryPointW(NULL,DllHandle,wszCmdLine,SW_HIDE); + /* Try the Unicode entrypoint. Note that GetProcAddress only takes ascii + * names. + */ + len=WideCharToMultiByte(CP_ACP,0,szEntryPoint,-1,NULL,0,NULL,NULL); + szProcName=HeapAlloc(GetProcessHeap(),0,len); + if (!szProcName) + goto CLEANUP; + WideCharToMultiByte(CP_ACP,0,szEntryPoint,-1,szProcName,len,NULL,NULL); + szProcName[len-1]=0x0057; + szProcName[len]=0; + pEntryPointW=(void*)GetProcAddress(hDll,szProcName); + if (pEntryPointW) + { + WCHAR* szArguments=NULL; + + /* Make a copy of the arguments so they are writable */ + len=lstrlenW(szCmdLine); + if (len>0) + { + szArguments=HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR)); + if (!szArguments) + goto CLEANUP; + lstrcpyW(szArguments,szCmdLine); + } + WINE_TRACE("Calling %s, arguments=%s\n", + szProcName,wine_dbgstr_w(szArguments)); + pEntryPointW(hWnd,hDll,szArguments,SW_SHOWDEFAULT); + if (szArguments) + HeapFree(GetProcessHeap(),0,szArguments); + } + else + { + /* Then try to append 'A' and finally nothing */ + szProcName[len-1]=0x0041; + pEntryPointA=(void*)GetProcAddress(hDll,szProcName); + if (!pEntryPointA) + { + szProcName[len-1]=0; + pEntryPointA=(void*)GetProcAddress(hDll,szProcName); + } + if (pEntryPointA) + { + char* szArguments=NULL; + /* Convert the command line to ascii */ + WINE_TRACE("Calling %s, arguments=%s\n", + szProcName,wine_dbgstr_a(szArguments)); + len=WideCharToMultiByte(CP_ACP,0,szCmdLine,-1,NULL,0,NULL,NULL); + if (len>1) + { + szArguments=HeapAlloc(GetProcessHeap(),0,len); + if (!szArguments) + goto CLEANUP; + WideCharToMultiByte(CP_ACP,0,szCmdLine,-1,szArguments,len,NULL,NULL); + } + pEntryPointA(hWnd,hDll,szArguments,SW_SHOWDEFAULT); + if (szArguments) + HeapFree(GetProcessHeap(),0,szArguments); } else { - strcpy(szEntryPoint,comma+1); - strcat(szEntryPoint,"A"); - pfEntryPointA=(EntryPointA)LoadProc(szDllName, szEntryPoint, &DllHandle); - if(pfEntryPointA==NULL) - { - strcpy(szEntryPoint,comma+1); - pfEntryPointA=(EntryPointA)LoadProc(szDllName, szEntryPoint, &DllHandle); - if(pfEntryPointA==NULL) - return 0; - } - pfEntryPointA(NULL,DllHandle,szCmdLine,SW_HIDE); - } - if(DllHandle) - FreeLibrary(DllHandle); - return 0; + /* Windows has a MessageBox here... */ + WINE_WARN("Unable to find the entry point: %s\n",szProcName); + } + } + +CLEANUP: + if (hWnd) + DestroyWindow(hWnd); + if (hDll) + FreeLibrary(hDll); + if (szDllName) + HeapFree(GetProcessHeap(),0,szDllName); + if (szProcName) + HeapFree(GetProcessHeap(),0,szProcName); + return 0; /* rundll32 always returns 0! */ }