reg: Add a message to better indicate when a specified registry key is not found.
[wine/zf.git] / programs / rundll32 / rundll32.c
blobeb7713518a9546e517122b987d9f1bc166e4a3a3
1 /*
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 * rundll32 dllname,entrypoint [arguments]
28 * Documentation for this utility found on KB Q164787
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
36 /* Exclude rarely-used stuff from Windows headers */
37 #define WIN32_LEAN_AND_MEAN
38 #include "windows.h"
39 #include "wine/winbase16.h"
40 #include "wine/asm.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(rundll32);
46 #ifdef __i386__
47 /* wrapper for dlls that declare the entry point incorrectly */
48 extern void call_entry_point( void *func, HWND hwnd, HINSTANCE inst, void *cmdline, int show );
49 __ASM_GLOBAL_FUNC( call_entry_point,
50 "pushl %ebp\n\t"
51 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
52 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
53 "movl %esp,%ebp\n\t"
54 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
55 "pushl %edi\n\t"
56 __ASM_CFI(".cfi_rel_offset %edi,-4\n\t")
57 "pushl %esi\n\t"
58 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
59 "pushl %ebx\n\t"
60 __ASM_CFI(".cfi_rel_offset %ebx,-12\n\t")
61 "subl $12,%esp\n\t"
62 "pushl 24(%ebp)\n\t"
63 "pushl 20(%ebp)\n\t"
64 "pushl 16(%ebp)\n\t"
65 "pushl 12(%ebp)\n\t"
66 "call *8(%ebp)\n\t"
67 "leal -12(%ebp),%esp\n\t"
68 "popl %ebx\n\t"
69 __ASM_CFI(".cfi_same_value %ebx\n\t")
70 "popl %esi\n\t"
71 __ASM_CFI(".cfi_same_value %esi\n\t")
72 "popl %edi\n\t"
73 __ASM_CFI(".cfi_same_value %edi\n\t")
74 "leave\n\t"
75 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
76 __ASM_CFI(".cfi_same_value %ebp\n\t")
77 "ret" )
78 #else
79 static void call_entry_point( void *func, HWND hwnd, HINSTANCE inst, void *cmdline, int show )
81 void (WINAPI *entry_point)( HWND hwnd, HINSTANCE inst, void *cmdline, int show ) = func;
82 entry_point( hwnd, inst, cmdline, show );
84 #endif
86 static HINSTANCE16 (WINAPI *pLoadLibrary16)(LPCSTR libname);
87 static FARPROC16 (WINAPI *pGetProcAddress16)(HMODULE16 hModule, LPCSTR name);
88 static void (WINAPI *pRunDLL_CallEntry16)( FARPROC proc, HWND hwnd, HINSTANCE inst,
89 LPCSTR cmdline, INT cmdshow );
92 * Control_RunDLL needs to have a window. So lets make us a very simple window class.
94 static ATOM register_class(void)
96 WNDCLASSEXW wcex;
98 wcex.cbSize = sizeof(WNDCLASSEXW);
100 wcex.style = CS_HREDRAW | CS_VREDRAW;
101 wcex.lpfnWndProc = DefWindowProcW;
102 wcex.cbClsExtra = 0;
103 wcex.cbWndExtra = 0;
104 wcex.hInstance = NULL;
105 wcex.hIcon = NULL;
106 wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
107 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
108 wcex.lpszMenuName = NULL;
109 wcex.lpszClassName = L"class_rundll32";
110 wcex.hIconSm = NULL;
112 return RegisterClassExW(&wcex);
115 static HINSTANCE16 load_dll16( LPCWSTR dll )
117 HINSTANCE16 ret = 0;
118 DWORD len = WideCharToMultiByte( CP_ACP, 0, dll, -1, NULL, 0, NULL, NULL );
119 char *dllA = HeapAlloc( GetProcessHeap(), 0, len );
121 if (dllA)
123 WideCharToMultiByte( CP_ACP, 0, dll, -1, dllA, len, NULL, NULL );
124 pLoadLibrary16 = (void *)GetProcAddress( GetModuleHandleW(L"kernel32.dll"), (LPCSTR)35 );
125 if (pLoadLibrary16) ret = pLoadLibrary16( dllA );
126 HeapFree( GetProcessHeap(), 0, dllA );
128 return ret;
131 static FARPROC16 get_entry_point16( HINSTANCE16 inst, LPCWSTR entry )
133 FARPROC16 ret = 0;
134 DWORD len = WideCharToMultiByte( CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL );
135 char *entryA = HeapAlloc( GetProcessHeap(), 0, len );
137 if (entryA)
139 WideCharToMultiByte( CP_ACP, 0, entry, -1, entryA, len, NULL, NULL );
140 pGetProcAddress16 = (void *)GetProcAddress( GetModuleHandleW(L"kernel32.dll"), (LPCSTR)37 );
141 if (pGetProcAddress16) ret = pGetProcAddress16( inst, entryA );
142 HeapFree( GetProcessHeap(), 0, entryA );
144 return ret;
147 static void *get_entry_point32( HMODULE module, LPCWSTR entry, BOOL *unicode )
149 void *ret;
151 /* determine if the entry point is an ordinal */
152 if (entry[0] == '#')
154 INT_PTR ordinal = wcstol( entry + 1, NULL, 10 );
155 if (ordinal <= 0)
156 return NULL;
158 *unicode = TRUE;
159 ret = GetProcAddress( module, (LPCSTR)ordinal );
161 else
163 DWORD len = WideCharToMultiByte( CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL );
164 char *entryA = HeapAlloc( GetProcessHeap(), 0, len + 1 );
166 if (!entryA)
167 return NULL;
169 WideCharToMultiByte( CP_ACP, 0, entry, -1, entryA, len, NULL, NULL );
171 /* first try the W version */
172 *unicode = TRUE;
173 strcat( entryA, "W" );
174 if (!(ret = GetProcAddress( module, entryA )))
176 /* now the A version */
177 *unicode = FALSE;
178 entryA[strlen(entryA)-1] = 'A';
179 if (!(ret = GetProcAddress( module, entryA )))
181 /* now the version without suffix */
182 entryA[strlen(entryA)-1] = 0;
183 ret = GetProcAddress( module, entryA );
186 HeapFree( GetProcessHeap(), 0, entryA );
188 return ret;
191 static LPWSTR get_next_arg(LPWSTR *cmdline)
193 LPWSTR s;
194 LPWSTR arg,d;
195 BOOL in_quotes;
196 int bcount,len=0;
198 /* count the chars */
199 bcount=0;
200 in_quotes=FALSE;
201 s=*cmdline;
202 while (1) {
203 if (*s==0 || ((*s=='\t' || *s==' ') && !in_quotes)) {
204 /* end of this command line argument */
205 break;
206 } else if (*s=='\\') {
207 /* '\', count them */
208 bcount++;
209 } else if ((*s=='"') && ((bcount & 1)==0)) {
210 /* unescaped '"' */
211 in_quotes=!in_quotes;
212 bcount=0;
213 } else {
214 /* a regular character */
215 bcount=0;
217 s++;
218 len++;
220 arg=HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
221 if (!arg)
222 return NULL;
224 bcount=0;
225 in_quotes=FALSE;
226 d=arg;
227 s=*cmdline;
228 while (*s) {
229 if ((*s=='\t' || *s==' ') && !in_quotes) {
230 /* end of this command line argument */
231 break;
232 } else if (*s=='\\') {
233 /* '\\' */
234 *d++=*s++;
235 bcount++;
236 } else if (*s=='"') {
237 /* '"' */
238 if ((bcount & 1)==0) {
239 /* Preceded by an even number of '\', this is half that
240 * number of '\', plus a quote which we erase.
242 d-=bcount/2;
243 in_quotes=!in_quotes;
244 s++;
245 } else {
246 /* Preceded by an odd number of '\', this is half that
247 * number of '\' followed by a '"'
249 d=d-bcount/2-1;
250 *d++='"';
251 s++;
253 bcount=0;
254 } else {
255 /* a regular character */
256 *d++=*s++;
257 bcount=0;
260 *d=0;
261 *cmdline=s;
263 /* skip the remaining spaces */
264 while (**cmdline=='\t' || **cmdline==' ') {
265 (*cmdline)++;
268 return arg;
271 int WINAPI wWinMain(HINSTANCE instance, HINSTANCE hOldInstance, LPWSTR szCmdLine, int nCmdShow)
273 HWND hWnd;
274 LPWSTR szDllName,szEntryPoint;
275 void *entry_point;
276 BOOL unicode = FALSE, win16;
277 STARTUPINFOW info;
278 HMODULE hDll;
280 hWnd=NULL;
281 hDll=NULL;
282 szDllName=NULL;
284 /* Initialize the rundll32 class */
285 register_class();
286 hWnd = CreateWindowW(L"class_rundll32", L"rundll32", WS_OVERLAPPEDWINDOW|WS_VISIBLE,
287 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, NULL, NULL);
289 /* Get the dll name and API EntryPoint */
290 WINE_TRACE("CmdLine=%s\n",wine_dbgstr_w(szCmdLine));
291 szDllName = get_next_arg(&szCmdLine);
292 if (!szDllName || *szDllName==0)
293 goto CLEANUP;
294 WINE_TRACE("DllName=%s\n",wine_dbgstr_w(szDllName));
295 if ((szEntryPoint = wcschr(szDllName, ',' )))
296 *szEntryPoint++=0;
297 else
298 szEntryPoint = get_next_arg(&szCmdLine);
299 WINE_TRACE("EntryPoint=%s\n",wine_dbgstr_w(szEntryPoint));
301 /* Load the library */
302 hDll=LoadLibraryW(szDllName);
303 if (hDll)
305 win16 = FALSE;
306 entry_point = get_entry_point32( hDll, szEntryPoint, &unicode );
308 else
310 HINSTANCE16 dll = load_dll16( szDllName );
311 if (dll <= 32)
313 /* Windows has a MessageBox here... */
314 WINE_ERR("Unable to load %s\n",wine_dbgstr_w(szDllName));
315 goto CLEANUP;
317 win16 = TRUE;
318 unicode = FALSE;
319 entry_point = get_entry_point16( dll, szEntryPoint );
322 if (!entry_point)
324 /* Windows has a MessageBox here... */
325 WINE_ERR( "Unable to find the entry point %s in %s\n",
326 wine_dbgstr_w(szEntryPoint), wine_dbgstr_w(szDllName) );
327 goto CLEANUP;
330 GetStartupInfoW( &info );
331 if (!(info.dwFlags & STARTF_USESHOWWINDOW)) info.wShowWindow = SW_SHOWDEFAULT;
333 if (unicode)
335 WINE_TRACE( "Calling %s (%p,%p,%s,%d)\n", wine_dbgstr_w(szEntryPoint),
336 hWnd, instance, wine_dbgstr_w(szCmdLine), info.wShowWindow );
338 call_entry_point( entry_point, hWnd, instance, szCmdLine, info.wShowWindow );
340 else
342 DWORD len = WideCharToMultiByte( CP_ACP, 0, szCmdLine, -1, NULL, 0, NULL, NULL );
343 char *cmdline = HeapAlloc( GetProcessHeap(), 0, len );
345 if (!cmdline)
346 goto CLEANUP;
348 WideCharToMultiByte( CP_ACP, 0, szCmdLine, -1, cmdline, len, NULL, NULL );
350 WINE_TRACE( "Calling %s (%p,%p,%s,%d)\n", wine_dbgstr_w(szEntryPoint),
351 hWnd, instance, wine_dbgstr_a(cmdline), info.wShowWindow );
353 if (win16)
355 HMODULE shell = LoadLibraryW( L"shell32.dll" );
356 if (shell) pRunDLL_CallEntry16 = (void *)GetProcAddress( shell, (LPCSTR)122 );
357 if (pRunDLL_CallEntry16)
358 pRunDLL_CallEntry16( entry_point, hWnd, instance, cmdline, info.wShowWindow );
360 else call_entry_point( entry_point, hWnd, instance, cmdline, info.wShowWindow );
362 HeapFree( GetProcessHeap(), 0, cmdline );
365 CLEANUP:
366 if (hWnd)
367 DestroyWindow(hWnd);
368 if (hDll)
369 FreeLibrary(hDll);
370 HeapFree(GetProcessHeap(),0,szDllName);
371 return 0; /* rundll32 always returns 0! */