2 * PURPOSE: Load a DLL and run an entry point with the specified parameters
4 * Copyright 2002 Alberto Massari
5 * Copyright 2001-2003 Aric Stewart for CodeWeavers
6 * Copyright 2003 Mike McCormack for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * rundll32 dllname,entrypoint [arguments]
28 * Documentation for this utility found on KB Q164787
36 /* Exclude rarely-used stuff from Windows headers */
37 #define WIN32_LEAN_AND_MEAN
39 #include "wine/winbase16.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(rundll32);
47 * Control_RunDLL has these parameters
49 typedef void (WINAPI *EntryPointW)(HWND hWnd, HINSTANCE hInst, LPWSTR lpszCmdLine, int nCmdShow);
50 typedef void (WINAPI *EntryPointA)(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow);
53 * Control_RunDLL needs to have a window. So lets make us a very
54 * simple window class.
56 static TCHAR *szTitle = "rundll32";
57 static TCHAR *szWindowClass = "class_rundll32";
59 static HINSTANCE16 (WINAPI *pLoadLibrary16)(LPCSTR libname);
60 static FARPROC16 (WINAPI *pGetProcAddress16)(HMODULE16 hModule, LPCSTR name);
61 static void (WINAPI *pRunDLL_CallEntry16)( FARPROC proc, HWND hwnd, HINSTANCE inst,
62 LPCSTR cmdline, INT cmdshow );
64 static ATOM MyRegisterClass(HINSTANCE hInstance)
68 wcex.cbSize = sizeof(WNDCLASSEX);
70 wcex.style = CS_HREDRAW | CS_VREDRAW;
71 wcex.lpfnWndProc = DefWindowProc;
74 wcex.hInstance = hInstance;
76 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
77 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
78 wcex.lpszMenuName = NULL;
79 wcex.lpszClassName = szWindowClass;
82 return RegisterClassEx(&wcex);
85 static HINSTANCE16 load_dll16( LPCWSTR dll )
88 DWORD len = WideCharToMultiByte( CP_ACP, 0, dll, -1, NULL, 0, NULL, NULL );
89 char *dllA = HeapAlloc( GetProcessHeap(), 0, len );
90 WideCharToMultiByte( CP_ACP, 0, dll, -1, dllA, len, NULL, NULL );
91 pLoadLibrary16 = (void *)GetProcAddress( GetModuleHandleA("kernel32.dll"), "LoadLibrary16" );
92 if (pLoadLibrary16) ret = pLoadLibrary16( dllA );
93 HeapFree( GetProcessHeap(), 0, dllA );
97 static FARPROC16 get_entry_point16( HINSTANCE16 inst, LPCWSTR entry )
100 DWORD len = WideCharToMultiByte( CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL );
101 char *entryA = HeapAlloc( GetProcessHeap(), 0, len );
102 WideCharToMultiByte( CP_ACP, 0, entry, -1, entryA, len, NULL, NULL );
103 pGetProcAddress16 = (void *)GetProcAddress( GetModuleHandleA("kernel32.dll"), "GetProcAddress16" );
104 if (pGetProcAddress16) ret = pGetProcAddress16( inst, entryA );
105 HeapFree( GetProcessHeap(), 0, entryA );
109 static void *get_entry_point32( HMODULE module, LPCWSTR entry, BOOL *unicode )
112 DWORD len = WideCharToMultiByte( CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL );
113 char *entryA = HeapAlloc( GetProcessHeap(), 0, len + 1 );
114 WideCharToMultiByte( CP_ACP, 0, entry, -1, entryA, len, NULL, NULL );
116 /* first try the W version */
118 strcat( entryA, "W" );
119 if (!(ret = GetProcAddress( module, entryA )))
121 /* now the A version */
123 entryA[strlen(entryA)-1] = 'A';
124 if (!(ret = GetProcAddress( module, entryA )))
126 /* now the version without suffix */
127 entryA[strlen(entryA)-1] = 0;
128 ret = GetProcAddress( module, entryA );
131 HeapFree( GetProcessHeap(), 0, entryA );
135 static LPWSTR GetNextArg(LPWSTR *cmdline)
139 int in_quotes,bcount,len=0;
141 /* count the chars */
146 if (*s==0 || ((*s=='\t' || *s==' ') && !in_quotes)) {
147 /* end of this command line argument */
149 } else if (*s=='\\') {
150 /* '\', count them */
152 } else if ((*s=='"') && ((bcount & 1)==0)) {
154 in_quotes=!in_quotes;
157 /* a regular character */
163 arg=HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
172 if ((*s=='\t' || *s==' ') && !in_quotes) {
173 /* end of this command line argument */
175 } else if (*s=='\\') {
179 } else if (*s=='"') {
181 if ((bcount & 1)==0) {
182 /* Preceded by an even number of '\', this is half that
183 * number of '\', plus a quote which we erase.
186 in_quotes=!in_quotes;
189 /* Preceded by an odd number of '\', this is half that
190 * number of '\' followed by a '"'
198 /* a regular character */
206 /* skip the remaining spaces */
207 while (**cmdline=='\t' || **cmdline==' ') {
214 int main(int argc, char* argv[])
218 LPWSTR szDllName,szEntryPoint;
222 HMODULE hDll, instance;
228 /* Initialize the rundll32 class */
229 MyRegisterClass( NULL );
230 hWnd = CreateWindow(szWindowClass, szTitle,
231 WS_OVERLAPPEDWINDOW|WS_VISIBLE,
232 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, NULL, NULL);
234 /* Skip the rundll32.exe path */
235 szCmdLine=GetCommandLineW();
236 WINE_TRACE("CmdLine=%s\n",wine_dbgstr_w(szCmdLine));
237 szDllName=GetNextArg(&szCmdLine);
238 if (!szDllName || *szDllName==0)
240 HeapFree(GetProcessHeap(),0,szDllName);
242 /* Get the dll name and API EntryPoint */
243 szDllName=GetNextArg(&szCmdLine);
244 if (!szDllName || *szDllName==0)
246 WINE_TRACE("DllName=%s\n",wine_dbgstr_w(szDllName));
247 if (!(szEntryPoint = strchrW( szDllName, ',' ))) goto CLEANUP;
249 WINE_TRACE("EntryPoint=%s\n",wine_dbgstr_w(szEntryPoint));
251 /* Load the library */
252 hDll=LoadLibraryW(szDllName);
256 entry_point = get_entry_point32( hDll, szEntryPoint, &unicode );
260 HINSTANCE16 dll = load_dll16( szDllName );
263 /* Windows has a MessageBox here... */
264 WINE_ERR("Unable to load %s\n",wine_dbgstr_w(szDllName));
269 entry_point = get_entry_point16( dll, szEntryPoint );
274 /* Windows has a MessageBox here... */
275 WINE_ERR( "Unable to find the entry point %s in %s\n",
276 wine_dbgstr_w(szEntryPoint), wine_dbgstr_w(szDllName) );
280 GetStartupInfoW( &info );
281 if (!(info.dwFlags & STARTF_USESHOWWINDOW)) info.wShowWindow = SW_SHOWDEFAULT;
282 instance = GetModuleHandleW(NULL); /* Windows always uses that, not hDll */
286 EntryPointW pEntryPointW = entry_point;
288 WINE_TRACE( "Calling %s (%p,%p,%s,%d)\n", wine_dbgstr_w(szEntryPoint),
289 hWnd, instance, wine_dbgstr_w(szCmdLine), info.wShowWindow );
291 pEntryPointW( hWnd, instance, szCmdLine, info.wShowWindow );
295 DWORD len = WideCharToMultiByte( CP_ACP, 0, szCmdLine, -1, NULL, 0, NULL, NULL );
296 char *cmdline = HeapAlloc( GetProcessHeap(), 0, len );
297 WideCharToMultiByte( CP_ACP, 0, szCmdLine, -1, cmdline, len, NULL, NULL );
299 WINE_TRACE( "Calling %s (%p,%p,%s,%d)\n", wine_dbgstr_w(szEntryPoint),
300 hWnd, instance, wine_dbgstr_a(cmdline), info.wShowWindow );
304 HMODULE shell = LoadLibraryA( "shell32.dll" );
305 if (shell) pRunDLL_CallEntry16 = (void *)GetProcAddress( shell, (LPCSTR)122 );
306 if (pRunDLL_CallEntry16)
307 pRunDLL_CallEntry16( entry_point, hWnd, instance, cmdline, info.wShowWindow );
311 EntryPointA pEntryPointA = entry_point;
312 pEntryPointA( hWnd, instance, cmdline, info.wShowWindow );
314 HeapFree( GetProcessHeap(), 0, cmdline );
322 HeapFree(GetProcessHeap(),0,szDllName);
323 return 0; /* rundll32 always returns 0! */