Removed some unnecessary includes.
[wine] / dlls / setupapi / setupx_main.c
1 /*
2  *      SETUPX library
3  *
4  *      Copyright 1998,2000  Andreas Mohr
5  *
6  * FIXME: Rather non-functional functions for now.
7  *
8  * See:
9  * http://www.geocities.com/SiliconValley/Network/5317/drivers.html
10  * http://willemer.de/informatik/windows/inf_info.htm (German)
11  * http://www.microsoft.com/ddk/ddkdocs/win98ddk/devinst_12uw.htm
12  * DDK: setupx.h
13  * http://mmatrix.tripod.com/customsystemfolder/infsysntaxfull.html
14  * http://www.rdrop.com/~cary/html/inf_faq.html
15  *
16  * Stuff tested with:
17  * - rs405deu.exe (German Acroread 4.05 setup)
18  * - ie5setup.exe
19  * - Netmeeting
20  *
21  * FIXME:
22  * - check buflen
23  */
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include "winreg.h"
28 #include "wine/winuser16.h"
29 #include "setupx16.h"
30 #include "winerror.h"
31 #include "debugtools.h"
32
33 DEFAULT_DEBUG_CHANNEL(setupx);
34
35 /***********************************************************************
36  *              SURegOpenKey
37  */
38 DWORD WINAPI SURegOpenKey( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
39 {
40     FIXME("(%x,%s,%p), semi-stub.\n",hkey,debugstr_a(lpszSubKey),retkey);
41     return RegOpenKeyA( hkey, lpszSubKey, retkey );
42 }
43
44 /***********************************************************************
45  *              SURegQueryValueEx
46  */
47 DWORD WINAPI SURegQueryValueEx( HKEY hkey, LPSTR lpszValueName,
48                                 LPDWORD lpdwReserved, LPDWORD lpdwType,
49                                 LPBYTE lpbData, LPDWORD lpcbData )
50 {
51     FIXME("(%x,%s,%p,%p,%p,%ld), semi-stub.\n",hkey,debugstr_a(lpszValueName),
52           lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
53     return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
54                                lpbData, lpcbData );
55 }
56
57 /*
58  * hwnd = parent window
59  * hinst = instance of SETUPX.DLL
60  * lpszCmdLine = e.g. "DefaultInstall 132 C:\MYINSTALL\MYDEV.INF"
61  * Here "DefaultInstall" is the .inf file section to be installed (optional).
62  * 132 is the standard parameter, it seems.
63  * 133 means don't prompt user for reboot.
64  * 
65  * nCmdShow = nCmdShow of CreateProcess
66  * FIXME: is the return type correct ?
67  */
68 DWORD WINAPI InstallHinfSection16( HWND16 hwnd, HINSTANCE16 hinst, LPCSTR lpszCmdLine, INT16 nCmdShow)
69 {
70     FIXME("(%04x, %04x, %s, %d), stub.\n", hwnd, hinst, lpszCmdLine, nCmdShow);
71     return 0;
72 }
73
74 typedef struct
75 {
76     LPCSTR RegValName;
77     LPCSTR StdString; /* fallback string; sub dir of windows directory */
78 } LDID_DATA;
79
80 static const LDID_DATA LDID_Data[34] =
81 {
82     { /* 0 (LDID_NULL) -- not defined */
83         NULL,
84         NULL
85     },
86     { /* 1 (LDID_SRCPATH) = source of installation. hmm, what to do here ? */
87         "SourcePath", /* hmm, does SETUPX have to care about updating it ?? */
88         NULL
89     },
90     { /* 2 (LDID_SETUPTEMP) = setup temp dir */
91         "SetupTempDir",
92         NULL
93     },
94     { /* 3 (LDID_UNINSTALL) = uninstall backup dir */
95         "UninstallDir",
96         NULL
97     },
98     { /* 4 (LDID_BACKUP) = backup dir */
99         "BackupDir",
100         NULL
101     },
102     { /* 5 (LDID_SETUPSCRATCH) = setup scratch dir */
103         "SetupScratchDir",
104         NULL
105     },
106     { /* 6 -- not defined */
107         NULL,
108         NULL
109     },
110     { /* 7 -- not defined */
111         NULL,
112         NULL
113     },
114     { /* 8 -- not defined */
115         NULL,
116         NULL
117     },
118     { /* 9 -- not defined */
119         NULL,
120         NULL
121     },
122     { /* 10 (LDID_WIN) = windows dir */
123         "WinDir",
124         ""
125     },
126     { /* 11 (LDID_SYS) = system dir */
127         "SysDir",
128         NULL /* call GetSystemDirectory() instead */
129     },
130     { /* 12 (LDID_IOS) = IOSubSys dir */
131         NULL, /* FIXME: registry string ? */
132         "SYSTEM\\IOSUBSYS"
133     },
134     { /* 13 (LDID_CMD) = COMMAND dir */
135         NULL, /* FIXME: registry string ? */
136         "COMMAND"
137     },
138     { /* 14 (LDID_CPL) = control panel dir */
139         NULL,
140         ""
141     },
142     { /* 15 (LDID_PRINT) = windows printer dir */
143         NULL,
144         "SYSTEM" /* correct ?? */
145     },
146     { /* 16 (LDID_MAIL) = destination mail dir */
147         NULL,
148         ""
149     },
150     { /* 17 (LDID_INF) = INF dir */
151         "SetupScratchDir", /* correct ? */
152         "INF"
153     },
154     { /* 18 (LDID_HELP) = HELP dir */
155         NULL, /* ??? */
156         "HELP"
157     },
158     { /* 19 (LDID_WINADMIN) = Admin dir */
159         "WinAdminDir",
160         ""
161     },
162     { /* 20 (LDID_FONTS) = Fonts dir */
163         NULL, /* ??? */
164         "FONTS"
165     },
166     { /* 21 (LDID_VIEWERS) = Viewers */
167         NULL, /* ??? */
168         "SYSTEM\\VIEWERS"
169     },
170     { /* 22 (LDID_VMM32) = VMM32 dir */
171         NULL, /* ??? */
172         "SYSTEM\\VMM32"
173     },
174     { /* 23 (LDID_COLOR) = ICM dir */
175         "ICMPath",
176         "SYSTEM\\COLOR"
177     },
178     { /* 24 (LDID_APPS) = root of boot drive ? */
179         "AppsDir",
180         "C:\\"
181     },
182     { /* 25 (LDID_SHARED) = shared dir */
183         "SharedDir",
184         ""
185     },
186     { /* 26 (LDID_WINBOOT) = Windows boot dir */
187         "WinBootDir",
188         ""
189     },
190     { /* 27 (LDID_MACHINE) = machine specific files */
191         "MachineDir",
192         NULL
193     },
194     { /* 28 (LDID_HOST_WINBOOT) = Host Windows boot dir */
195         "HostWinBootDir",
196         NULL
197     },
198     { /* 29 -- not defined */
199         NULL,
200         NULL
201     },
202     { /* 30 (LDID_BOOT) = Root of boot drive */
203         "BootDir",
204         NULL
205     },
206     { /* 31 (LDID_BOOT_HOST) = Root of boot drive host */
207         "BootHost",
208         NULL
209     },
210     { /* 32 (LDID_OLD_WINBOOT) = subdir of root */
211         "OldWinBootDir",
212         NULL
213     },
214     { /* 33 (LDID_OLD_WIN) = old win dir */
215         "OldWinDir",
216         NULL
217     }
218     /* the rest (34-38) isn't too interesting, so I'll forget about it */
219 };
220
221 static void SETUPX_IsolateSubString(LPSTR *begin, LPSTR *end)
222 {
223     LPSTR p, q;
224
225     p = *begin;
226     q = *end;
227
228     while ((p < q) && ((*p == ' ') || (*p == '\t'))) p++;
229     while ((p < q) && (*p == '"')) p++;
230
231     while ((q-1 >= p) && ((*(q-1) == ' ') || (*(q-1) == '\t'))) q--;
232     while ((q-1 >= p) && (*(q-1) == '"')) q--;
233
234     *begin = p;
235     *end = q;
236 }
237
238 /*
239  * Example: HKLM,"Software\Microsoft\Windows\CurrentVersion","ProgramFilesDir",,"C:\"
240  */
241 static BOOL SETUPX_LookupRegistryString(LPSTR regstr, LPSTR buffer, DWORD buflen)
242 {
243     HANDLE heap = GetProcessHeap();
244     LPSTR items[5];
245     LPSTR p, q, next;
246     int len, n;
247     HKEY hkey, hsubkey;
248     DWORD dwType;
249
250     TRACE("retrieving '%s'\n", regstr);
251
252     p = regstr;
253
254     /* isolate root key, subkey, value, flag, defval */
255     for (n=0; n < 5; n++)
256     {
257         q = strchr(p, ',');
258         if (!q)
259         {
260             if (n == 4)
261                 q = p+strlen(p);
262             else
263                 return FALSE;
264         }
265         next = q+1;
266         if (q < regstr)
267             return FALSE;
268         SETUPX_IsolateSubString(&p, &q);
269         len = (int)q - (int)p;
270         items[n] = HeapAlloc(heap, 0, len+1);
271         strncpy(items[n], p, len);
272         items[n][len] = '\0';
273         p = next;
274     }
275     TRACE("got '%s','%s','%s','%s','%s'\n",
276                         items[0], items[1], items[2], items[3], items[4]);
277     
278     /* check root key */
279     if (!strcasecmp(items[0], "HKCR"))
280         hkey = HKEY_CLASSES_ROOT;
281     else
282     if (!strcasecmp(items[0], "HKCU"))
283         hkey = HKEY_CURRENT_USER;
284     else
285     if (!strcasecmp(items[0], "HKLM"))
286         hkey = HKEY_LOCAL_MACHINE;
287     else
288     if (!strcasecmp(items[0], "HKU"))
289         hkey = HKEY_USERS;
290     else
291     { /* HKR ? -> relative to key passed to GenInstallEx */
292         FIXME("unsupported regkey '%s'\n", items[0]);
293         goto regfailed;
294     }
295
296     if (RegOpenKeyA(hkey, items[1], &hsubkey) != ERROR_SUCCESS)
297         goto regfailed;
298
299     if (RegQueryValueExA(hsubkey, items[2], 0, &dwType, buffer, &buflen)
300                 != ERROR_SUCCESS)
301         goto regfailed;
302     goto done;
303
304 regfailed:
305     strcpy(buffer, items[4]); /* I don't care about buflen */
306 done:
307     for (n=0; n < 5; n++)
308         HeapFree(heap, 0, items[n]);
309     TRACE("return '%s'\n", buffer);
310     return TRUE;
311 }
312
313 /*
314  * Find the value of a custom LDID in a .inf file
315  * e.g. for 49301:
316  * 49300,49301=ProgramFilesDir,5
317  * -- profile section lookup -->
318  * [ProgramFilesDir]
319  * HKLM,"Software\Microsoft\Windows\CurrentVersion","ProgramFilesDir",,"%24%"
320  * -- GenFormStrWithoutPlaceHolders16 -->
321  * HKLM,"Software\Microsoft\Windows\CurrentVersion","ProgramFilesDir",,"C:\"
322  * -- registry lookup -->
323  * C:\Program Files (or C:\ if not found in registry)
324  * 
325  * FIXME:
326  * - maybe we ought to add a caching array for speed ? - I don't care :)
327  * - not sure whether the processing is correct - sometimes there are equal
328  *   LDIDs for both install and removal sections.
329  */
330 static BOOL SETUPX_TranslateCustomLDID(int ldid, LPSTR buffer, WORD buflen, INT16 hInf)
331 {
332     char ldidstr[6], sectionbuf[0xffff], entrybuf[0xffff], section[256];
333     LPCSTR filename;
334     LPSTR pSec, pEnt, pEqual, p, pEnd;
335     BOOL ret = FALSE;
336
337     sprintf(ldidstr, "%d", ldid);
338     filename = IP_GetFileName(hInf);
339     if (!GetPrivateProfileStringA(NULL, NULL, NULL,
340                                 sectionbuf, sizeof(sectionbuf), filename))
341     {
342         ERR("section buffer too small ?\n");
343         return FALSE;
344     }
345     for (pSec=sectionbuf; *pSec; pSec += strlen(pSec)+1)
346     {
347         if (!GetPrivateProfileSectionA(pSec,
348                                 entrybuf, sizeof(entrybuf), filename))
349         {
350             ERR("entry buffer too small ?\n");
351             return FALSE;
352         }
353         for (pEnt=entrybuf; *pEnt; pEnt += strlen(pEnt)+1)
354         {
355             if (strstr(pEnt, ldidstr))
356             {
357                 pEqual = strchr(pEnt, '=');
358                 if (!pEqual) /* crippled entry ?? */
359                     continue;
360
361                 /* make sure we found the LDID on left side of the equation */
362                 if (pEnt+strlen(ldidstr) <= pEqual)
363                 { /* found */
364
365                     /* but we don't want entries in the strings section */
366                     if (!strcasecmp(pSec, "Strings"))
367                         goto next_section;
368                     p = pEqual+1;
369                     while ((*p == ' ') || (*p == '\t')) p++;
370                     goto found;
371                 }
372             }
373         }
374 next_section:
375     }
376     return FALSE;
377 found:
378     TRACE("found entry '%s'\n", p);
379     /* strip off any flags we get
380      * FIXME: what are these flags used for ?? */
381     pEnd = strchr(p, ',');
382     strncpy(section, p, (int)pEnd - (int)p);
383     section[(int)pEnd - (int)p] = '\0';
384
385     /* get the location of the registry key from that section */
386     if (!GetPrivateProfileSectionA(section, entrybuf, sizeof(entrybuf), filename))
387     {
388         ERR("entrybuf too small ?\n");
389         return FALSE;
390     }
391     GenFormStrWithoutPlaceHolders16(sectionbuf, entrybuf, hInf);
392     ret = SETUPX_LookupRegistryString(sectionbuf, buffer, buflen);
393     TRACE("return '%s'\n", buffer);
394     return ret;
395 }
396
397 /*
398  * Translate a logical disk identifier (LDID) into its string representation
399  */
400 static BOOL SETUPX_TranslateLDID(int ldid, LPSTR buffer, WORD buflen, HINF16 hInf)
401 {
402     BOOL handled = FALSE;
403
404     if ((ldid >= LDID_SRCPATH) && (ldid <= LDID_OLD_WIN))
405     {
406         if (LDID_Data[ldid].RegValName)
407         {
408             HKEY hKey;
409
410             if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup", &hKey) == ERROR_SUCCESS)
411             {
412                 DWORD type, len = buflen;
413
414                 if ( (RegQueryValueExA(hKey, LDID_Data[ldid].RegValName,
415                         NULL, &type, buffer, &len) == ERROR_SUCCESS)
416                 &&   (type == REG_SZ) )
417                 {
418                     TRACE("found value '%s' for LDID %d\n", buffer, ldid);
419                     handled = TRUE;
420                 }
421
422                 RegCloseKey(hKey);
423             }
424         }
425     }
426     if (!handled)
427     {
428         switch(ldid)
429         {
430             case LDID_SRCPATH:
431                 FIXME("LDID_SRCPATH: what exactly do we have to do here ?\n");
432                 break;
433             case LDID_SYS:
434                 GetSystemDirectoryA(buffer, buflen);
435                 handled = TRUE;
436                 break;
437             case LDID_APPS:
438             case LDID_MACHINE:
439             case LDID_HOST_WINBOOT:
440             case LDID_BOOT:
441             case LDID_BOOT_HOST:
442                 strncpy(buffer, "C:\\", buflen);
443                 buffer[buflen-1] = '\0';
444                 handled = TRUE;
445                 break;
446             default:
447                 if ( (ldid >= LDID_NULL) && (ldid <= LDID_OLD_WIN)
448                   && (LDID_Data[ldid].StdString) )
449                 {
450                     UINT len = GetWindowsDirectoryA(buffer, buflen);
451                     if (len <= buflen-1)
452                     {
453                         buffer += len;
454                         buflen -= len;
455                         *buffer++ = '\\';
456                         buflen--;
457                         strncpy(buffer, LDID_Data[ldid].StdString, buflen);
458                         buffer[buflen-1] = '\0';
459                     }
460                     handled = TRUE;
461                 }
462                 break;
463         }
464     }
465
466     if (!handled)
467         handled = SETUPX_TranslateCustomLDID(ldid, buffer, buflen, hInf);
468
469     if (!handled)
470         FIXME("unimplemented LDID %d\n", ldid);
471
472     return handled;
473 }
474
475 /*
476  * GenFormStrWithoutPlaceHolders
477  */
478 void WINAPI GenFormStrWithoutPlaceHolders16( LPSTR szDst, LPCSTR szSrc, HINF16 hInf)
479 {
480     LPCSTR pSrc = szSrc, pSrcEnd = szSrc + strlen(szSrc);
481     LPSTR pDst = szDst, p, pPHBegin;
482     int count;
483     
484     FIXME("(%p, '%s', %04x), semi stub.\n", szDst, szSrc, hInf);
485     while (pSrc < pSrcEnd)
486     {
487         p = strchr(pSrc, '%');
488         if (p)
489         {
490             count = (int)p - (int)pSrc;
491             strncpy(pDst, pSrc, count);
492             pSrc += count;
493             pDst += count;
494             pPHBegin = p+1;
495             p = strchr(pPHBegin, '%');
496             if (p)
497             {
498                 char placeholder[80]; /* that really ought to be enough ;) */
499                 int ldid;
500                 BOOL done = TRUE;
501                 count = (int)p - (int)pPHBegin;
502                 strncpy(placeholder, pPHBegin, count);
503                 placeholder[count] = '\0';
504                 ldid = atoi(placeholder);
505                 if (ldid)
506                 {
507                     done = SETUPX_TranslateLDID(ldid, pDst, 256, hInf);
508                     if (done)
509                         pDst += strlen(pDst);
510                 }
511                 else
512                 { /* hmm, string placeholder. Need to look up
513                      in the [strings] section of the hInf */
514                     DWORD ret;
515                     char buf[256]; /* long enough ? */
516                     
517                     ret = GetPrivateProfileStringA("strings", placeholder, "",
518                                         buf, 256, IP_GetFileName(hInf));
519                     if (ret)
520                     {
521                         strcpy(pDst, buf);
522                         pDst += strlen(buf);
523                     }
524                     else
525                     {
526                         ERR("placeholder string '%s' not found !\n", placeholder);
527                         done = FALSE;
528                     }
529                 }
530                 if (!done)
531                 { /* copy raw placeholder string over */
532                     count = (int)p - (int)pPHBegin + 2;
533                     strncpy(pDst, pPHBegin-1, count);
534                     pDst += count;
535                     
536                 }
537                 pSrc = p+1;
538                 continue;
539             }
540         }
541
542         /* copy the remaining source string over */
543         strncpy(pDst, pSrc, (int)pSrcEnd - (int)pSrc + 1);
544         break;
545     }
546     TRACE("ret '%s'\n", szDst);
547 }
548
549 RETERR16 WINAPI CtlGetLddPath16(LOGDISKID16 ldid, LPSTR szPath)
550 {
551     FIXME("(%04x, %p), stub.\n", ldid, szPath);
552     strcpy(szPath, "FIXME_BogusLddPath");
553     return OK;
554 }
555
556 RETERR16 WINAPI CtlSetLddPath16(LOGDISKID16 ldid, LPSTR szPath)
557 {
558     FIXME("(%04x, '%s'), stub.\n", ldid, szPath);
559     return OK;
560 }
561
562 /*
563  * p2 is "\001" for Netmeeting.
564  */
565 RETERR16 WINAPI vcpOpen16(LPWORD p1, LPWORD p2)
566 {
567     FIXME("(%p, %p), stub.\n", p1, p2);
568     return OK;
569 }
570
571 RETERR16 WINAPI vcpClose16(WORD w1, WORD w2, WORD w3)
572 {
573     FIXME("(%04x, %04x %04x), stub.\n", w1, w2, w3);
574     return OK;
575 }
576
577 RETERR16 WINAPI GenInstall16(HINF16 hInfFile, LPCSTR szInstallSection, WORD wFlags)
578 {
579     FIXME("(%04x, '%s', %04x), stub. This doesn't install anything yet ! Use native SETUPX.DLL instead !!\n", hInfFile, szInstallSection, wFlags);
580     return OK;
581 }