Added CSIDL_MYVIDEO|MYPICTURES|MYMUSIC to _SHRegisterUserShellFolders.
[wine] / dlls / advpack / advpack.c
1 /*
2  * Advpack main
3  *
4  * Copyright 2004 Huw D M Davies
5  * Copyright 2005 Sami Aario
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "winreg.h"
28 #include "winver.h"
29 #include "winnls.h"
30 #include "setupapi.h"
31 #include "advpub.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(advpack);
36
37 typedef HRESULT (WINAPI *DLLREGISTER) (void);
38
39
40 /***********************************************************************
41  *           DllMain (ADVPACK.@)
42  */
43 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
44 {
45     TRACE("(%p, %ld, %p)\n",hinstDLL, fdwReason, lpvReserved);
46
47     if (fdwReason == DLL_PROCESS_ATTACH)
48         DisableThreadLibraryCalls(hinstDLL);
49
50     return TRUE;
51 }
52
53 /***********************************************************************
54  *              RunSetupCommand  (ADVPACK.@)
55  *
56  * Executes an install section in an INF file or a program.
57  *
58  * PARAMS
59  *   hWnd          [I] Handle to parent window, NULL for quiet mode
60  *   szCmdName     [I] Inf or EXE filename to execute
61  *   szInfSection  [I] Inf section to install, NULL for DefaultInstall
62  *   szDir         [I] Path to extracted files
63  *   szTitle       [I] Title of all dialogs
64  *   phEXE         [O] Handle of EXE to wait for
65  *   dwFlags       [I] Flags; see include/advpub.h
66  *   pvReserved    [I] Reserved
67  *
68  * RETURNS
69  *   S_OK                                 Everything OK
70  *   S_ASYNCHRONOUS                       OK, required to wait on phEXE
71  *   ERROR_SUCCESS_REBOOT_REQUIRED        Reboot required
72  *   E_INVALIDARG                         Invalid argument given
73  *   HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION)
74  *                                        Not supported on this Windows version
75  *   E_UNEXPECTED                         Unexpected error
76  *   HRESULT_FROM_WIN32(GetLastError())   Some other error
77  *
78  * BUGS
79  *   Unimplemented
80  */
81 HRESULT WINAPI RunSetupCommand( HWND hWnd, LPCSTR szCmdName,
82                                 LPCSTR szInfSection, LPCSTR szDir,
83                                 LPCSTR lpszTitle, HANDLE *phEXE,
84                                 DWORD dwFlags, LPVOID pvReserved )
85 {
86     FIXME("(%p, %s, %s, %s, %s, %p, 0x%08lx, %p): stub\n",
87            hWnd, debugstr_a(szCmdName), debugstr_a(szInfSection),
88            debugstr_a(szDir), debugstr_a(lpszTitle),
89            phEXE, dwFlags, pvReserved);
90     return E_UNEXPECTED;
91 }
92
93 /***********************************************************************
94  *              LaunchINFSection  (ADVPACK.@)
95  */
96 INT WINAPI LaunchINFSection( HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show )
97 {
98     FIXME("(%p %p %s %d): stub\n", hWnd, hInst, debugstr_a(cmdline), show );
99     return 0;
100 }
101
102 /***********************************************************************
103  *              LaunchINFSectionEx  (ADVPACK.@)
104  */
105 HRESULT WINAPI LaunchINFSectionEx( HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show )
106 {
107     FIXME("(%p %p %s %d): stub\n", hWnd, hInst, debugstr_a(cmdline), show );
108     return E_FAIL;
109 }
110
111 /* this structure very closely resembles parameters of RunSetupCommand() */
112 typedef struct
113 {
114     HWND hwnd;
115     LPCSTR title;
116     LPCSTR inf_name;
117     LPCSTR dir;
118     LPCSTR section_name;
119 } SETUPCOMMAND_PARAMS;
120
121 /***********************************************************************
122  *              DoInfInstall  (ADVPACK.@)
123  */
124 BOOL WINAPI DoInfInstall(const SETUPCOMMAND_PARAMS *setup)
125 {
126     BOOL ret;
127     HINF hinf;
128     void *callback_context;
129
130     TRACE("%p %s %s %s %s\n", setup->hwnd, debugstr_a(setup->title),
131           debugstr_a(setup->inf_name), debugstr_a(setup->dir),
132           debugstr_a(setup->section_name));
133
134     hinf = SetupOpenInfFileA(setup->inf_name, NULL, INF_STYLE_WIN4, NULL);
135     if (hinf == INVALID_HANDLE_VALUE) return FALSE;
136
137     callback_context = SetupInitDefaultQueueCallback(setup->hwnd);
138
139     ret = SetupInstallFromInfSectionA(NULL, hinf, setup->section_name, SPINST_ALL,
140                                       NULL, NULL, 0, SetupDefaultQueueCallbackA,
141                                       callback_context, NULL, NULL);
142     SetupTermDefaultQueueCallback(callback_context);
143     SetupCloseInfFile(hinf);
144
145     return ret;
146 }
147
148 /***********************************************************************
149  *              IsNTAdmin       (ADVPACK.@)
150  */
151 BOOL WINAPI IsNTAdmin( DWORD reserved, LPDWORD pReserved )
152 {
153     FIXME("(0x%08lx, %p): stub\n", reserved, pReserved);
154     return TRUE;
155 }
156
157 /***********************************************************************
158  *             NeedRebootInit  (ADVPACK.@)
159  */
160 DWORD WINAPI NeedRebootInit(VOID)
161 {
162     FIXME("(): stub\n");
163     return 0;
164 }
165
166 /***********************************************************************
167  *             NeedReboot      (ADVPACK.@)
168  */
169 BOOL WINAPI NeedReboot(DWORD dwRebootCheck)
170 {
171     FIXME("(0x%08lx): stub\n", dwRebootCheck);
172     return FALSE;
173 }
174
175 /***********************************************************************
176  *             GetVersionFromFile      (ADVPACK.@)
177  */
178 HRESULT WINAPI GetVersionFromFile( LPSTR Filename, LPDWORD MajorVer,
179                                    LPDWORD MinorVer, BOOL Version )
180 {
181     TRACE("(%s, %p, %p, %d)\n", Filename, MajorVer, MinorVer, Version);
182     return GetVersionFromFileEx(Filename, MajorVer, MinorVer, Version);
183 }
184
185 /* data for GetVersionFromFileEx */
186 typedef struct tagLANGANDCODEPAGE
187 {
188     WORD wLanguage;
189     WORD wCodePage;
190 } LANGANDCODEPAGE;
191
192 /***********************************************************************
193  *             GetVersionFromFileEx    (ADVPACK.@)
194  */
195 HRESULT WINAPI GetVersionFromFileEx( LPSTR lpszFilename, LPDWORD pdwMSVer,
196                                      LPDWORD pdwLSVer, BOOL bVersion )
197 {
198     VS_FIXEDFILEINFO *pFixedVersionInfo;
199     LANGANDCODEPAGE *pLangAndCodePage;
200     DWORD dwHandle, dwInfoSize;
201     CHAR szWinDir[MAX_PATH];
202     CHAR szFile[MAX_PATH];
203     LPVOID pVersionInfo = NULL;
204     BOOL bFileCopied = FALSE;
205     UINT uValueLen;
206
207     TRACE("(%s, %p, %p, %d)\n", lpszFilename, pdwMSVer, pdwLSVer, bVersion);
208
209     *pdwLSVer = 0;
210     *pdwMSVer = 0;
211
212     lstrcpynA(szFile, lpszFilename, MAX_PATH);
213
214     dwInfoSize = GetFileVersionInfoSizeA(szFile, &dwHandle);
215     if (!dwInfoSize)
216     {
217         /* check that the file exists */
218         if (GetFileAttributesA(szFile) == INVALID_FILE_ATTRIBUTES)
219             return S_OK;
220
221         /* file exists, but won't be found by GetFileVersionInfoSize,
222         * so copy it to the temp dir where it will be found.
223         */
224         GetWindowsDirectoryA(szWinDir, MAX_PATH);
225         GetTempFileNameA(szWinDir, NULL, 0, szFile);
226         CopyFileA(lpszFilename, szFile, FALSE);
227         bFileCopied = TRUE;
228
229         dwInfoSize = GetFileVersionInfoSizeA(szFile, &dwHandle);
230         if (!dwInfoSize)
231             goto done;
232     }
233
234     pVersionInfo = HeapAlloc(GetProcessHeap(), 0, dwInfoSize);
235     if (!pVersionInfo)
236         goto done;
237
238     if (!GetFileVersionInfoA(szFile, dwHandle, dwInfoSize, pVersionInfo))
239         goto done;
240
241     if (bVersion)
242     {
243         if (!VerQueryValueA(pVersionInfo, "\\",
244             (LPVOID *)&pFixedVersionInfo, &uValueLen))
245             goto done;
246
247         if (!uValueLen)
248             goto done;
249
250         *pdwMSVer = pFixedVersionInfo->dwFileVersionMS;
251         *pdwLSVer = pFixedVersionInfo->dwFileVersionLS;
252     }
253     else
254     {
255         if (!VerQueryValueA(pVersionInfo, "\\VarFileInfo\\Translation",
256              (LPVOID *)&pLangAndCodePage, &uValueLen))
257             goto done;
258
259         if (!uValueLen)
260             goto done;
261
262         *pdwMSVer = pLangAndCodePage->wLanguage;
263         *pdwLSVer = pLangAndCodePage->wCodePage;
264     }
265
266 done:
267     HeapFree(GetProcessHeap(), 0, pVersionInfo);
268
269     if (bFileCopied)
270         DeleteFileA(szFile);
271
272     return S_OK;
273 }
274
275 /***********************************************************************
276  *             RegisterOCX    (ADVPACK.@)
277  */
278 void WINAPI RegisterOCX( HWND hWnd, HINSTANCE hInst, LPCSTR cmdline, INT show )
279 {
280     WCHAR wszBuff[MAX_PATH];
281     WCHAR* pwcComma;
282     HMODULE hm;
283     DLLREGISTER pfnRegister;
284     HRESULT hr;
285
286     TRACE("(%s)\n", cmdline);
287
288     MultiByteToWideChar(CP_ACP, 0, cmdline, strlen(cmdline), wszBuff, MAX_PATH);
289     if ((pwcComma = strchrW( wszBuff, ',' ))) *pwcComma = 0;
290
291     TRACE("Parsed DLL name (%s)\n", debugstr_w(wszBuff));
292
293     hm = LoadLibraryExW(wszBuff, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
294     if (!hm)
295     {
296         ERR("Couldn't load DLL: %s\n", debugstr_w(wszBuff));
297         return;
298     }
299
300     pfnRegister = (DLLREGISTER)GetProcAddress(hm, "DllRegisterServer");
301     if (pfnRegister == NULL)
302     {
303         ERR("DllRegisterServer entry point not found\n");
304     }
305     else
306     {
307         hr = pfnRegister();
308         if (hr != S_OK)
309         {
310             ERR("DllRegisterServer entry point returned %08lx\n", hr);
311         }
312     }
313
314     TRACE("Successfully registered OCX\n");
315
316     FreeLibrary(hm);
317 }
318
319 static HRESULT DELNODE_recurse_dirtree(LPSTR fname, DWORD flags)
320 {
321     DWORD fattrs = GetFileAttributesA(fname);
322     HRESULT ret = E_FAIL;
323
324     if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
325     {
326         HANDLE hFindFile;
327         WIN32_FIND_DATAA w32fd;
328         BOOL done = TRUE;
329         int fname_len = lstrlenA(fname);
330
331         /* Generate a path with wildcard suitable for iterating */
332         if (CharPrevA(fname, fname + fname_len) != "\\")
333         {
334             lstrcpyA(fname + fname_len, "\\");
335             ++fname_len;
336         }
337         lstrcpyA(fname + fname_len, "*");
338
339         if ((hFindFile = FindFirstFileA(fname, &w32fd)) != INVALID_HANDLE_VALUE)
340         {
341             /* Iterate through the files in the directory */
342             for (done = FALSE; !done; done = !FindNextFileA(hFindFile, &w32fd))
343             {
344                 TRACE("%s\n", w32fd.cFileName);
345                 if (lstrcmpA(".", w32fd.cFileName) != 0 &&
346                     lstrcmpA("..", w32fd.cFileName) != 0)
347                 {
348                     lstrcpyA(fname + fname_len, w32fd.cFileName);
349                     if (DELNODE_recurse_dirtree(fname, flags) != S_OK)
350                     {
351                         break; /* Failure */
352                     }
353                 }
354             }
355             FindClose(hFindFile);
356         }
357
358         /* We're done with this directory, so restore the old path without wildcard */
359         *(fname + fname_len) = '\0';
360
361         if (done)
362         {
363             TRACE("%s: directory\n", fname);
364             if (SetFileAttributesA(fname, FILE_ATTRIBUTE_NORMAL) && RemoveDirectoryA(fname))
365             {
366                 ret = S_OK;
367             }
368         }
369     }
370     else
371     {
372         TRACE("%s: file\n", fname);
373         if (SetFileAttributesA(fname, FILE_ATTRIBUTE_NORMAL) && DeleteFileA(fname))
374         {
375             ret = S_OK;
376         }
377     }
378     
379     return ret;
380 }
381
382 /***********************************************************************
383  *              DelNode    (ADVPACK.@)
384  *
385  * Deletes a file or directory
386  *
387  * PARAMS
388  *   pszFileOrDirName   [I] Name of file or directory to delete
389  *   dwFlags            [I] Flags; see include/advpub.h
390  *
391  * RETURNS 
392  *   Success: S_OK
393  *   Failure: E_FAIL
394  *
395  * BUGS
396  *   - Ignores flags
397  *   - Native version apparently does a lot of checking to make sure
398  *     we're not trying to delete a system directory etc.
399  */
400 HRESULT WINAPI DelNode( LPCSTR pszFileOrDirName, DWORD dwFlags )
401 {
402     CHAR fname[MAX_PATH];
403     HRESULT ret = E_FAIL;
404
405     FIXME("(%s, 0x%08lx): flags ignored\n", debugstr_a(pszFileOrDirName), dwFlags);
406     if (pszFileOrDirName && *pszFileOrDirName)
407     {
408         lstrcpyA(fname, pszFileOrDirName);
409
410         /* TODO: Should check for system directory deletion etc. here */
411
412         ret = DELNODE_recurse_dirtree(fname, dwFlags);
413     }
414
415     return ret;
416 }
417
418 /***********************************************************************
419  *             DelNodeRunDLL32    (ADVPACK.@)
420  *
421  * BUGS
422  *   Unimplemented
423  */
424 HRESULT WINAPI DelNodeRunDLL32( HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show )
425 {
426     FIXME("(%s): stub\n", debugstr_a(cmdline));
427     return E_FAIL;
428 }
429
430 /***********************************************************************
431  *             ExecuteCab    (ADVPACK.@)
432  *
433  * BUGS
434  *   Unimplemented
435  */
436 HRESULT WINAPI ExecuteCab( HWND hwnd, PCABINFO pCab, LPVOID pReserved )
437 {
438     FIXME("(%p %p %p): stub\n", hwnd, pCab, pReserved);
439     return E_FAIL;
440 }
441
442 /***********************************************************************
443  *             ExtractFiles    (ADVPACK.@)
444  *
445  * BUGS
446  *   Unimplemented
447  */
448
449 HRESULT WINAPI ExtractFiles ( LPCSTR CabName, LPCSTR ExpandDir, DWORD Flags,
450                               LPCSTR FileList, LPVOID LReserved, DWORD Reserved)
451 {
452     FIXME("(%p %p 0x%08lx %p %p 0x%08lx): stub\n", CabName, ExpandDir, Flags, 
453           FileList, LReserved, Reserved);
454     return E_FAIL;
455 }
456
457 /***********************************************************************
458  *             TranslateInfString    (ADVPACK.@)
459  *
460  * Translates the value of a specified key in an inf file into the
461  * current locale by expanding string macros.
462  *
463  * PARAMS
464  *   pszInfFilename      [I] Filename of the inf file.
465  *   pszInstallSection   [I]
466  *   pszTranslateSection [I] Inf section where the key exists.
467  *   pszTranslateKey     [I] Key to translate.
468  *   pszBuffer           [O] Contains the translated string on exit.
469  *   dwBufferSize        [I] Size on input of pszBuffer.
470  *   pdwRequiredSize     [O] Length of the translated key.
471  *   pvReserved          [I] Reserved, must be NULL.
472  *
473  * RETURNS
474  *   Success: S_OK.
475  *   Failure: An hresult error code.
476  */
477 HRESULT WINAPI TranslateInfString(PCSTR pszInfFilename, PCSTR pszInstallSection,
478                 PCSTR pszTranslateSection, PCSTR pszTranslateKey, PSTR pszBuffer,
479                 DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved)
480 {
481     HINF hInf;
482
483     TRACE("(%s %s %s %s %p %ld %p %p)\n",
484           debugstr_a(pszInfFilename), debugstr_a(pszInstallSection),
485           debugstr_a(pszTranslateSection), debugstr_a(pszTranslateKey),
486           pszBuffer, dwBufferSize,pdwRequiredSize, pvReserved);
487
488     if (!pszInfFilename || !pszTranslateSection ||
489         !pszTranslateKey || !pdwRequiredSize)
490         return E_INVALIDARG;
491
492     hInf = SetupOpenInfFileA(pszInfFilename, NULL, INF_STYLE_WIN4, NULL);
493     if (hInf == INVALID_HANDLE_VALUE)
494         return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
495
496     if (!SetupGetLineTextA(NULL, hInf, pszTranslateSection, pszTranslateKey,
497                            pszBuffer, dwBufferSize, pdwRequiredSize))
498     {
499         if (dwBufferSize < *pdwRequiredSize)
500             return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
501
502         return SPAPI_E_LINE_NOT_FOUND;
503     }
504
505     return S_OK;
506 }