Release 951105
[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 "win.h"
19 #include "stddebug.h"
20 #include "debug.h"
21 #include "xmalloc.h"
22
23 LPKEYSTRUCT     lphRootKey = NULL,lphTopKey = NULL;
24
25 static char RootKeyName[]=".classes", TopKeyName[] = "[top-null]";
26
27 /*************************************************************************
28  *                        SHELL_RegCheckForRoot()     internal use only
29  */
30 static LONG SHELL_RegCheckForRoot()
31 {
32     HKEY hNewKey;
33
34     if (lphRootKey == NULL){
35       hNewKey = GlobalAlloc(GMEM_MOVEABLE,sizeof(KEYSTRUCT));
36       lphRootKey = (LPKEYSTRUCT) GlobalLock(hNewKey);
37       if (lphRootKey == NULL) {
38         printf("SHELL_RegCheckForRoot: Couldn't allocate root key!\n");
39         return ERROR_OUTOFMEMORY;
40       }
41       lphRootKey->hKey = (HKEY)1;
42       lphRootKey->lpSubKey = RootKeyName;
43       lphRootKey->dwType = 0;
44       lphRootKey->lpValue = NULL;
45       lphRootKey->lpSubLvl = lphRootKey->lpNextKey = lphRootKey->lpPrevKey = NULL;
46
47       hNewKey = GlobalAlloc(GMEM_MOVEABLE,sizeof(KEYSTRUCT));
48       lphTopKey = (LPKEYSTRUCT) GlobalLock(hNewKey);
49       if (lphTopKey == NULL) {
50         printf("SHELL_RegCheckForRoot: Couldn't allocate top key!\n");
51         return ERROR_OUTOFMEMORY;
52       }
53       lphTopKey->hKey = 0;
54       lphTopKey->lpSubKey = TopKeyName;
55       lphTopKey->dwType = 0;
56       lphTopKey->lpValue = NULL;
57       lphTopKey->lpSubLvl = lphRootKey;
58       lphTopKey->lpNextKey = lphTopKey->lpPrevKey = NULL;
59
60       dprintf_reg(stddeb,"SHELL_RegCheckForRoot: Root/Top created\n");
61     }
62     return ERROR_SUCCESS;
63 }
64
65 /* FIXME: the loading and saving of the registry database is rather messy.
66  * bad input (while reading) may crash wine.
67  */
68 void
69 _DumpLevel(FILE *f,LPKEYSTRUCT lpTKey,int tabs) {
70         LPKEYSTRUCT     lpKey;
71
72         lpKey=lpTKey->lpSubLvl;
73         while (lpKey) {
74                 int     i;
75                 for (i=0;i<tabs;i++) fprintf(f,"\t");
76                 /* implement different dwTypes ... */
77                 if (lpKey->lpValue)
78                         fprintf(f,"%s=%s\n",lpKey->lpSubKey,lpKey->lpValue);
79                 else
80                         fprintf(f,"%s\n",lpKey->lpSubKey);
81
82                 if (lpKey->lpSubLvl)
83                         _DumpLevel(f,lpKey,tabs+1);
84                 lpKey=lpKey->lpNextKey;
85         }
86 }
87
88 static void
89 _SaveKey(HKEY hKey,char *where) {
90         FILE            *f;
91         LPKEYSTRUCT     lpKey;
92
93         f=fopen(where,"w");
94         if (f==NULL) {
95                 perror("registry-fopen");
96                 return;
97         }
98         switch ((DWORD)hKey) {
99         case HKEY_CLASSES_ROOT:
100                 lpKey=lphRootKey;
101                 break;
102         default:return;
103         }
104         _DumpLevel(f,lpKey,0);
105         fclose(f);
106 }
107
108 void
109 SHELL_SaveRegistry(void) {
110         /* FIXME: 
111          * -implement win95 additional keytypes here
112          * (HKEY_LOCAL_MACHINE,HKEY_CURRENT_USER or whatever)
113          * -choose better filename(s)
114          */
115         _SaveKey((HKEY)HKEY_CLASSES_ROOT,"/tmp/winereg");
116 }
117
118 #define BUFSIZE 256
119 void
120 _LoadLevel(FILE *f,LPKEYSTRUCT lpKey,int tabsexp,char *buf) {
121         int             i;
122         char            *s,*t;
123         HKEY            hNewKey;
124         LPKEYSTRUCT     lpNewKey;
125
126         while (1) {
127                 if (NULL==fgets(buf,BUFSIZE,f)) {
128                         buf[0]=0;
129                         return;
130                 }
131                 for (i=0;buf[i]=='\t';i++) /*empty*/;
132                 s=buf+i;
133                 if (NULL!=(t=strchr(s,'\n'))) *t='\0';
134                 if (NULL!=(t=strchr(s,'\r'))) *t='\0';
135
136                 if (i<tabsexp) return;
137
138                 if (i>tabsexp) {
139                         hNewKey=GlobalAlloc(GMEM_MOVEABLE,sizeof(KEYSTRUCT));
140                         lpNewKey=lpKey->lpSubLvl=(LPKEYSTRUCT)GlobalLock(hNewKey);
141                         lpNewKey->hKey          = hNewKey;
142                         lpNewKey->dwType        = 0;
143                         lpNewKey->lpSubKey      = NULL;
144                         lpNewKey->lpValue       = NULL;
145                         lpNewKey->lpSubLvl      = NULL;
146                         lpNewKey->lpNextKey     = NULL;
147                         lpNewKey->lpPrevKey     = NULL;
148                         if (NULL!=(t=strchr(s,'='))) {
149                                 *t='\0';t++;
150                                 lpNewKey->dwType        = REG_SZ;
151                                 lpNewKey->lpSubKey      = strdup(s);
152                                 lpNewKey->lpValue       = strdup(t);
153                         } else {
154                                 lpNewKey->dwType        = REG_SZ;
155                                 lpNewKey->lpSubKey      = strdup(s);
156                         }
157                         _LoadLevel(f,lpNewKey,tabsexp+1,buf);
158                 }
159                 for (i=0;buf[i]=='\t';i++) /*empty*/;
160                 s=buf+i;
161                 if (i<tabsexp) return;
162                 if (buf[0]=='\0') break; /* marks end of file */
163                 /* we have a buf now. even when returning from _LoadLevel */
164                 hNewKey         = GlobalAlloc(GMEM_MOVEABLE,sizeof(KEYSTRUCT));
165                 lpNewKey        = lpKey->lpNextKey=(LPKEYSTRUCT)GlobalLock(hNewKey);
166                 lpNewKey->lpPrevKey     = lpKey;
167                 lpNewKey->hKey          = hNewKey;
168                 lpNewKey->dwType        = 0;
169                 lpNewKey->lpSubKey      = NULL;
170                 lpNewKey->lpValue       = NULL;
171                 lpNewKey->lpSubLvl      = NULL;
172                 lpNewKey->lpNextKey     = NULL;
173                 if (NULL!=(t=strchr(s,'='))) {
174                         *t='\0';t++;
175                         lpNewKey->dwType        = REG_SZ;
176                         lpNewKey->lpSubKey      = strdup(s);
177                         lpNewKey->lpValue       = strdup(t);
178                 } else {
179                         lpNewKey->dwType        = REG_SZ;
180                         lpNewKey->lpSubKey      = strdup(s);
181                 }
182                 lpKey=lpNewKey;
183         }
184 }
185
186 void
187 _LoadKey(HKEY hKey,char *from) {
188         FILE            *f;
189         LPKEYSTRUCT     lpKey;
190         char            buf[BUFSIZE]; /* FIXME: long enough? */
191
192         f=fopen(from,"r");
193         if (f==NULL) {
194                 perror("fopen-registry-read");
195                 return;
196         }
197         switch ((DWORD)hKey) {
198         case HKEY_CLASSES_ROOT:
199                 lpKey=lphRootKey;
200                 break;
201         default:return;
202         }
203         _LoadLevel(f,lpKey,-1,buf);
204 }
205
206 void
207 SHELL_LoadRegistry(void) {
208         DWORD   dwRet;
209
210         dwRet=SHELL_RegCheckForRoot();
211         if (dwRet!=ERROR_SUCCESS) 
212                 return;/*very bad magic, if we can't even allocate the rootkeys*/
213         _LoadKey((HKEY)HKEY_CLASSES_ROOT,"/tmp/winereg");
214 }
215
216 /*************************************************************************
217  *                              RegOpenKey              [SHELL.1]
218  */
219 LONG RegOpenKey(HKEY hKey, LPCSTR lpSubKey, HKEY FAR *lphKey)
220 {
221         LPKEYSTRUCT     lpKey,lpNextKey;
222         LPCSTR          ptr;
223         char            str[128];
224         LONG            dwRet;
225
226         dwRet = SHELL_RegCheckForRoot();
227         if (dwRet != ERROR_SUCCESS) return dwRet;
228         dprintf_reg(stddeb, "RegOpenKey(%08lX, %p='%s', %p)\n",
229                                        (DWORD)hKey, lpSubKey, lpSubKey, lphKey);
230         if (lphKey == NULL) return ERROR_INVALID_PARAMETER;
231         switch((DWORD)hKey) {
232         case 0: 
233           lpKey = lphTopKey; break;
234         case HKEY_CLASSES_ROOT: /* == 1 */
235         case 0x80000000:
236           lpKey = lphRootKey; break;
237         default: 
238           dprintf_reg(stddeb,"RegOpenKey // specific key = %08lX !\n", (DWORD)hKey);
239           lpKey = (LPKEYSTRUCT)GlobalLock(hKey);
240         }
241         if (lpSubKey == NULL || !*lpSubKey)  { 
242           *lphKey = hKey; 
243           return ERROR_SUCCESS; 
244         }
245         while(*lpSubKey) {
246           ptr = strchr(lpSubKey,'\\');
247           if (!ptr) ptr = lpSubKey + strlen(lpSubKey);
248           strncpy(str,lpSubKey,ptr-lpSubKey);
249           str[ptr-lpSubKey] = 0;
250           lpSubKey = ptr; 
251           if (*lpSubKey) lpSubKey++;
252           
253           lpNextKey = lpKey->lpSubLvl;
254           while(lpKey != NULL && strcmp(lpKey->lpSubKey, str) != 0) { 
255                 lpKey = lpNextKey;
256                 if (lpKey) lpNextKey = lpKey->lpNextKey;
257           }
258           if (lpKey == NULL) {
259             dprintf_reg(stddeb,"RegOpenKey: key %s not found!\n",str);
260             return ERROR_BADKEY;
261           }         
262         }
263         *lphKey = lpKey->hKey;
264         return ERROR_SUCCESS;
265 }
266
267
268 /*************************************************************************
269  *                              RegCreateKey            [SHELL.2]
270  */
271 LONG RegCreateKey(HKEY hKey, LPCSTR lpSubKey, HKEY FAR *lphKey)
272 {
273         HKEY            hNewKey;
274         LPKEYSTRUCT     lpNewKey;
275         LPKEYSTRUCT     lpKey;
276         LPKEYSTRUCT     lpPrevKey;
277         LONG            dwRet;
278         LPCSTR          ptr;
279         char            str[128];
280
281         dwRet = SHELL_RegCheckForRoot();
282         if (dwRet != ERROR_SUCCESS) return dwRet;
283         dprintf_reg(stddeb, "RegCreateKey(%08lX, '%s', %p)\n",  (DWORD)hKey, lpSubKey, lphKey);
284         if (lphKey == NULL) return ERROR_INVALID_PARAMETER;
285         switch((DWORD)hKey) {
286         case 0: 
287           lpKey = lphTopKey; break;
288         case HKEY_CLASSES_ROOT: /* == 1 */
289         case 0x80000000:
290           lpKey = lphRootKey; break;
291         default: 
292           dprintf_reg(stddeb,"RegCreateKey // specific key = %08lX !\n", (DWORD)hKey);
293           lpKey = (LPKEYSTRUCT)GlobalLock(hKey);
294         }
295         if (lpSubKey == NULL || !*lpSubKey)  { 
296           *lphKey = hKey; 
297           return ERROR_SUCCESS;
298         }
299         while (*lpSubKey) {
300           dprintf_reg(stddeb, "RegCreateKey: Looking for subkey %s\n", lpSubKey);
301           ptr = strchr(lpSubKey,'\\');
302           if (!ptr) ptr = lpSubKey + strlen(lpSubKey);
303           strncpy(str,lpSubKey,ptr-lpSubKey);
304           str[ptr-lpSubKey] = 0;
305           lpSubKey = ptr; 
306           if (*lpSubKey) lpSubKey++;
307           
308           lpPrevKey = lpKey;
309           lpKey = lpKey->lpSubLvl;
310           while(lpKey != NULL && strcmp(lpKey->lpSubKey, str) != 0) { 
311             lpKey = lpKey->lpNextKey; 
312           }
313           if (lpKey == NULL) {
314             hNewKey = GlobalAlloc(GMEM_MOVEABLE, sizeof(KEYSTRUCT));
315             lpNewKey = (LPKEYSTRUCT) GlobalLock(hNewKey);
316             if (lpNewKey == NULL) {
317               printf("RegCreateKey // Can't alloc new key !\n");
318               return ERROR_OUTOFMEMORY;
319             }
320             lpNewKey->hKey = hNewKey;
321             lpNewKey->lpSubKey = malloc(strlen(str) + 1);
322             if (lpNewKey->lpSubKey == NULL) {
323               printf("RegCreateKey // Can't alloc key string !\n");
324               return ERROR_OUTOFMEMORY;
325             }
326             strcpy(lpNewKey->lpSubKey, str);
327             lpNewKey->lpNextKey = lpPrevKey->lpSubLvl;
328             lpNewKey->lpPrevKey = NULL;
329             lpPrevKey->lpSubLvl = lpNewKey;
330
331             lpNewKey->dwType = 0;
332             lpNewKey->lpValue = NULL;
333             lpNewKey->lpSubLvl = NULL;
334             *lphKey = hNewKey;
335             dprintf_reg(stddeb,"RegCreateKey // successful '%s' key=%08lX !\n", str, (DWORD)hNewKey);
336             lpKey = lpNewKey;
337           } else {
338             *lphKey = lpKey->hKey;
339             dprintf_reg(stddeb,"RegCreateKey // found '%s', key=%08lX\n", str, (DWORD)*lphKey);
340           }
341         }
342         return ERROR_SUCCESS;
343 }
344
345
346 /*************************************************************************
347  *                              RegCloseKey             [SHELL.3]
348  */
349 LONG RegCloseKey(HKEY hKey)
350 {
351         dprintf_reg(stdnimp, "EMPTY STUB !!! RegCloseKey(%08lX);\n", (DWORD)hKey);
352         return ERROR_SUCCESS;
353 }
354
355
356 /*************************************************************************
357  *                              RegDeleteKey            [SHELL.4]
358  */
359 LONG RegDeleteKey(HKEY hKey, LPCSTR lpSubKey)
360 {
361         dprintf_reg(stdnimp, "EMPTY STUB !!! RegDeleteKey(%08lX, '%s');\n",
362                      (DWORD)hKey, lpSubKey);
363         return ERROR_SUCCESS;
364 }
365
366
367 /*************************************************************************
368  *                              RegSetValue             [SHELL.5]
369  */
370 LONG RegSetValue(HKEY hKey, LPCSTR lpSubKey, DWORD dwType, 
371                  LPCSTR lpVal, DWORD dwIgnored)
372 {
373     HKEY        hRetKey;
374     LPKEYSTRUCT lpKey;
375     LONG        dwRet;
376     dprintf_reg(stddeb, "RegSetValue(%08lX, '%s', %08lX, '%s', %08lX);\n",
377                 (DWORD)hKey, lpSubKey, dwType, lpVal, dwIgnored);
378     /*if (lpSubKey == NULL) return ERROR_INVALID_PARAMETER;*/
379     if (lpVal == NULL) return ERROR_INVALID_PARAMETER;
380     if ((dwRet = RegOpenKey(hKey, lpSubKey, &hRetKey)) != ERROR_SUCCESS) {
381         dprintf_reg(stddeb, "RegSetValue // key not found ... so create it !\n");
382         if ((dwRet = RegCreateKey(hKey, lpSubKey, &hRetKey)) != ERROR_SUCCESS) {
383             fprintf(stderr, "RegSetValue // key creation error %08lX !\n", dwRet);
384             return dwRet;
385         }
386     }
387     lpKey = (LPKEYSTRUCT)GlobalLock(hRetKey);
388     if (lpKey == NULL) return ERROR_BADKEY;
389     if (lpKey->lpValue != NULL) free(lpKey->lpValue);
390     lpKey->lpValue = xmalloc(strlen(lpVal) + 1);
391     strcpy(lpKey->lpValue, lpVal);
392     dprintf_reg(stddeb,"RegSetValue // successful key='%s' val='%s' !\n", lpSubKey, lpKey->lpValue);
393     return ERROR_SUCCESS;
394 }
395
396
397 /*************************************************************************
398  *                              RegQueryValue           [SHELL.6]
399  */
400 LONG RegQueryValue(HKEY hKey, LPCSTR lpSubKey, LPSTR lpVal, LONG FAR *lpcb)
401 {
402         HKEY            hRetKey;
403         LPKEYSTRUCT     lpKey;
404         LONG            dwRet;
405         int                     size;
406         dprintf_reg(stddeb, "RegQueryValue(%08lX, '%s', %p, %p);\n",
407                     (DWORD)hKey, lpSubKey, lpVal, lpcb);
408         /*if (lpSubKey == NULL) return ERROR_INVALID_PARAMETER;*/
409         if (lpVal == NULL) return ERROR_INVALID_PARAMETER;
410         if (lpcb == NULL) return ERROR_INVALID_PARAMETER;
411         if (!*lpcb) return ERROR_INVALID_PARAMETER;
412
413         if ((dwRet = RegOpenKey(hKey, lpSubKey, &hRetKey)) != ERROR_SUCCESS) {
414                 fprintf(stderr, "RegQueryValue // key not found !\n");
415                 return dwRet;
416         }
417         lpKey = (LPKEYSTRUCT)GlobalLock(hRetKey);
418         if (lpKey == NULL) return ERROR_BADKEY;
419         if (lpKey->lpValue != NULL) {
420           if ((size = strlen(lpKey->lpValue)+1) > *lpcb){
421             strncpy(lpVal,lpKey->lpValue,*lpcb-1);
422             lpVal[*lpcb-1] = 0;
423           } else {
424             strcpy(lpVal,lpKey->lpValue);
425             *lpcb = size;
426           }
427         } else {
428           *lpVal = 0;
429           *lpcb = (LONG)1;
430         }
431         dprintf_reg(stddeb,"RegQueryValue // return '%s' !\n", lpVal);
432         return ERROR_SUCCESS;
433 }
434
435
436 /*************************************************************************
437  *                              RegEnumKey              [SHELL.7]
438  */
439 LONG RegEnumKey(HKEY hKey, DWORD dwSubKey, LPSTR lpBuf, DWORD dwSize)
440 {
441         LPKEYSTRUCT     lpKey;
442         LONG            dwRet;
443         LONG            len;
444
445         dwRet = SHELL_RegCheckForRoot();
446         if (dwRet != ERROR_SUCCESS) return dwRet;
447         dprintf_reg(stddeb, "RegEnumKey(%08lX, %ld)\n", (DWORD)hKey, dwSubKey);
448         if (lpBuf == NULL) return ERROR_INVALID_PARAMETER;
449         switch((DWORD)hKey) {
450         case 0: 
451           lpKey = lphTopKey; break;
452         case HKEY_CLASSES_ROOT: /* == 1 */
453         case 0x80000000:
454           lpKey = lphRootKey; break;
455         default: 
456           dprintf_reg(stddeb,"RegEnumKey // specific key = %08lX !\n", (DWORD)hKey);
457           lpKey = (LPKEYSTRUCT)GlobalLock(hKey);
458         }
459         lpKey = lpKey->lpSubLvl;
460         while(lpKey != NULL){
461           if (!dwSubKey){
462             len = MIN(dwSize-1,strlen(lpKey->lpSubKey));
463             strncpy(lpBuf,lpKey->lpSubKey,len);
464             lpBuf[len] = 0;
465             dprintf_reg(stddeb, "RegEnumKey: found %s\n",lpBuf);
466             return ERROR_SUCCESS;
467           }
468           dwSubKey--;
469           lpKey = lpKey->lpNextKey;
470         }
471         dprintf_reg(stddeb, "RegEnumKey: key not found!\n");
472         return ERROR_INVALID_PARAMETER;
473 }
474
475
476 /*************************************************************************
477  *                              DragAcceptFiles         [SHELL.9]
478  */
479 void DragAcceptFiles(HWND hWnd, BOOL b)
480 {
481  /* flips WS_EX_ACCEPTFILES bit according to the value of b (TRUE or FALSE) */
482
483  dprintf_reg(stddeb,"DragAcceptFiles("NPFMT", %u) old exStyle %08lx\n",hWnd,b,GetWindowLong(hWnd,GWL_EXSTYLE));
484
485  SetWindowLong(hWnd,GWL_EXSTYLE,GetWindowLong(hWnd,GWL_EXSTYLE) | b*(LONG)WS_EX_ACCEPTFILES); 
486 }
487
488
489 /*************************************************************************
490  *                              DragQueryFile           [SHELL.11]
491  */
492 UINT DragQueryFile(HDROP hDrop, WORD wFile, LPSTR lpszFile, WORD wLength)
493 {
494  /* hDrop is a global memory block allocated with GMEM_SHARE 
495     with DROPFILESTRUCT as a header and filenames following
496     it, zero length filename is in the end */       
497
498  LPDROPFILESTRUCT lpDropFileStruct;
499  LPSTR            lpCurrent;
500  WORD             i;
501
502  dprintf_reg(stddeb,"DragQueryFile("NPFMT", %i, %p, %u)\n",
503                            hDrop,wFile,lpszFile,wLength);
504
505  lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop); 
506  if(!lpDropFileStruct)
507     {
508        dprintf_reg(stddeb,"DragQueryFile: unable to lock handle!\n");
509        return 0;
510     } 
511  lpCurrent = (LPSTR) lpDropFileStruct + lpDropFileStruct->wSize;
512
513  i = 0;
514  while(i++ < wFile)
515     {
516        while(*lpCurrent++);  /* skip filename */
517        if(!*lpCurrent) 
518           return (wFile == 0xFFFF)? i : 0;  
519     }
520
521  i = strlen(lpCurrent); 
522  if(!lpszFile) return i+1;   /* needed buffer size */
523
524  i = ( wLength > i)? i : wLength-1;
525  strncpy(lpszFile,lpCurrent,i);
526  lpszFile[i]='\0';
527
528  GlobalUnlock(hDrop);
529  return i;
530 }
531
532
533 /*************************************************************************
534  *                              DragFinish              [SHELL.12]
535  */
536 void DragFinish(HDROP h)
537 {
538  GlobalFree((HGLOBAL)h);
539 }
540
541
542 /*************************************************************************
543  *                              DragQueryPoint          [SHELL.13]
544  */
545 BOOL DragQueryPoint(HDROP hDrop, POINT FAR *p)
546 {
547  LPDROPFILESTRUCT lpDropFileStruct;  
548  BOOL             bRet;
549
550  lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop);
551
552  memcpy(p,&lpDropFileStruct->ptMousePos,sizeof(POINT));
553  bRet = lpDropFileStruct->fInNonClientArea;
554
555  GlobalUnlock(hDrop);
556  return bRet; 
557 }
558
559
560 /*************************************************************************
561  *                              ShellExecute            [SHELL.20]
562  */
563 HINSTANCE ShellExecute(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, int iShowCmd)
564 {
565     char cmd[400];
566     char *p,*x;
567     long len;
568     char subclass[200];
569     /* OK. We are supposed to lookup the program associated with lpFile,
570      * then to execute it using that program. If lpFile is a program,
571      * we have to pass the parameters. If an instance is already running,
572      * we might have to send DDE commands.
573      */
574     dprintf_exec(stddeb, "ShellExecute("NPFMT",'%s','%s','%s','%s',%x)\n",
575                 hWnd, lpOperation ? lpOperation:"<null>", lpFile ? lpFile:"<null>",
576                 lpParameters ? lpParameters : "<null>", 
577                 lpDirectory ? lpDirectory : "<null>", iShowCmd);
578     if (lpFile==NULL) return 0; /* should not happen */
579     if (lpOperation==NULL) /* default is open */
580       lpOperation="open";
581     p=strrchr(lpFile,'.');
582     if (p!=NULL) {
583       x=p; /* the suffixes in the register database are lowercased */
584       while (*x) {*x=tolower(*x);x++;}
585     }
586     if (p==NULL || !strcmp(p,".exe")) {
587       p=".exe";
588       if (lpParameters) {
589         sprintf(cmd,"%s %s",lpFile,lpParameters);
590       } else {
591         strcpy(cmd,lpFile);
592       }
593     } else {
594       len=200;
595       if (RegQueryValue((HKEY)HKEY_CLASSES_ROOT,p,subclass,&len)==ERROR_SUCCESS) {
596         if (len>20)
597           fprintf(stddeb,"ShellExecute:subclass with len %ld? (%s), please report.\n",len,subclass);
598         subclass[len]='\0';
599         strcat(subclass,"\\shell\\");
600         strcat(subclass,lpOperation);
601         strcat(subclass,"\\command");
602         dprintf_exec(stddeb,"ShellExecute:looking for %s.\n",subclass);
603         len=400;
604         if (RegQueryValue((HKEY)HKEY_CLASSES_ROOT,subclass,cmd,&len)==ERROR_SUCCESS) {
605           char *t;
606           dprintf_exec(stddeb,"ShellExecute:...got %s\n",cmd);
607           cmd[len]='\0';
608           t=strstr(cmd,"%1");
609           if (t==NULL) {
610             strcat(cmd," ");
611             strcat(cmd,lpFile);
612           } else {
613             char *s;
614             s=xmalloc(len+strlen(lpFile)+10);
615             strncpy(s,cmd,t-cmd);
616             s[t-cmd]='\0';
617             strcat(s,lpFile);
618             strcat(s,t+2);
619             strcpy(cmd,s);
620             free(s);
621           }
622           /* does this use %x magic too? */
623           if (lpParameters) {
624             strcat(cmd," ");
625             strcat(cmd,lpParameters);
626           }
627         } else {
628           fprintf(stddeb,"ShellExecute: No %s\\shell\\%s\\command found for \"%s\" suffix.\n",subclass,lpOperation,p);
629           return (HINSTANCE)14; /* unknown type */
630         }
631       } else {
632         fprintf(stddeb,"ShellExecute: No operation found for \"%s\" suffix.\n",p);
633         return (HINSTANCE)14; /* file not found */
634       }
635     }
636     dprintf_exec(stddeb,"ShellExecute:starting %s\n",cmd);
637     return WinExec(cmd,iShowCmd);
638 }
639
640
641 /*************************************************************************
642  *                              FindExecutable          [SHELL.21]
643  */
644 HINSTANCE FindExecutable(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
645 {
646         fprintf(stdnimp, "FindExecutable : Empty Stub !!!\n");
647         return 0;
648 }
649
650 static char AppName[128], AppMisc[906];
651
652 /*************************************************************************
653  *                              AboutDlgProc            [SHELL.33]
654  */
655 LRESULT AboutDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
656 {
657   char Template[512], AppTitle[512];
658  
659   switch(msg) {
660    case WM_INITDIALOG:
661 #ifdef WINELIB32
662     SendDlgItemMessage(hWnd,stc1,STM_SETICON,lParam,0);
663 #else
664     SendDlgItemMessage(hWnd,stc1,STM_SETICON,LOWORD(lParam),0);
665 #endif
666     GetWindowText(hWnd, Template, 511);
667     sprintf(AppTitle, Template, AppName);
668     SetWindowText(hWnd, AppTitle);
669     SetWindowText(GetDlgItem(hWnd,100), AppMisc);
670     return 1;
671     
672    case WM_COMMAND:
673     switch (wParam) {
674      case IDOK:
675       EndDialog(hWnd, TRUE);
676       return TRUE;
677     }
678     break;
679   }
680   return FALSE;
681 }
682
683 /*************************************************************************
684  *                              ShellAbout              [SHELL.22]
685  */
686 INT ShellAbout(HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff, HICON hIcon)
687 {
688     HANDLE handle;
689     BOOL bRet;
690     DWORD WineProc,Win16Proc,Win32Proc;
691     static int initialized=0;
692
693     if (szApp) strncpy(AppName, szApp, sizeof(AppName));
694     else *AppName = 0;
695     AppName[sizeof(AppName)-1]=0;
696
697     if (szOtherStuff) strncpy(AppMisc, szOtherStuff, sizeof(AppMisc));
698     else *AppMisc = 0;
699     AppMisc[sizeof(AppMisc)-1]=0;
700
701     if (!hIcon) hIcon = LoadIcon(0,MAKEINTRESOURCE(OIC_WINEICON));
702     
703     if(!initialized)
704     {
705         WineProc=(DWORD)AboutDlgProc;
706         Win16Proc=(DWORD)GetWndProcEntry16("AboutDlgProc");
707         Win32Proc=(DWORD)RELAY32_GetEntryPoint("WINPROCS32","AboutDlgProc",0);
708         ALIAS_RegisterAlias(WineProc,Win16Proc,Win32Proc);
709         initialized=1;
710     }
711
712     handle = GLOBAL_CreateBlock( GMEM_FIXED,
713                                  sysres_DIALOG_SHELL_ABOUT_MSGBOX.bytes,
714                                  sysres_DIALOG_SHELL_ABOUT_MSGBOX.size,
715                                  GetCurrentPDB(), FALSE, FALSE,
716                                  TRUE, NULL );
717     if (!handle) return FALSE;
718     bRet = DialogBoxIndirectParam( WIN_GetWindowInstance( hWnd ),
719                                    handle, hWnd,
720                                    GetWndProcEntry16("AboutDlgProc"), 
721                                    (LONG)hIcon );
722     GLOBAL_FreeBlock( handle );
723     return bRet;
724 }
725
726 /*************************************************************************
727  *                              ExtractIcon             [SHELL.34]
728  */
729 HICON ExtractIcon(HINSTANCE hInst, LPCSTR lpszExeFileName, UINT nIconIndex)
730 {
731         HICON   hIcon = 0;
732         HINSTANCE hInst2 = hInst;
733         dprintf_reg(stddeb, "ExtractIcon("NPFMT", '%s', %d\n", 
734                         hInst, lpszExeFileName, nIconIndex);
735         return 0;
736         if (lpszExeFileName != NULL) {
737                 hInst2 = LoadModule(lpszExeFileName,(LPVOID)-1);
738         }
739         if (hInst2 != 0 && nIconIndex == (UINT)-1) {
740 #if 0
741                 count = GetRsrcCount(hInst2, NE_RSCTYPE_GROUP_ICON);
742                 dprintf_reg(stddeb, "ExtractIcon // '%s' has %d icons !\n", lpszExeFileName, count);
743                 return (HICON)count;
744 #endif
745         }
746         if (hInst2 != hInst && hInst2 != 0) {
747                 FreeLibrary(hInst2);
748         }
749         return hIcon;
750 }
751
752
753 /*************************************************************************
754  *                              ExtractAssociatedIcon   [SHELL.36]
755  */
756 HICON ExtractAssociatedIcon(HINSTANCE hInst,LPSTR lpIconPath, LPWORD lpiIcon)
757 {
758     dprintf_reg(stdnimp, "ExtractAssociatedIcon : Empty Stub !!!\n");
759     return 0;
760 }
761
762 /*************************************************************************
763  *              DoEnvironmentSubst      [SHELL.37]
764  */
765 DWORD DoEnvironmentSubst(LPSTR str,WORD len)
766 {
767     dprintf_reg(stdnimp, "DoEnvironmentSubst(%s,%x): Empyt Stub !!!\n",str,len);
768     return 0;
769 }
770
771 /*************************************************************************
772  *                              RegisterShellHook       [SHELL.102]
773  */
774 int RegisterShellHook(void *ptr) 
775 {
776         dprintf_reg(stdnimp, "RegisterShellHook : Empty Stub !!!\n");
777         return 0;
778 }
779
780
781 /*************************************************************************
782  *                              ShellHookProc           [SHELL.103]
783  */
784 int ShellHookProc(void) 
785 {
786         dprintf_reg(stdnimp, "ShellHookProc : Empty Stub !!!\n");
787         return 0;
788 }