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);
46 extern void WINAPI RunDLL_CallEntry16( FARPROC proc, HWND hwnd, HINSTANCE inst,
47 LPCSTR cmdline, INT cmdshow );
50 * Control_RunDLL has these parameters
52 typedef void (WINAPI *EntryPointW)(HWND hWnd, HINSTANCE hInst, LPWSTR lpszCmdLine, int nCmdShow);
53 typedef void (WINAPI *EntryPointA)(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow);
56 * Control_RunDLL needs to have a window. So lets make us a very
57 * simple window class.
59 static TCHAR *szTitle = "rundll32";
60 static TCHAR *szWindowClass = "class_rundll32";
62 static ATOM MyRegisterClass(HINSTANCE hInstance)
66 wcex.cbSize = sizeof(WNDCLASSEX);
68 wcex.style = CS_HREDRAW | CS_VREDRAW;
69 wcex.lpfnWndProc = (WNDPROC)DefWindowProc;
72 wcex.hInstance = hInstance;
74 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
75 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
76 wcex.lpszMenuName = NULL;
77 wcex.lpszClassName = szWindowClass;
80 return RegisterClassEx(&wcex);
83 static HINSTANCE16 load_dll16( LPCWSTR dll )
86 DWORD len = WideCharToMultiByte( CP_ACP, 0, dll, -1, NULL, 0, NULL, NULL );
87 char *dllA = HeapAlloc( GetProcessHeap(), 0, len );
88 WideCharToMultiByte( CP_ACP, 0, dll, -1, dllA, len, NULL, NULL );
89 ret = LoadLibrary16( dllA );
90 HeapFree( GetProcessHeap(), 0, dllA );
94 static FARPROC16 get_entry_point16( HINSTANCE16 inst, LPCWSTR entry )
97 DWORD len = WideCharToMultiByte( CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL );
98 char *entryA = HeapAlloc( GetProcessHeap(), 0, len );
99 WideCharToMultiByte( CP_ACP, 0, entry, -1, entryA, len, NULL, NULL );
100 ret = GetProcAddress16( inst, entryA );
101 HeapFree( GetProcessHeap(), 0, entryA );
105 static void *get_entry_point32( HMODULE module, LPCWSTR entry, BOOL *unicode )
108 DWORD len = WideCharToMultiByte( CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL );
109 char *entryA = HeapAlloc( GetProcessHeap(), 0, len + 1 );
110 WideCharToMultiByte( CP_ACP, 0, entry, -1, entryA, len, NULL, NULL );
112 /* first try the W version */
114 strcat( entryA, "W" );
115 if (!(ret = GetProcAddress( module, entryA )))
117 /* now the A version */
119 entryA[strlen(entryA)-1] = 'A';
120 if (!(ret = GetProcAddress( module, entryA )))
122 /* now the version without suffix */
123 entryA[strlen(entryA)-1] = 0;
124 ret = GetProcAddress( module, entryA );
127 HeapFree( GetProcessHeap(), 0, entryA );
131 static LPWSTR GetNextArg(LPWSTR *cmdline)
135 int in_quotes,bcount,len=0;
137 /* count the chars */
142 if (*s==0 || ((*s=='\t' || *s==' ') && !in_quotes)) {
143 /* end of this command line argument */
145 } else if (*s=='\\') {
146 /* '\', count them */
148 } else if ((*s=='"') && ((bcount & 1)==0)) {
150 in_quotes=!in_quotes;
153 /* a regular character */
159 arg=HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
168 if ((*s=='\t' || *s==' ') && !in_quotes) {
169 /* end of this command line argument */
171 } else if (*s=='\\') {
175 } else if (*s=='"') {
177 if ((bcount & 1)==0) {
178 /* Preceeded by an even number of '\', this is half that
179 * number of '\', plus a quote which we erase.
182 in_quotes=!in_quotes;
185 /* Preceeded by an odd number of '\', this is half that
186 * number of '\' followed by a '"'
194 /* a regular character */
202 /* skip the remaining spaces */
203 while (**cmdline=='\t' || **cmdline==' ') {
210 int main(int argc, char* argv[])
214 LPWSTR szDllName,szEntryPoint;
218 HMODULE hDll, instance;
224 /* Initialize the rundll32 class */
225 MyRegisterClass( NULL );
226 hWnd = CreateWindow(szWindowClass, szTitle,
227 WS_OVERLAPPEDWINDOW|WS_VISIBLE,
228 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, NULL, NULL);
230 /* Skip the rundll32.exe path */
231 szCmdLine=GetCommandLineW();
232 WINE_TRACE("CmdLine=%s\n",wine_dbgstr_w(szCmdLine));
233 szDllName=GetNextArg(&szCmdLine);
234 if (!szDllName || *szDllName==0)
236 HeapFree(GetProcessHeap(),0,szDllName);
238 /* Get the dll name and API EntryPoint */
239 szDllName=GetNextArg(&szCmdLine);
240 if (!szDllName || *szDllName==0)
242 WINE_TRACE("DllName=%s\n",wine_dbgstr_w(szDllName));
243 if (!(szEntryPoint = strchrW( szDllName, ',' ))) goto CLEANUP;
245 WINE_TRACE("EntryPoint=%s\n",wine_dbgstr_w(szEntryPoint));
247 /* Load the library */
248 hDll=LoadLibraryW(szDllName);
252 entry_point = get_entry_point32( hDll, szEntryPoint, &unicode );
256 HINSTANCE16 dll = load_dll16( szDllName );
259 /* Windows has a MessageBox here... */
260 WINE_ERR("Unable to load %s\n",wine_dbgstr_w(szDllName));
265 entry_point = get_entry_point16( dll, szEntryPoint );
270 /* Windows has a MessageBox here... */
271 WINE_ERR( "Unable to find the entry point %s in %s\n",
272 wine_dbgstr_w(szEntryPoint), wine_dbgstr_w(szDllName) );
276 GetStartupInfoW( &info );
277 if (!(info.dwFlags & STARTF_USESHOWWINDOW)) info.wShowWindow = SW_SHOWDEFAULT;
278 instance = GetModuleHandleW(NULL); /* Windows always uses that, not hDll */
282 EntryPointW pEntryPointW = entry_point;
284 WINE_TRACE( "Calling %s (%p,%p,%s,%d)\n", wine_dbgstr_w(szEntryPoint),
285 hWnd, instance, wine_dbgstr_w(szCmdLine), info.wShowWindow );
287 pEntryPointW( hWnd, instance, szCmdLine, info.wShowWindow );
291 DWORD len = WideCharToMultiByte( CP_ACP, 0, szCmdLine, -1, NULL, 0, NULL, NULL );
292 char *cmdline = HeapAlloc( GetProcessHeap(), 0, len );
293 WideCharToMultiByte( CP_ACP, 0, szCmdLine, -1, cmdline, len, NULL, NULL );
295 WINE_TRACE( "Calling %s (%p,%p,%s,%d)\n", wine_dbgstr_w(szEntryPoint),
296 hWnd, instance, wine_dbgstr_a(cmdline), info.wShowWindow );
298 if (win16) RunDLL_CallEntry16( entry_point, hWnd, instance, cmdline, info.wShowWindow );
301 EntryPointA pEntryPointA = entry_point;
302 pEntryPointA( hWnd, instance, cmdline, info.wShowWindow );
304 HeapFree( GetProcessHeap(), 0, cmdline );
313 HeapFree(GetProcessHeap(),0,szDllName);
314 return 0; /* rundll32 always returns 0! */