shell32: Use the current directory when copying to an empty destination.
[wine.git] / programs / rundll32 / rundll32.c
blobb360bedb1d51f196361f3f7060e196d023be544c
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/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 const TCHAR *szTitle = "rundll32";
57 static const 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)
66 WNDCLASSEX wcex;
68 wcex.cbSize = sizeof(WNDCLASSEX);
70 wcex.style = CS_HREDRAW | CS_VREDRAW;
71 wcex.lpfnWndProc = DefWindowProc;
72 wcex.cbClsExtra = 0;
73 wcex.cbWndExtra = 0;
74 wcex.hInstance = hInstance;
75 wcex.hIcon = NULL;
76 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
77 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
78 wcex.lpszMenuName = NULL;
79 wcex.lpszClassName = szWindowClass;
80 wcex.hIconSm = NULL;
82 return RegisterClassEx(&wcex);
85 static HINSTANCE16 load_dll16( LPCWSTR dll )
87 HINSTANCE16 ret = 0;
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"), (LPCSTR)35 );
92 if (pLoadLibrary16) ret = pLoadLibrary16( dllA );
93 HeapFree( GetProcessHeap(), 0, dllA );
94 return ret;
97 static FARPROC16 get_entry_point16( HINSTANCE16 inst, LPCWSTR entry )
99 FARPROC16 ret = 0;
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"), (LPCSTR)37 );
104 if (pGetProcAddress16) ret = pGetProcAddress16( inst, entryA );
105 HeapFree( GetProcessHeap(), 0, entryA );
106 return ret;
109 static void *get_entry_point32( HMODULE module, LPCWSTR entry, BOOL *unicode )
111 void *ret;
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 */
117 *unicode = TRUE;
118 strcat( entryA, "W" );
119 if (!(ret = GetProcAddress( module, entryA )))
121 /* now the A version */
122 *unicode = FALSE;
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 );
132 return ret;
135 static LPWSTR GetNextArg(LPWSTR *cmdline)
137 LPWSTR s;
138 LPWSTR arg,d;
139 int in_quotes,bcount,len=0;
141 /* count the chars */
142 bcount=0;
143 in_quotes=0;
144 s=*cmdline;
145 while (1) {
146 if (*s==0 || ((*s=='\t' || *s==' ') && !in_quotes)) {
147 /* end of this command line argument */
148 break;
149 } else if (*s=='\\') {
150 /* '\', count them */
151 bcount++;
152 } else if ((*s=='"') && ((bcount & 1)==0)) {
153 /* unescaped '"' */
154 in_quotes=!in_quotes;
155 bcount=0;
156 } else {
157 /* a regular character */
158 bcount=0;
160 s++;
161 len++;
163 arg=HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
164 if (!arg)
165 return NULL;
167 bcount=0;
168 in_quotes=0;
169 d=arg;
170 s=*cmdline;
171 while (*s) {
172 if ((*s=='\t' || *s==' ') && !in_quotes) {
173 /* end of this command line argument */
174 break;
175 } else if (*s=='\\') {
176 /* '\\' */
177 *d++=*s++;
178 bcount++;
179 } else if (*s=='"') {
180 /* '"' */
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.
185 d-=bcount/2;
186 in_quotes=!in_quotes;
187 s++;
188 } else {
189 /* Preceded by an odd number of '\', this is half that
190 * number of '\' followed by a '"'
192 d=d-bcount/2-1;
193 *d++='"';
194 s++;
196 bcount=0;
197 } else {
198 /* a regular character */
199 *d++=*s++;
200 bcount=0;
203 *d=0;
204 *cmdline=s;
206 /* skip the remaining spaces */
207 while (**cmdline=='\t' || **cmdline==' ') {
208 (*cmdline)++;
211 return arg;
214 int WINAPI WinMain(HINSTANCE instance, HINSTANCE hOldInstance, LPSTR szCmdArgs, int nCmdShow)
216 HWND hWnd;
217 LPWSTR szCmdLine;
218 LPWSTR szDllName,szEntryPoint;
219 void *entry_point;
220 BOOL unicode, win16;
221 STARTUPINFOW info;
222 HMODULE hDll;
224 hWnd=NULL;
225 hDll=NULL;
226 szDllName=NULL;
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)
239 goto CLEANUP;
240 HeapFree(GetProcessHeap(),0,szDllName);
242 /* Get the dll name and API EntryPoint */
243 szDllName=GetNextArg(&szCmdLine);
244 if (!szDllName || *szDllName==0)
245 goto CLEANUP;
246 WINE_TRACE("DllName=%s\n",wine_dbgstr_w(szDllName));
247 if ((szEntryPoint = strchrW(szDllName, ',' )))
248 *szEntryPoint++=0;
249 else
250 szEntryPoint = GetNextArg(&szCmdLine);
251 WINE_TRACE("EntryPoint=%s\n",wine_dbgstr_w(szEntryPoint));
253 /* Load the library */
254 hDll=LoadLibraryW(szDllName);
255 if (hDll)
257 win16 = FALSE;
258 entry_point = get_entry_point32( hDll, szEntryPoint, &unicode );
260 else
262 HINSTANCE16 dll = load_dll16( szDllName );
263 if (dll <= 32)
265 /* Windows has a MessageBox here... */
266 WINE_ERR("Unable to load %s\n",wine_dbgstr_w(szDllName));
267 goto CLEANUP;
269 win16 = TRUE;
270 unicode = FALSE;
271 entry_point = get_entry_point16( dll, szEntryPoint );
274 if (!entry_point)
276 /* Windows has a MessageBox here... */
277 WINE_ERR( "Unable to find the entry point %s in %s\n",
278 wine_dbgstr_w(szEntryPoint), wine_dbgstr_w(szDllName) );
279 goto CLEANUP;
282 GetStartupInfoW( &info );
283 if (!(info.dwFlags & STARTF_USESHOWWINDOW)) info.wShowWindow = SW_SHOWDEFAULT;
285 if (unicode)
287 EntryPointW pEntryPointW = entry_point;
289 WINE_TRACE( "Calling %s (%p,%p,%s,%d)\n", wine_dbgstr_w(szEntryPoint),
290 hWnd, instance, wine_dbgstr_w(szCmdLine), info.wShowWindow );
292 pEntryPointW( hWnd, instance, szCmdLine, info.wShowWindow );
294 else
296 DWORD len = WideCharToMultiByte( CP_ACP, 0, szCmdLine, -1, NULL, 0, NULL, NULL );
297 char *cmdline = HeapAlloc( GetProcessHeap(), 0, len );
298 WideCharToMultiByte( CP_ACP, 0, szCmdLine, -1, cmdline, len, NULL, NULL );
300 WINE_TRACE( "Calling %s (%p,%p,%s,%d)\n", wine_dbgstr_w(szEntryPoint),
301 hWnd, instance, wine_dbgstr_a(cmdline), info.wShowWindow );
303 if (win16)
305 HMODULE shell = LoadLibraryA( "shell32.dll" );
306 if (shell) pRunDLL_CallEntry16 = (void *)GetProcAddress( shell, (LPCSTR)122 );
307 if (pRunDLL_CallEntry16)
308 pRunDLL_CallEntry16( entry_point, hWnd, instance, cmdline, info.wShowWindow );
310 else
312 EntryPointA pEntryPointA = entry_point;
313 pEntryPointA( hWnd, instance, cmdline, info.wShowWindow );
315 HeapFree( GetProcessHeap(), 0, cmdline );
318 CLEANUP:
319 if (hWnd)
320 DestroyWindow(hWnd);
321 if (hDll)
322 FreeLibrary(hDll);
323 HeapFree(GetProcessHeap(),0,szDllName);
324 return 0; /* rundll32 always returns 0! */