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
36 /* Exclude rarely-used stuff from Windows headers */
37 #define WIN32_LEAN_AND_MEAN
39 #include "wine/winbase16.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(rundll32
);
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
,
51 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
52 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
54 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
56 __ASM_CFI(".cfi_rel_offset %edi,-4\n\t")
58 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
60 __ASM_CFI(".cfi_rel_offset %ebx,-12\n\t")
67 "leal -12(%ebp),%esp\n\t"
69 __ASM_CFI(".cfi_same_value %ebx\n\t")
71 __ASM_CFI(".cfi_same_value %esi\n\t")
73 __ASM_CFI(".cfi_same_value %edi\n\t")
75 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
76 __ASM_CFI(".cfi_same_value %ebp\n\t")
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
);
86 static void (WINAPI
*pRunDLL_CallEntry16
)( FARPROC proc
, HWND hwnd
, HINSTANCE inst
,
87 LPCSTR cmdline
, INT cmdshow
);
90 * Control_RunDLL needs to have a window. So lets make us a very simple window class.
92 static ATOM
register_class(void)
96 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
98 wcex
.style
= CS_HREDRAW
| CS_VREDRAW
;
99 wcex
.lpfnWndProc
= DefWindowProcW
;
102 wcex
.hInstance
= NULL
;
104 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_ARROW
);
105 wcex
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+1);
106 wcex
.lpszMenuName
= NULL
;
107 wcex
.lpszClassName
= L
"class_rundll32";
110 return RegisterClassExW(&wcex
);
115 static HINSTANCE16
load_dll16( LPCWSTR dll
)
117 HINSTANCE16 (WINAPI
*pLoadLibrary16
)(LPCSTR libname
);
119 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, dll
, -1, NULL
, 0, NULL
, NULL
);
120 char *dllA
= HeapAlloc( GetProcessHeap(), 0, len
);
124 WideCharToMultiByte( CP_ACP
, 0, dll
, -1, dllA
, len
, NULL
, NULL
);
125 pLoadLibrary16
= (void *)GetProcAddress( GetModuleHandleW(L
"kernel32.dll"), (LPCSTR
)35 );
126 if (pLoadLibrary16
) ret
= pLoadLibrary16( dllA
);
127 HeapFree( GetProcessHeap(), 0, dllA
);
132 static FARPROC16
get_entry_point16( HINSTANCE16 inst
, LPCWSTR entry
)
134 FARPROC16 (WINAPI
*pGetProcAddress16
)(HMODULE16 hModule
, LPCSTR name
);
136 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, entry
, -1, NULL
, 0, NULL
, NULL
);
137 char *entryA
= HeapAlloc( GetProcessHeap(), 0, len
);
141 WideCharToMultiByte( CP_ACP
, 0, entry
, -1, entryA
, len
, NULL
, NULL
);
142 pGetProcAddress16
= (void *)GetProcAddress( GetModuleHandleW(L
"kernel32.dll"), (LPCSTR
)37 );
143 if (pGetProcAddress16
) ret
= pGetProcAddress16( inst
, entryA
);
144 HeapFree( GetProcessHeap(), 0, entryA
);
150 static void *get_entry_point32( HMODULE module
, LPCWSTR entry
, BOOL
*unicode
)
154 /* determine if the entry point is an ordinal */
157 INT_PTR ordinal
= wcstol( entry
+ 1, NULL
, 10 );
162 ret
= GetProcAddress( module
, (LPCSTR
)ordinal
);
166 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, entry
, -1, NULL
, 0, NULL
, NULL
);
167 char *entryA
= HeapAlloc( GetProcessHeap(), 0, len
+ 1 );
172 WideCharToMultiByte( CP_ACP
, 0, entry
, -1, entryA
, len
, NULL
, NULL
);
174 /* first try the W version */
176 strcat( entryA
, "W" );
177 if (!(ret
= GetProcAddress( module
, entryA
)))
179 /* now the A version */
181 entryA
[strlen(entryA
)-1] = 'A';
182 if (!(ret
= GetProcAddress( module
, entryA
)))
184 /* now the version without suffix */
185 entryA
[strlen(entryA
)-1] = 0;
186 ret
= GetProcAddress( module
, entryA
);
189 HeapFree( GetProcessHeap(), 0, entryA
);
194 static LPWSTR
get_next_arg(LPWSTR
*cmdline
)
201 /* count the chars */
206 if (*s
==0 || ((*s
=='\t' || *s
==' ') && !in_quotes
)) {
207 /* end of this command line argument */
209 } else if (*s
=='\\') {
210 /* '\', count them */
212 } else if ((*s
=='"') && ((bcount
& 1)==0)) {
214 in_quotes
=!in_quotes
;
217 /* a regular character */
223 arg
=HeapAlloc(GetProcessHeap(), 0, (len
+1)*sizeof(WCHAR
));
232 if ((*s
=='\t' || *s
==' ') && !in_quotes
) {
233 /* end of this command line argument */
235 } else if (*s
=='\\') {
239 } else if (*s
=='"') {
241 if ((bcount
& 1)==0) {
242 /* Preceded by an even number of '\', this is half that
243 * number of '\', plus a quote which we erase.
246 in_quotes
=!in_quotes
;
249 /* Preceded by an odd number of '\', this is half that
250 * number of '\' followed by a '"'
258 /* a regular character */
266 /* skip the remaining spaces */
267 while (**cmdline
=='\t' || **cmdline
==' ') {
274 int WINAPI
wWinMain(HINSTANCE instance
, HINSTANCE hOldInstance
, LPWSTR szCmdLine
, int nCmdShow
)
277 LPWSTR szDllName
,szEntryPoint
;
278 void *entry_point
= NULL
;
279 BOOL unicode
= FALSE
, win16
= FALSE
, activated
= FALSE
;
280 HMODULE hDll
, hCtx
= INVALID_HANDLE_VALUE
;
281 WCHAR path
[MAX_PATH
];
290 /* Initialize the rundll32 class */
292 hWnd
= CreateWindowW(L
"class_rundll32", L
"rundll32", WS_OVERLAPPEDWINDOW
|WS_VISIBLE
,
293 CW_USEDEFAULT
, 0, CW_USEDEFAULT
, 0, NULL
, NULL
, NULL
, NULL
);
295 /* Get the dll name and API EntryPoint */
296 WINE_TRACE("CmdLine=%s\n",wine_dbgstr_w(szCmdLine
));
297 szDllName
= get_next_arg(&szCmdLine
);
298 if (!szDllName
|| *szDllName
==0)
300 WINE_TRACE("DllName=%s\n",wine_dbgstr_w(szDllName
));
301 if ((szEntryPoint
= wcschr(szDllName
, ',' )))
304 szEntryPoint
= get_next_arg(&szCmdLine
);
305 WINE_TRACE("EntryPoint=%s\n",wine_dbgstr_w(szEntryPoint
));
307 /* Activate context before DllMain() is called */
308 if (SearchPathW(NULL
, szDllName
, NULL
, ARRAY_SIZE(path
), path
, NULL
))
310 memset(&ctx
, 0, sizeof(ctx
));
311 ctx
.cbSize
= sizeof(ctx
);
313 ctx
.lpResourceName
= MAKEINTRESOURCEW(123);
314 ctx
.dwFlags
= ACTCTX_FLAG_RESOURCE_NAME_VALID
;
315 hCtx
= CreateActCtxW(&ctx
);
316 if (hCtx
!= INVALID_HANDLE_VALUE
)
317 activated
= ActivateActCtx(hCtx
, &cookie
);
319 WINE_TRACE("No manifest at ID 123 in %s\n", wine_dbgstr_w(path
));
322 /* Load the library */
323 hDll
=LoadLibraryW(szDllName
);
324 if (hDll
) entry_point
= get_entry_point32( hDll
, szEntryPoint
, &unicode
);
328 HINSTANCE16 dll
= load_dll16( szDllName
);
331 /* Windows has a MessageBox here... */
332 WINE_ERR("Unable to load %s\n",wine_dbgstr_w(szDllName
));
336 entry_point
= get_entry_point16( dll
, szEntryPoint
);
342 /* Windows has a MessageBox here... */
343 WINE_ERR( "Unable to find the entry point %s in %s\n",
344 wine_dbgstr_w(szEntryPoint
), wine_dbgstr_w(szDllName
) );
348 GetStartupInfoW( &info
);
349 if (!(info
.dwFlags
& STARTF_USESHOWWINDOW
)) info
.wShowWindow
= SW_SHOWDEFAULT
;
353 WINE_TRACE( "Calling %s (%p,%p,%s,%d)\n", wine_dbgstr_w(szEntryPoint
),
354 hWnd
, instance
, wine_dbgstr_w(szCmdLine
), info
.wShowWindow
);
356 call_entry_point( entry_point
, hWnd
, instance
, szCmdLine
, info
.wShowWindow
);
360 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, szCmdLine
, -1, NULL
, 0, NULL
, NULL
);
361 char *cmdline
= HeapAlloc( GetProcessHeap(), 0, len
);
366 WideCharToMultiByte( CP_ACP
, 0, szCmdLine
, -1, cmdline
, len
, NULL
, NULL
);
368 WINE_TRACE( "Calling %s (%p,%p,%s,%d)\n", wine_dbgstr_w(szEntryPoint
),
369 hWnd
, instance
, wine_dbgstr_a(cmdline
), info
.wShowWindow
);
373 HMODULE shell
= LoadLibraryW( L
"shell32.dll" );
374 if (shell
) pRunDLL_CallEntry16
= (void *)GetProcAddress( shell
, (LPCSTR
)122 );
375 if (pRunDLL_CallEntry16
)
376 pRunDLL_CallEntry16( entry_point
, hWnd
, instance
, cmdline
, info
.wShowWindow
);
378 else call_entry_point( entry_point
, hWnd
, instance
, cmdline
, info
.wShowWindow
);
380 HeapFree( GetProcessHeap(), 0, cmdline
);
389 DeactivateActCtx(0, cookie
);
391 HeapFree(GetProcessHeap(),0,szDllName
);
392 return 0; /* rundll32 always returns 0! */