Release 950918
[wine] / misc / shell.c
1 /*
2  *                              Shell Library Functions
3  */
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <ctype.h>
9 #include "windows.h"
10 #include "shell.h"
11 #include "global.h"
12 #include "neexe.h"
13 #include "selectors.h"
14 #include "alias.h"
15 #include "relay32.h"
16 #include "../rc/sysres.h"
17 #include "dlgs.h"
18 #include "stddebug.h"
19 #include "debug.h"
20
21 LPKEYSTRUCT     lphRootKey = NULL,lphTopKey = NULL;
22
23 static char RootKeyName[]=".classes", TopKeyName[] = "[top-null]";
24
25 /*************************************************************************
26  *                        SHELL_RegCheckForRoot()     internal use only
27  */
28 static LONG SHELL_RegCheckForRoot()
29 {
30     HKEY hNewKey;
31
32     if (lphRootKey == NULL){
33       hNewKey = GlobalAlloc(GMEM_MOVEABLE,sizeof(KEYSTRUCT));
34       lphRootKey = (LPKEYSTRUCT) GlobalLock(hNewKey);
35       if (lphRootKey == NULL) {
36         printf("SHELL_RegCheckForRoot: Couldn't allocate root key!\n");
37         return ERROR_OUTOFMEMORY;
38       }
39       lphRootKey->hKey = 1;
40       lphRootKey->lpSubKey = RootKeyName;
41       lphRootKey->dwType = 0;
42       lphRootKey->lpValue = NULL;
43       lphRootKey->lpSubLvl = lphRootKey->lpNextKey = lphRootKey->lpPrevKey = NULL;
44
45       hNewKey = GlobalAlloc(GMEM_MOVEABLE,sizeof(KEYSTRUCT));
46       lphTopKey = (LPKEYSTRUCT) GlobalLock(hNewKey);
47       if (lphTopKey == NULL) {
48         printf("SHELL_RegCheckForRoot: Couldn't allocate top key!\n");
49         return ERROR_OUTOFMEMORY;
50       }
51       lphTopKey->hKey = 0;
52       lphTopKey->lpSubKey = TopKeyName;
53       lphTopKey->dwType = 0;
54       lphTopKey->lpValue = NULL;
55       lphTopKey->lpSubLvl = lphRootKey;
56       lphTopKey->lpNextKey = lphTopKey->lpPrevKey = NULL;
57
58       dprintf_reg(stddeb,"SHELL_RegCheckForRoot: Root/Top created\n");
59     }
60     return ERROR_SUCCESS;
61 }
62
63 /*************************************************************************
64  *                              RegOpenKey              [SHELL.1]
65  */
66 LONG RegOpenKey(HKEY hKey, LPCSTR lpSubKey, HKEY FAR *lphKey)
67 {
68         LPKEYSTRUCT     lpKey,lpNextKey;
69         LPCSTR          ptr;
70         char            str[128];
71         LONG            dwRet;
72
73         dwRet = SHELL_RegCheckForRoot();
74         if (dwRet != ERROR_SUCCESS) return dwRet;
75         dprintf_reg(stddeb, "RegOpenKey(%08lX, %p='%s', %p)\n",
76                                                 hKey, lpSubKey, lpSubKey, lphKey);
77         if (lphKey == NULL) return ERROR_INVALID_PARAMETER;
78         switch(hKey) {
79         case 0: 
80           lpKey = lphTopKey; break;
81         case HKEY_CLASSES_ROOT: /* == 1 */
82         case 0x80000000:
83           lpKey = lphRootKey; break;
84         default: 
85           dprintf_reg(stddeb,"RegOpenKey // specific key = %08lX !\n", hKey);
86           lpKey = (LPKEYSTRUCT)GlobalLock(hKey);
87         }
88         if (lpSubKey == NULL || !*lpSubKey)  { 
89           *lphKey = hKey; 
90           return ERROR_SUCCESS; 
91         }
92         while(*lpSubKey) {
93           ptr = strchr(lpSubKey,'\\');
94           if (!ptr) ptr = lpSubKey + strlen(lpSubKey);
95           strncpy(str,lpSubKey,ptr-lpSubKey);
96           str[ptr-lpSubKey] = 0;
97           lpSubKey = ptr; 
98           if (*lpSubKey) lpSubKey++;
99           
100           lpNextKey = lpKey->lpSubLvl;
101           while(lpKey != NULL && strcmp(lpKey->lpSubKey, str) != 0) { 
102                 lpKey = lpNextKey;
103                 if (lpKey) lpNextKey = lpKey->lpNextKey;
104           }
105           if (lpKey == NULL) {
106             dprintf_reg(stddeb,"RegOpenKey: key %s not found!\n",str);
107             return ERROR_BADKEY;
108           }         
109         }
110         *lphKey = lpKey->hKey;
111         return ERROR_SUCCESS;
112 }
113
114
115 /*************************************************************************
116  *                              RegCreateKey            [SHELL.2]
117  */
118 LONG RegCreateKey(HKEY hKey, LPCSTR lpSubKey, HKEY FAR *lphKey)
119 {
120         HKEY            hNewKey;
121         LPKEYSTRUCT     lpNewKey;
122         LPKEYSTRUCT     lpKey;
123         LPKEYSTRUCT     lpPrevKey;
124         LONG            dwRet;
125         LPCSTR          ptr;
126         char            str[128];
127
128         dwRet = SHELL_RegCheckForRoot();
129         if (dwRet != ERROR_SUCCESS) return dwRet;
130         dprintf_reg(stddeb, "RegCreateKey(%08lX, '%s', %p)\n",  hKey, lpSubKey, lphKey);
131         if (lphKey == NULL) return ERROR_INVALID_PARAMETER;
132         switch(hKey) {
133         case 0: 
134           lpKey = lphTopKey; break;
135         case HKEY_CLASSES_ROOT: /* == 1 */
136         case 0x80000000:
137           lpKey = lphRootKey; break;
138         default: 
139           dprintf_reg(stddeb,"RegCreateKey // specific key = %08lX !\n", hKey);
140           lpKey = (LPKEYSTRUCT)GlobalLock(hKey);
141         }
142         if (lpSubKey == NULL || !*lpSubKey)  { 
143           *lphKey = hKey; 
144           return ERROR_SUCCESS;
145         }
146         while (*lpSubKey) {
147           dprintf_reg(stddeb, "RegCreateKey: Looking for subkey %s\n", lpSubKey);
148           ptr = strchr(lpSubKey,'\\');
149           if (!ptr) ptr = lpSubKey + strlen(lpSubKey);
150           strncpy(str,lpSubKey,ptr-lpSubKey);
151           str[ptr-lpSubKey] = 0;
152           lpSubKey = ptr; 
153           if (*lpSubKey) lpSubKey++;
154           
155           lpPrevKey = lpKey;
156           lpKey = lpKey->lpSubLvl;
157           while(lpKey != NULL && strcmp(lpKey->lpSubKey, str) != 0) { 
158             lpKey = lpKey->lpNextKey; 
159           }
160           if (lpKey == NULL) {
161             hNewKey = GlobalAlloc(GMEM_MOVEABLE, sizeof(KEYSTRUCT));
162             lpNewKey = (LPKEYSTRUCT) GlobalLock(hNewKey);
163             if (lpNewKey == NULL) {
164               printf("RegCreateKey // Can't alloc new key !\n");
165               return ERROR_OUTOFMEMORY;
166             }
167             lpNewKey->hKey = hNewKey;
168             lpNewKey->lpSubKey = malloc(strlen(str) + 1);
169             if (lpNewKey->lpSubKey == NULL) {
170               printf("RegCreateKey // Can't alloc key string !\n");
171               return ERROR_OUTOFMEMORY;
172             }
173             strcpy(lpNewKey->lpSubKey, str);
174             lpNewKey->lpNextKey = lpPrevKey->lpSubLvl;
175             lpNewKey->lpPrevKey = NULL;
176             lpPrevKey->lpSubLvl = lpNewKey;
177
178             lpNewKey->dwType = 0;
179             lpNewKey->lpValue = NULL;
180             lpNewKey->lpSubLvl = NULL;
181             *lphKey = hNewKey;
182             dprintf_reg(stddeb,"RegCreateKey // successful '%s' key=%08lX !\n", str, hNewKey);
183             lpKey = lpNewKey;
184           } else {
185             *lphKey = lpKey->hKey;
186             dprintf_reg(stddeb,"RegCreateKey // found '%s', key=%08lX\n", str, *lphKey);
187           }
188         }
189         return ERROR_SUCCESS;
190 }
191
192
193 /*************************************************************************
194  *                              RegCloseKey             [SHELL.3]
195  */
196 LONG RegCloseKey(HKEY hKey)
197 {
198         dprintf_reg(stdnimp, "EMPTY STUB !!! RegCloseKey(%08lX);\n", hKey);
199         return ERROR_SUCCESS;
200 }
201
202
203 /*************************************************************************
204  *                              RegDeleteKey            [SHELL.4]
205  */
206 LONG RegDeleteKey(HKEY hKey, LPCSTR lpSubKey)
207 {
208         dprintf_reg(stdnimp, "EMPTY STUB !!! RegDeleteKey(%08lX, '%s');\n", 
209                                                                                                 hKey, lpSubKey);
210         return ERROR_SUCCESS;
211 }
212
213
214 /*************************************************************************
215  *                              RegSetValue             [SHELL.5]
216  */
217 LONG RegSetValue(HKEY hKey, LPCSTR lpSubKey, DWORD dwType, 
218                  LPCSTR lpVal, DWORD dwIgnored)
219 {
220     HKEY        hRetKey;
221     LPKEYSTRUCT lpKey;
222     LONG        dwRet;
223     dprintf_reg(stddeb, "RegSetValue(%08lX, '%s', %08lX, '%s', %08lX);\n",
224                 hKey, lpSubKey, dwType, lpVal, dwIgnored);
225     /*if (lpSubKey == NULL) return ERROR_INVALID_PARAMETER;*/
226     if (lpVal == NULL) return ERROR_INVALID_PARAMETER;
227     if ((dwRet = RegOpenKey(hKey, lpSubKey, &hRetKey)) != ERROR_SUCCESS) {
228         dprintf_reg(stddeb, "RegSetValue // key not found ... so create it !\n");
229         if ((dwRet = RegCreateKey(hKey, lpSubKey, &hRetKey)) != ERROR_SUCCESS) {
230             fprintf(stderr, "RegSetValue // key creation error %08lX !\n", dwRet);
231             return dwRet;
232         }
233     }
234     lpKey = (LPKEYSTRUCT)GlobalLock(hRetKey);
235     if (lpKey == NULL) return ERROR_BADKEY;
236     if (lpKey->lpValue != NULL) free(lpKey->lpValue);
237     lpKey->lpValue = malloc(strlen(lpVal) + 1);
238     strcpy(lpKey->lpValue, lpVal);
239     dprintf_reg(stddeb,"RegSetValue // successful key='%s' val='%s' !\n", lpSubKey, lpKey->lpValue);
240     return ERROR_SUCCESS;
241 }
242
243
244 /*************************************************************************
245  *                              RegQueryValue           [SHELL.6]
246  */
247 LONG RegQueryValue(HKEY hKey, LPCSTR lpSubKey, LPSTR lpVal, LONG FAR *lpcb)
248 {
249         HKEY            hRetKey;
250         LPKEYSTRUCT     lpKey;
251         LONG            dwRet;
252         int                     size;
253         dprintf_reg(stddeb, "RegQueryValue(%08lX, '%s', %p, %p);\n",
254                                                         hKey, lpSubKey, lpVal, lpcb);
255         /*if (lpSubKey == NULL) return ERROR_INVALID_PARAMETER;*/
256         if (lpVal == NULL) return ERROR_INVALID_PARAMETER;
257         if (lpcb == NULL) return ERROR_INVALID_PARAMETER;
258         if (!*lpcb) return ERROR_INVALID_PARAMETER;
259
260         if ((dwRet = RegOpenKey(hKey, lpSubKey, &hRetKey)) != ERROR_SUCCESS) {
261                 fprintf(stderr, "RegQueryValue // key not found !\n");
262                 return dwRet;
263         }
264         lpKey = (LPKEYSTRUCT)GlobalLock(hRetKey);
265         if (lpKey == NULL) return ERROR_BADKEY;
266         if (lpKey->lpValue != NULL) {
267           if ((size = strlen(lpKey->lpValue)+1) > *lpcb){
268             strncpy(lpVal,lpKey->lpValue,*lpcb-1);
269             lpVal[*lpcb-1] = 0;
270           } else {
271             strcpy(lpVal,lpKey->lpValue);
272             *lpcb = size;
273           }
274         } else {
275           *lpVal = 0;
276           *lpcb = (LONG)1;
277         }
278         dprintf_reg(stddeb,"RegQueryValue // return '%s' !\n", lpVal);
279         return ERROR_SUCCESS;
280 }
281
282
283 /*************************************************************************
284  *                              RegEnumKey              [SHELL.7]
285  */
286 LONG RegEnumKey(HKEY hKey, DWORD dwSubKey, LPSTR lpBuf, DWORD dwSize)
287 {
288         LPKEYSTRUCT     lpKey;
289         LONG            dwRet;
290         LONG            len;
291
292         dwRet = SHELL_RegCheckForRoot();
293         if (dwRet != ERROR_SUCCESS) return dwRet;
294         dprintf_reg(stddeb, "RegEnumKey(%08lX, %ld)\n", hKey, dwSubKey);
295         if (lpBuf == NULL) return ERROR_INVALID_PARAMETER;
296         switch(hKey) {
297         case 0: 
298           lpKey = lphTopKey; break;
299         case HKEY_CLASSES_ROOT: /* == 1 */
300         case 0x80000000:
301           lpKey = lphRootKey; break;
302         default: 
303           dprintf_reg(stddeb,"RegEnumKey // specific key = %08lX !\n", hKey);
304           lpKey = (LPKEYSTRUCT)GlobalLock(hKey);
305         }
306         lpKey = lpKey->lpSubLvl;
307         while(lpKey != NULL){
308           if (!dwSubKey){
309             len = min(dwSize-1,strlen(lpKey->lpSubKey));
310             strncpy(lpBuf,lpKey->lpSubKey,len);
311             lpBuf[len] = 0;
312             dprintf_reg(stddeb, "RegEnumKey: found %s\n",lpBuf);
313             return ERROR_SUCCESS;
314           }
315           dwSubKey--;
316           lpKey = lpKey->lpNextKey;
317         }
318         dprintf_reg(stddeb, "RegEnumKey: key not found!\n");
319         return ERROR_INVALID_PARAMETER;
320 }
321
322 /*************************************************************************
323  *                              DragAcceptFiles         [SHELL.9]
324  */
325 void DragAcceptFiles(HWND hWnd, BOOL b)
326 {
327         fprintf(stdnimp, "DragAcceptFiles : Empty Stub !!!\n");
328 }
329
330
331 /*************************************************************************
332  *                              DragQueryFile           [SHELL.11]
333  */
334 void DragQueryFile(HDROP h, UINT u, LPSTR u2, UINT u3)
335 {
336         fprintf(stdnimp, "DragQueryFile : Empty Stub !!!\n");
337
338 }
339
340
341 /*************************************************************************
342  *                              DragFinish              [SHELL.12]
343  */
344 void DragFinish(HDROP h)
345 {
346         fprintf(stdnimp, "DragFinish : Empty Stub !!!\n");
347 }
348
349
350 /*************************************************************************
351  *                              DragQueryPoint          [SHELL.13]
352  */
353 BOOL DragQueryPoint(HDROP h, POINT FAR *p)
354 {
355         fprintf(stdnimp, "DragQueryPoint : Empty Stub !!!\n");
356         return FALSE;
357 }
358
359
360 /*************************************************************************
361  *                              ShellExecute            [SHELL.20]
362  */
363 HINSTANCE ShellExecute(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, int iShowCmd)
364 {
365     char cmd[400];
366     char *p,*x;
367     long len;
368     char subclass[200];
369     /* OK. We are supposed to lookup the program associated with lpFile,
370      * then to execute it using that program. If lpFile is a program,
371      * we have to pass the parameters. If an instance is already running,
372      * we might have to send DDE commands.
373      */
374     dprintf_exec(stddeb, "ShellExecute(%4X,'%s','%s','%s','%s',%x)\n",
375                 hWnd, lpOperation ? lpOperation:"<null>", lpFile ? lpFile:"<null>",
376                 lpParameters ? lpParameters : "<null>", 
377                 lpDirectory ? lpDirectory : "<null>", iShowCmd);
378     if (lpFile==NULL) return 0; /* should not happen */
379     if (lpOperation==NULL) /* default is open */
380       lpOperation="open";
381     p=strrchr(lpFile,'.');
382     if (p!=NULL) {
383       x=p; /* the suffixes in the register database are lowercased */
384       while (*x) {*x=tolower(*x);x++;}
385     }
386     if (p==NULL || !strcmp(p,".exe")) {
387       p=".exe";
388       if (lpParameters) {
389         sprintf(cmd,"%s %s",lpFile,lpParameters);
390       } else {
391         strcpy(cmd,lpFile);
392       }
393     } else {
394       len=200;
395       if (RegQueryValue(HKEY_CLASSES_ROOT,p,subclass,&len)==ERROR_SUCCESS) {
396         if (len>20)
397           fprintf(stddeb,"ShellExecute:subclass with len %ld? (%s), please report.\n",len,subclass);
398         subclass[len]='\0';
399         strcat(subclass,"\\shell\\");
400         strcat(subclass,lpOperation);
401         strcat(subclass,"\\command");
402         dprintf_exec(stddeb,"ShellExecute:looking for %s.\n",subclass);
403         len=400;
404         if (RegQueryValue(HKEY_CLASSES_ROOT,subclass,cmd,&len)==ERROR_SUCCESS) {
405           char *t;
406           dprintf_exec(stddeb,"ShellExecute:...got %s\n",cmd);
407           cmd[len]='\0';
408           t=strstr(cmd,"%1");
409           if (t==NULL) {
410             strcat(cmd," ");
411             strcat(cmd,lpFile);
412           } else {
413             char *s;
414             s=malloc(len+strlen(lpFile)+10);
415             strncpy(s,cmd,t-cmd);
416             strcat(s,lpFile);
417             strcat(s,t+2);
418             strcpy(cmd,s);
419             free(s);
420           }
421           /* does this use %x magic too? */
422           if (lpParameters) {
423             strcat(cmd," ");
424             strcat(cmd,lpParameters);
425           }
426         } else {
427           fprintf(stddeb,"ShellExecute: No %s\\shell\\%s\\command found for \"%s\" suffix.\n",subclass,lpOperation,p);
428           return 14; /* unknown type */
429         }
430       } else {
431         fprintf(stddeb,"ShellExecute: No operation found for \"%s\" suffix.\n",p);
432         return 14; /* file not found */
433       }
434     }
435     return WinExec(cmd,iShowCmd);
436 }
437
438
439 /*************************************************************************
440  *                              FindExecutable          [SHELL.21]
441  */
442 HINSTANCE FindExecutable(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
443 {
444         fprintf(stdnimp, "FindExecutable : Empty Stub !!!\n");
445         return 0;
446 }
447
448 static char AppName[512], AppMisc[512];
449
450 /*************************************************************************
451  *                              AboutDlgProc            [SHELL.33]
452  */
453 INT AboutDlgProc(HWND hWnd, WORD msg, WORD wParam, LONG lParam)
454 {
455   char Template[512], AppTitle[512];
456  
457   switch(msg) {
458    case WM_INITDIALOG:
459     SendDlgItemMessage(hWnd,stc1,STM_SETICON,LOWORD(lParam),0);
460     GetWindowText(hWnd, Template, 511);
461     sprintf(AppTitle, Template, AppName);
462     SetWindowText(hWnd, AppTitle);
463     SetWindowText(GetDlgItem(hWnd,100), AppMisc);
464     return 1;
465     
466    case WM_COMMAND:
467     switch (wParam) {
468      case IDOK:
469       EndDialog(hWnd, TRUE);
470       return TRUE;
471     }
472     break;
473   }
474   return FALSE;
475 }
476
477 /*************************************************************************
478  *                              ShellAbout              [SHELL.22]
479  */
480 INT ShellAbout(HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff, HICON hIcon)
481 {
482     HANDLE handle;
483     BOOL bRet;
484     DWORD WineProc,Win16Proc,Win32Proc;
485     static int initialized=0;
486
487     if (szApp) strcpy(AppName, szApp);
488     else *AppName = 0;
489
490     if (szOtherStuff) strcpy(AppMisc, szOtherStuff);
491     else *AppMisc = 0;
492
493     if (!hIcon) hIcon = LoadIcon(0,MAKEINTRESOURCE(OIC_WINEICON));
494     
495     if(!initialized)
496     {
497         WineProc=(DWORD)AboutDlgProc;
498         Win16Proc=(DWORD)GetWndProcEntry16("AboutDlgProc");
499         Win32Proc=(DWORD)RELAY32_GetEntryPoint("WINPROCS32","AboutDlgProc",0);
500         ALIAS_RegisterAlias(WineProc,Win16Proc,Win32Proc);
501         initialized=1;
502     }
503
504     handle = GLOBAL_CreateBlock( GMEM_FIXED,
505                                  sysres_DIALOG_SHELL_ABOUT_MSGBOX.bytes,
506                                  sysres_DIALOG_SHELL_ABOUT_MSGBOX.size,
507                                  GetCurrentPDB(), FALSE, FALSE,
508                                  TRUE, NULL );
509     if (!handle) return FALSE;
510     bRet = DialogBoxIndirectParam( GetWindowWord( hWnd, GWW_HINSTANCE ),
511                                    handle, hWnd,
512                                    GetWndProcEntry16("AboutDlgProc"), hIcon );
513     GLOBAL_FreeBlock( handle );
514     return bRet;
515 }
516
517 /*************************************************************************
518  *                              ExtractIcon             [SHELL.34]
519  */
520 HICON ExtractIcon(HINSTANCE hInst, LPCSTR lpszExeFileName, UINT nIconIndex)
521 {
522         HICON   hIcon = 0;
523         HINSTANCE hInst2 = hInst;
524         dprintf_reg(stddeb, "ExtractIcon(%04X, '%s', %d\n", 
525                         hInst, lpszExeFileName, nIconIndex);
526         return 0;
527         if (lpszExeFileName != NULL) {
528                 hInst2 = LoadModule(lpszExeFileName,(LPVOID)-1);
529         }
530         if (hInst2 != 0 && nIconIndex == (UINT)-1) {
531 #if 0
532                 count = GetRsrcCount(hInst2, NE_RSCTYPE_GROUP_ICON);
533                 dprintf_reg(stddeb, "ExtractIcon // '%s' has %d icons !\n", lpszExeFileName, count);
534                 return (HICON)count;
535 #endif
536         }
537         if (hInst2 != hInst && hInst2 != 0) {
538                 FreeLibrary(hInst2);
539         }
540         return hIcon;
541 }
542
543
544 /*************************************************************************
545  *                              ExtractAssociatedIcon   [SHELL.36]
546  */
547 HICON ExtractAssociatedIcon(HINSTANCE hInst,LPSTR lpIconPath, LPWORD lpiIcon)
548 {
549     dprintf_reg(stdnimp, "ExtractAssociatedIcon : Empty Stub !!!\n");
550     return 0;
551 }
552
553 /*************************************************************************
554  *              DoEnvironmentSubst      [SHELL.37]
555  */
556 DWORD DoEnvironmentSubst(LPSTR str,WORD len)
557 {
558     dprintf_reg(stdnimp, "DoEnvironmentSubst(%s,%x): Empyt Stub !!!\n",str,len);
559     return 0;
560 }
561
562 /*************************************************************************
563  *                              RegisterShellHook       [SHELL.102]
564  */
565 int RegisterShellHook(void *ptr) 
566 {
567         dprintf_reg(stdnimp, "RegisterShellHook : Empty Stub !!!\n");
568         return 0;
569 }
570
571
572 /*************************************************************************
573  *                              ShellHookProc           [SHELL.103]
574  */
575 int ShellHookProc(void) 
576 {
577         dprintf_reg(stdnimp, "ShellHookProc : Empty Stub !!!\n");
578         return 0;
579 }