Hack around broken state management so InstallShield works.
[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 void WINAPI LaunchINFSection( HWND hWnd, HINSTANCE hInst, LPCSTR cmdline, INT show )
97 {
98     FIXME("(%p %p %s %d): stub\n", hWnd, hInst, debugstr_a(cmdline), show );
99 }
100
101 /***********************************************************************
102  *              LaunchINFSectionEx  (ADVPACK.@)
103  */
104 void WINAPI LaunchINFSectionEx( HWND hWnd, HINSTANCE hInst, LPCSTR cmdline, INT show )
105 {
106     FIXME("(%p %p %s %d): stub\n", hWnd, hInst, debugstr_a(cmdline), show );
107 }
108
109 /* this structure very closely resembles parameters of RunSetupCommand() */
110 typedef struct
111 {
112     HWND hwnd;
113     LPCSTR title;
114     LPCSTR inf_name;
115     LPCSTR dir;
116     LPCSTR section_name;
117 } SETUPCOMMAND_PARAMS;
118
119 /***********************************************************************
120  *              DoInfInstall  (ADVPACK.@)
121  */
122 BOOL WINAPI DoInfInstall(const SETUPCOMMAND_PARAMS *setup)
123 {
124     BOOL ret;
125     HINF hinf;
126     void *callback_context;
127
128     TRACE("%p %s %s %s %s\n", setup->hwnd, debugstr_a(setup->title),
129           debugstr_a(setup->inf_name), debugstr_a(setup->dir),
130           debugstr_a(setup->section_name));
131
132     hinf = SetupOpenInfFileA(setup->inf_name, NULL, INF_STYLE_WIN4, NULL);
133     if (hinf == INVALID_HANDLE_VALUE) return FALSE;
134
135     callback_context = SetupInitDefaultQueueCallback(setup->hwnd);
136
137     ret = SetupInstallFromInfSectionA(NULL, hinf, setup->section_name, SPINST_ALL,
138                                       NULL, NULL, 0, SetupDefaultQueueCallbackA,
139                                       callback_context, NULL, NULL);
140     SetupTermDefaultQueueCallback(callback_context);
141     SetupCloseInfFile(hinf);
142
143     return ret;
144 }
145
146 /***********************************************************************
147  *             NeedRebootInit  (ADVPACK.@)
148  */
149 DWORD WINAPI NeedRebootInit(VOID)
150 {
151     FIXME("(): stub\n");
152     return 0;
153 }
154
155 /***********************************************************************
156  *             NeedReboot      (ADVPACK.@)
157  */
158 BOOL WINAPI NeedReboot(DWORD dwRebootCheck)
159 {
160     FIXME("(0x%08lx): stub\n", dwRebootCheck);
161     return FALSE;
162 }
163
164 /***********************************************************************
165  *             GetVersionFromFile      (ADVPACK.@)
166  */
167 HRESULT WINAPI GetVersionFromFile( LPSTR Filename, LPDWORD MajorVer,
168                                    LPDWORD MinorVer, BOOL Version )
169 {
170     TRACE("(%s, %p, %p, %d)\n", Filename, MajorVer, MinorVer, Version);
171     return GetVersionFromFileEx(Filename, MajorVer, MinorVer, Version);
172 }
173
174 /***********************************************************************
175  *             GetVersionFromFileEx    (ADVPACK.@)
176  */
177 HRESULT WINAPI GetVersionFromFileEx( LPSTR lpszFilename, LPDWORD pdwMSVer,
178                                      LPDWORD pdwLSVer, BOOL bVersion )
179 {
180     DWORD hdl, retval;
181     LPVOID pVersionInfo;
182     BOOL boolret;
183     VS_FIXEDFILEINFO *pFixedVersionInfo;
184     UINT uiLength;
185     TRACE("(%s, %p, %p, %d)\n", lpszFilename, pdwMSVer, pdwLSVer, bVersion);
186
187     if (bVersion)
188     {
189         retval = GetFileVersionInfoSizeA(lpszFilename, &hdl);
190         if (retval == 0 || hdl != 0)
191             return E_FAIL;
192
193         pVersionInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, retval);
194         if (pVersionInfo == NULL)
195              return E_FAIL;
196         GetFileVersionInfoA( lpszFilename, 0, retval, pVersionInfo);
197
198         boolret = VerQueryValueA(pVersionInfo, "\\",
199                                  (LPVOID) &pFixedVersionInfo, &uiLength);
200
201         HeapFree(GetProcessHeap(), 0, pVersionInfo);
202
203         if (boolret)
204         {
205             *pdwMSVer = pFixedVersionInfo->dwFileVersionMS;
206             *pdwLSVer = pFixedVersionInfo->dwFileVersionLS;
207         }
208         else
209             return E_FAIL;
210     }
211     else
212     {
213         *pdwMSVer = GetUserDefaultUILanguage();
214         *pdwLSVer = GetACP();
215     }
216
217     return S_OK;
218 }
219
220 /***********************************************************************
221  *             RegisterOCX    (ADVPACK.@)
222  */
223 void WINAPI RegisterOCX( HWND hWnd, HINSTANCE hInst, LPCSTR cmdline, INT show )
224 {
225     WCHAR wszBuff[MAX_PATH];
226     WCHAR* pwcComma;
227     HMODULE hm;
228     DLLREGISTER pfnRegister;
229     HRESULT hr;
230
231     TRACE("(%s)\n", cmdline);
232
233     MultiByteToWideChar(CP_ACP, 0, cmdline, strlen(cmdline), wszBuff, MAX_PATH);
234     if ((pwcComma = strchrW( wszBuff, ',' ))) *pwcComma = 0;
235
236     TRACE("Parsed DLL name (%s)\n", debugstr_w(wszBuff));
237
238     hm = LoadLibraryExW(wszBuff, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
239     if (!hm)
240     {
241         ERR("Couldn't load DLL: %s\n", debugstr_w(wszBuff));
242         return;
243     }
244
245     pfnRegister = (DLLREGISTER)GetProcAddress(hm, "DllRegisterServer");
246     if (pfnRegister == NULL)
247     {
248         ERR("DllRegisterServer entry point not found\n");
249     }
250     else
251     {
252         hr = pfnRegister();
253         if (hr != S_OK)
254         {
255             ERR("DllRegisterServer entry point returned %08lx\n", hr);
256         }
257     }
258
259     TRACE("Successfully registered OCX\n");
260
261     FreeLibrary(hm);
262 }
263
264 static HRESULT DELNODE_recurse_dirtree(LPSTR fname, DWORD flags)
265 {
266     DWORD fattrs = GetFileAttributesA(fname);
267     HRESULT ret = E_FAIL;
268
269     if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
270     {
271         HANDLE hFindFile;
272         WIN32_FIND_DATAA w32fd;
273         BOOL done = TRUE;
274         int fname_len = lstrlenA(fname);
275
276         /* Generate a path with wildcard suitable for iterating */
277         if (CharPrevA(fname, fname + fname_len) != "\\")
278         {
279             lstrcpyA(fname + fname_len, "\\");
280             ++fname_len;
281         }
282         lstrcpyA(fname + fname_len, "*");
283
284         if ((hFindFile = FindFirstFileA(fname, &w32fd)) != INVALID_HANDLE_VALUE)
285         {
286             /* Iterate through the files in the directory */
287             for (done = FALSE; !done; done = !FindNextFileA(hFindFile, &w32fd))
288             {
289                 TRACE("%s\n", w32fd.cFileName);
290                 if (lstrcmpA(".", w32fd.cFileName) != 0 &&
291                     lstrcmpA("..", w32fd.cFileName) != 0)
292                 {
293                     lstrcpyA(fname + fname_len, w32fd.cFileName);
294                     if (DELNODE_recurse_dirtree(fname, flags) != S_OK)
295                     {
296                         break; /* Failure */
297                     }
298                 }
299             }
300             FindClose(hFindFile);
301         }
302
303         /* We're done with this directory, so restore the old path without wildcard */
304         *(fname + fname_len) = '\0';
305
306         if (done)
307         {
308             TRACE("%s: directory\n", fname);
309             if (SetFileAttributesA(fname, FILE_ATTRIBUTE_NORMAL) && RemoveDirectoryA(fname))
310             {
311                 ret = S_OK;
312             }
313         }
314     }
315     else
316     {
317         TRACE("%s: file\n", fname);
318         if (SetFileAttributesA(fname, FILE_ATTRIBUTE_NORMAL) && DeleteFileA(fname))
319         {
320             ret = S_OK;
321         }
322     }
323     
324     return ret;
325 }
326
327 /***********************************************************************
328  *              DelNode    (ADVPACK.@)
329  *
330  * Deletes a file or directory
331  *
332  * PARAMS
333  *   pszFileOrDirName   [I] Name of file or directory to delete
334  *   dwFlags            [I] Flags; see include/advpub.h
335  *
336  * RETURNS 
337  *   Success: S_OK
338  *   Failure: E_FAIL
339  *
340  * BUGS
341  *   - Ignores flags
342  *   - Native version apparently does a lot of checking to make sure
343  *     we're not trying to delete a system directory etc.
344  */
345 HRESULT WINAPI DelNode( LPCSTR pszFileOrDirName, DWORD dwFlags )
346 {
347     CHAR fname[MAX_PATH];
348     HRESULT ret = E_FAIL;
349
350     FIXME("(%s, 0x%08lx): flags ignored\n", debugstr_a(pszFileOrDirName), dwFlags);
351     if (pszFileOrDirName && *pszFileOrDirName)
352     {
353         lstrcpyA(fname, pszFileOrDirName);
354
355         /* TODO: Should check for system directory deletion etc. here */
356
357         ret = DELNODE_recurse_dirtree(fname, dwFlags);
358     }
359
360     return ret;
361 }
362
363 /***********************************************************************
364  *             DelNodeRunDLL32    (ADVPACK.@)
365  *
366  * BUGS
367  *   Unimplemented
368  */
369 void WINAPI DelNodeRunDLL32( HWND hWnd, HINSTANCE hInst, LPCSTR cmdline, INT show )
370 {
371     FIXME("(%s): stub\n", debugstr_a(cmdline));
372 }
373
374 /***********************************************************************
375  *             ExecuteCab    (ADVPACK.@)
376  *
377  * BUGS
378  *   Unimplemented
379  */
380 HRESULT WINAPI ExecuteCab( HWND hwnd, PCABINFO pCab, LPVOID pReserved )
381 {
382     FIXME("(%p %p %p): stub\n", hwnd, pCab, pReserved);
383     return E_FAIL;
384 }
385
386 /***********************************************************************
387  *             TranslateInfString    (ADVPACK.@)
388  *
389  * BUGS
390  *   Unimplemented
391  */
392 HRESULT WINAPI TranslateInfString(PCSTR pszInfFilename, PCSTR pszInstallSection,
393                 PCSTR pszTranslateSection, PCSTR pszTranslateKey, PSTR pszBuffer,
394                 DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved)
395 {
396     FIXME("(%s %s %s %s %p %ld %p %p): stub\n",
397         debugstr_a(pszInfFilename), debugstr_a(pszInstallSection),
398         debugstr_a(pszTranslateSection), debugstr_a(pszTranslateKey),
399         pszBuffer, dwBufferSize,pdwRequiredSize, pvReserved);
400     return E_FAIL;
401 }