kerberos: Add support for SECPKG_CRED_BOTH.
[wine.git] / programs / rundll32 / rundll32.c
blob2fb87fb8a50e8eb1c6580da9da99ca36614d316a
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 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)
94 WNDCLASSEXW wcex;
96 wcex.cbSize = sizeof(WNDCLASSEXW);
98 wcex.style = CS_HREDRAW | CS_VREDRAW;
99 wcex.lpfnWndProc = DefWindowProcW;
100 wcex.cbClsExtra = 0;
101 wcex.cbWndExtra = 0;
102 wcex.hInstance = NULL;
103 wcex.hIcon = 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";
108 wcex.hIconSm = NULL;
110 return RegisterClassExW(&wcex);
113 #ifdef __i386__
115 static HINSTANCE16 load_dll16( LPCWSTR dll )
117 HINSTANCE16 (WINAPI *pLoadLibrary16)(LPCSTR libname);
118 HINSTANCE16 ret = 0;
119 DWORD len = WideCharToMultiByte( CP_ACP, 0, dll, -1, NULL, 0, NULL, NULL );
120 char *dllA = HeapAlloc( GetProcessHeap(), 0, len );
122 if (dllA)
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 );
129 return ret;
132 static FARPROC16 get_entry_point16( HINSTANCE16 inst, LPCWSTR entry )
134 FARPROC16 (WINAPI *pGetProcAddress16)(HMODULE16 hModule, LPCSTR name);
135 FARPROC16 ret = 0;
136 DWORD len = WideCharToMultiByte( CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL );
137 char *entryA = HeapAlloc( GetProcessHeap(), 0, len );
139 if (entryA)
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 );
146 return ret;
148 #endif
150 static void *get_entry_point32( HMODULE module, LPCWSTR entry, BOOL *unicode )
152 void *ret;
154 /* determine if the entry point is an ordinal */
155 if (entry[0] == '#')
157 INT_PTR ordinal = wcstol( entry + 1, NULL, 10 );
158 if (ordinal <= 0)
159 return NULL;
161 *unicode = TRUE;
162 ret = GetProcAddress( module, (LPCSTR)ordinal );
164 else
166 DWORD len = WideCharToMultiByte( CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL );
167 char *entryA = HeapAlloc( GetProcessHeap(), 0, len + 1 );
169 if (!entryA)
170 return NULL;
172 WideCharToMultiByte( CP_ACP, 0, entry, -1, entryA, len, NULL, NULL );
174 /* first try the W version */
175 *unicode = TRUE;
176 strcat( entryA, "W" );
177 if (!(ret = GetProcAddress( module, entryA )))
179 /* now the A version */
180 *unicode = FALSE;
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 );
191 return ret;
194 static LPWSTR get_next_arg(LPWSTR *cmdline)
196 LPWSTR s;
197 LPWSTR arg,d;
198 BOOL in_quotes;
199 int bcount,len=0;
201 /* count the chars */
202 bcount=0;
203 in_quotes=FALSE;
204 s=*cmdline;
205 while (1) {
206 if (*s==0 || ((*s=='\t' || *s==' ') && !in_quotes)) {
207 /* end of this command line argument */
208 break;
209 } else if (*s=='\\') {
210 /* '\', count them */
211 bcount++;
212 } else if ((*s=='"') && ((bcount & 1)==0)) {
213 /* unescaped '"' */
214 in_quotes=!in_quotes;
215 bcount=0;
216 } else {
217 /* a regular character */
218 bcount=0;
220 s++;
221 len++;
223 arg=HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
224 if (!arg)
225 return NULL;
227 bcount=0;
228 in_quotes=FALSE;
229 d=arg;
230 s=*cmdline;
231 while (*s) {
232 if ((*s=='\t' || *s==' ') && !in_quotes) {
233 /* end of this command line argument */
234 break;
235 } else if (*s=='\\') {
236 /* '\\' */
237 *d++=*s++;
238 bcount++;
239 } else if (*s=='"') {
240 /* '"' */
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.
245 d-=bcount/2;
246 in_quotes=!in_quotes;
247 s++;
248 } else {
249 /* Preceded by an odd number of '\', this is half that
250 * number of '\' followed by a '"'
252 d=d-bcount/2-1;
253 *d++='"';
254 s++;
256 bcount=0;
257 } else {
258 /* a regular character */
259 *d++=*s++;
260 bcount=0;
263 *d=0;
264 *cmdline=s;
266 /* skip the remaining spaces */
267 while (**cmdline=='\t' || **cmdline==' ') {
268 (*cmdline)++;
271 return arg;
274 int WINAPI wWinMain(HINSTANCE instance, HINSTANCE hOldInstance, LPWSTR szCmdLine, int nCmdShow)
276 HWND hWnd;
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];
282 STARTUPINFOW info;
283 ULONG_PTR cookie;
284 ACTCTXW ctx;
286 hWnd=NULL;
287 hDll=NULL;
288 szDllName=NULL;
290 /* Initialize the rundll32 class */
291 register_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)
299 goto CLEANUP;
300 WINE_TRACE("DllName=%s\n",wine_dbgstr_w(szDllName));
301 if ((szEntryPoint = wcschr(szDllName, ',' )))
302 *szEntryPoint++=0;
303 else
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);
312 ctx.lpSource = path;
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);
318 else
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 );
325 #ifdef __i386__
326 else
328 HINSTANCE16 dll = load_dll16( szDllName );
329 if (dll <= 32)
331 /* Windows has a MessageBox here... */
332 WINE_ERR("Unable to load %s\n",wine_dbgstr_w(szDllName));
333 goto CLEANUP;
335 win16 = TRUE;
336 entry_point = get_entry_point16( dll, szEntryPoint );
338 #endif
340 if (!entry_point)
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) );
345 goto CLEANUP;
348 GetStartupInfoW( &info );
349 if (!(info.dwFlags & STARTF_USESHOWWINDOW)) info.wShowWindow = SW_SHOWDEFAULT;
351 if (unicode)
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 );
358 else
360 DWORD len = WideCharToMultiByte( CP_ACP, 0, szCmdLine, -1, NULL, 0, NULL, NULL );
361 char *cmdline = HeapAlloc( GetProcessHeap(), 0, len );
363 if (!cmdline)
364 goto CLEANUP;
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 );
371 if (win16)
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 );
383 CLEANUP:
384 if (hWnd)
385 DestroyWindow(hWnd);
386 if (hDll)
387 FreeLibrary(hDll);
388 if (activated)
389 DeactivateActCtx(0, cookie);
390 ReleaseActCtx(hCtx);
391 HeapFree(GetProcessHeap(),0,szDllName);
392 return 0; /* rundll32 always returns 0! */