xref: /reactos/dll/win32/inseng/inseng_main.c (revision bf833d29)
1 /*
2  *    INSENG Implementation
3  *
4  * Copyright 2006 Mike McCormack
5  * Copyright 2016 Michael M�ller
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #define COBJMACROS
23 
24 
25 #include <stdarg.h>
26 
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "ole2.h"
31 #include "rpcproxy.h"
32 #include "urlmon.h"
33 #ifdef __REACTOS__
34 #include <winreg.h>
35 #endif
36 #include "shlwapi.h"
37 #include "initguid.h"
38 #include "inseng.h"
39 
40 #include "inseng_private.h"
41 
42 #include "wine/debug.h"
43 
44 WINE_DEFAULT_DEBUG_CHANNEL(inseng);
45 
46 static HINSTANCE instance;
47 
48 enum thread_operation
49 {
50     OP_DOWNLOAD,
51     OP_INSTALL
52 };
53 
54 struct thread_info
55 {
56     DWORD operation;
57     DWORD jobflags;
58     IEnumCifComponents *enum_comp;
59 
60     DWORD download_size;
61     DWORD install_size;
62 
63     DWORD downloaded_kb;
64     ULONGLONG download_start;
65 };
66 
67 struct InstallEngine {
68     IInstallEngine2 IInstallEngine2_iface;
69     IInstallEngineTiming IInstallEngineTiming_iface;
70     LONG ref;
71 
72     IInstallEngineCallback *callback;
73     char *baseurl;
74     char *downloaddir;
75     ICifFile *icif;
76     DWORD status;
77 
78     /* used for the installation thread */
79     struct thread_info thread;
80 };
81 
82 struct downloadcb
83 {
84     IBindStatusCallback IBindStatusCallback_iface;
85     LONG ref;
86 
87     WCHAR *file_name;
88     WCHAR *cache_file;
89 
90     char *id;
91     char *display;
92 
93     DWORD dl_size;
94     DWORD dl_previous_kb;
95 
96     InstallEngine *engine;
97     HANDLE event_done;
98     HRESULT hr;
99 };
100 
impl_from_IInstallEngine2(IInstallEngine2 * iface)101 static inline InstallEngine *impl_from_IInstallEngine2(IInstallEngine2 *iface)
102 {
103     return CONTAINING_RECORD(iface, InstallEngine, IInstallEngine2_iface);
104 }
105 
impl_from_IBindStatusCallback(IBindStatusCallback * iface)106 static inline struct downloadcb *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
107 {
108     return CONTAINING_RECORD(iface, struct downloadcb, IBindStatusCallback_iface);
109 }
110 
impl_from_IInstallEngineTiming(IInstallEngineTiming * iface)111 static inline InstallEngine *impl_from_IInstallEngineTiming(IInstallEngineTiming *iface)
112 {
113     return CONTAINING_RECORD(iface, InstallEngine, IInstallEngineTiming_iface);
114 }
115 
downloadcb_QueryInterface(IBindStatusCallback * iface,REFIID riid,void ** ppv)116 static HRESULT WINAPI downloadcb_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
117 {
118     struct downloadcb *This = impl_from_IBindStatusCallback(iface);
119 
120     if (IsEqualGUID(&IID_IUnknown, riid))
121     {
122         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
123         *ppv = &This->IBindStatusCallback_iface;
124     }
125     else if (IsEqualGUID(&IID_IBindStatusCallback, riid))
126     {
127         TRACE("(%p)->(IID_IBindStatusCallback %p)\n", This, ppv);
128         *ppv = &This->IBindStatusCallback_iface;
129     }
130     else
131     {
132         FIXME("(%p)->(%s %p) not found\n", This, debugstr_guid(riid), ppv);
133         *ppv = NULL;
134         return E_NOINTERFACE;
135     }
136 
137     IUnknown_AddRef((IUnknown *)*ppv);
138     return S_OK;
139 }
140 
downloadcb_AddRef(IBindStatusCallback * iface)141 static ULONG WINAPI downloadcb_AddRef(IBindStatusCallback *iface)
142 {
143     struct downloadcb *This = impl_from_IBindStatusCallback(iface);
144     LONG ref = InterlockedIncrement(&This->ref);
145 
146     TRACE("(%p) ref = %d\n", This, ref);
147 
148     return ref;
149 }
150 
downloadcb_Release(IBindStatusCallback * iface)151 static ULONG WINAPI downloadcb_Release(IBindStatusCallback *iface)
152 {
153     struct downloadcb *This = impl_from_IBindStatusCallback(iface);
154     LONG ref = InterlockedDecrement(&This->ref);
155 
156     TRACE("(%p) ref = %d\n", This, ref);
157 
158     if (!ref)
159     {
160         heap_free(This->file_name);
161         heap_free(This->cache_file);
162 
163         IInstallEngine2_Release(&This->engine->IInstallEngine2_iface);
164         heap_free(This);
165     }
166 
167     return ref;
168 }
169 
downloadcb_OnStartBinding(IBindStatusCallback * iface,DWORD reserved,IBinding * pbind)170 static HRESULT WINAPI downloadcb_OnStartBinding(IBindStatusCallback *iface, DWORD reserved, IBinding *pbind)
171 {
172     struct downloadcb *This = impl_from_IBindStatusCallback(iface);
173 
174     TRACE("(%p)->(%u %p)\n", This, reserved, pbind);
175 
176     return S_OK;
177 }
178 
downloadcb_GetPriority(IBindStatusCallback * iface,LONG * priority)179 static HRESULT WINAPI downloadcb_GetPriority(IBindStatusCallback *iface, LONG *priority)
180 {
181     struct downloadcb *This = impl_from_IBindStatusCallback(iface);
182 
183     FIXME("(%p)->(%p): stub\n", This, priority);
184 
185     return E_NOTIMPL;
186 }
187 
downloadcb_OnLowResource(IBindStatusCallback * iface,DWORD reserved)188 static HRESULT WINAPI downloadcb_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
189 {
190     struct downloadcb *This = impl_from_IBindStatusCallback(iface);
191 
192     FIXME("(%p)->(%u): stub\n", This, reserved);
193 
194     return E_NOTIMPL;
195 }
196 
downloadcb_OnProgress(IBindStatusCallback * iface,ULONG progress,ULONG progress_max,ULONG status,const WCHAR * status_text)197 static HRESULT WINAPI downloadcb_OnProgress(IBindStatusCallback *iface, ULONG progress,
198         ULONG progress_max, ULONG status, const WCHAR *status_text)
199 {
200     struct downloadcb *This = impl_from_IBindStatusCallback(iface);
201     HRESULT hr = S_OK;
202 
203     TRACE("%p)->(%u %u %u %s)\n", This, progress, progress_max, status, debugstr_w(status_text));
204 
205     switch(status)
206     {
207         case BINDSTATUS_BEGINDOWNLOADDATA:
208             if (!This->engine->thread.download_start)
209                 This->engine->thread.download_start = GetTickCount64();
210             /* fall-through */
211         case BINDSTATUS_DOWNLOADINGDATA:
212         case BINDSTATUS_ENDDOWNLOADDATA:
213             This->engine->thread.downloaded_kb = This->dl_previous_kb + progress / 1024;
214             if (This->engine->callback)
215             {
216                 hr = IInstallEngineCallback_OnComponentProgress(This->engine->callback,
217                          This->id, INSTALLSTATUS_DOWNLOADING, This->display, NULL, progress / 1024, This->dl_size);
218             }
219             break;
220 
221         case BINDSTATUS_CACHEFILENAMEAVAILABLE:
222             This->cache_file = strdupW(status_text);
223             if (!This->cache_file)
224             {
225                 ERR("Failed to allocate memory for cache file\n");
226                 hr = E_OUTOFMEMORY;
227             }
228             break;
229 
230         case BINDSTATUS_CONNECTING:
231         case BINDSTATUS_SENDINGREQUEST:
232         case BINDSTATUS_MIMETYPEAVAILABLE:
233         case BINDSTATUS_FINDINGRESOURCE:
234             break;
235 
236         default:
237             FIXME("Unsupported status %u\n", status);
238     }
239 
240     return hr;
241 }
242 
downloadcb_OnStopBinding(IBindStatusCallback * iface,HRESULT hresult,LPCWSTR szError)243 static HRESULT WINAPI downloadcb_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
244 {
245     struct downloadcb *This = impl_from_IBindStatusCallback(iface);
246 
247     TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
248 
249     if (FAILED(hresult))
250     {
251         This->hr = hresult;
252         goto done;
253     }
254 
255     if (!This->cache_file)
256     {
257         This->hr = E_FAIL;
258         goto done;
259     }
260 
261     if (CopyFileW(This->cache_file, This->file_name, FALSE))
262         This->hr = S_OK;
263     else
264     {
265         ERR("CopyFile failed: %u\n", GetLastError());
266         This->hr = E_FAIL;
267     }
268 
269 done:
270     SetEvent(This->event_done);
271     return S_OK;
272 }
273 
downloadcb_GetBindInfo(IBindStatusCallback * iface,DWORD * grfBINDF,BINDINFO * pbindinfo)274 static HRESULT WINAPI downloadcb_GetBindInfo(IBindStatusCallback *iface,
275         DWORD *grfBINDF, BINDINFO *pbindinfo)
276 {
277     struct downloadcb *This = impl_from_IBindStatusCallback(iface);
278 
279     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
280 
281     *grfBINDF = BINDF_PULLDATA | BINDF_NEEDFILE;
282     return S_OK;
283 }
284 
downloadcb_OnDataAvailable(IBindStatusCallback * iface,DWORD grfBSCF,DWORD dwSize,FORMATETC * pformatetc,STGMEDIUM * pstgmed)285 static HRESULT WINAPI downloadcb_OnDataAvailable(IBindStatusCallback *iface,
286         DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
287 {
288     struct downloadcb *This = impl_from_IBindStatusCallback(iface);
289 
290     TRACE("(%p)->(%08x %u %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
291 
292     return S_OK;
293 }
294 
downloadcb_OnObjectAvailable(IBindStatusCallback * iface,REFIID riid,IUnknown * punk)295 static HRESULT WINAPI downloadcb_OnObjectAvailable(IBindStatusCallback *iface,
296         REFIID riid, IUnknown *punk)
297 {
298     struct downloadcb *This = impl_from_IBindStatusCallback(iface);
299 
300     FIXME("(%p)->(%s %p): stub\n", This, debugstr_guid(riid), punk);
301 
302     return E_NOTIMPL;
303 }
304 
305 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl =
306 {
307     downloadcb_QueryInterface,
308     downloadcb_AddRef,
309     downloadcb_Release,
310     downloadcb_OnStartBinding,
311     downloadcb_GetPriority,
312     downloadcb_OnLowResource,
313     downloadcb_OnProgress,
314     downloadcb_OnStopBinding,
315     downloadcb_GetBindInfo,
316     downloadcb_OnDataAvailable,
317     downloadcb_OnObjectAvailable
318 };
319 
downloadcb_create(InstallEngine * engine,HANDLE event,char * file_name,char * id,char * display,DWORD dl_size,struct downloadcb ** callback)320 static HRESULT downloadcb_create(InstallEngine *engine, HANDLE event, char *file_name, char *id,
321                                  char *display, DWORD dl_size, struct downloadcb **callback)
322 {
323     struct downloadcb *cb;
324 
325     cb = heap_alloc_zero(sizeof(*cb));
326     if (!cb) return E_OUTOFMEMORY;
327 
328     cb->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl;
329     cb->ref = 1;
330     cb->hr = E_FAIL;
331     cb->id = id;
332     cb->display = display;
333     cb->engine = engine;
334     cb->dl_size = dl_size;
335     cb->dl_previous_kb = engine->thread.downloaded_kb;
336     cb->event_done = event;
337     cb->file_name = strAtoW(file_name);
338     if (!cb->file_name)
339     {
340         heap_free(cb);
341         return E_OUTOFMEMORY;
342     }
343 
344     IInstallEngine2_AddRef(&engine->IInstallEngine2_iface);
345 
346     *callback = cb;
347     return S_OK;
348 }
349 
InstallEngine_QueryInterface(IInstallEngine2 * iface,REFIID riid,void ** ppv)350 static HRESULT WINAPI InstallEngine_QueryInterface(IInstallEngine2 *iface, REFIID riid, void **ppv)
351 {
352     InstallEngine *This = impl_from_IInstallEngine2(iface);
353 
354     if(IsEqualGUID(&IID_IUnknown, riid)) {
355         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
356         *ppv = &This->IInstallEngine2_iface;
357     }else if(IsEqualGUID(&IID_IInstallEngine, riid)) {
358         TRACE("(%p)->(IID_IInstallEngine %p)\n", This, ppv);
359         *ppv = &This->IInstallEngine2_iface;
360     }else if(IsEqualGUID(&IID_IInstallEngine2, riid)) {
361         TRACE("(%p)->(IID_IInstallEngine2 %p)\n", This, ppv);
362         *ppv = &This->IInstallEngine2_iface;
363     }else if(IsEqualGUID(&IID_IInstallEngineTiming, riid)) {
364         TRACE("(%p)->(IID_IInstallEngineTiming %p)\n", This, ppv);
365         *ppv = &This->IInstallEngineTiming_iface;
366     }else {
367         FIXME("(%p)->(%s %p) not found\n", This, debugstr_guid(riid), ppv);
368         *ppv = NULL;
369         return E_NOINTERFACE;
370     }
371 
372     IUnknown_AddRef((IUnknown *)*ppv);
373     return S_OK;
374 }
375 
InstallEngine_AddRef(IInstallEngine2 * iface)376 static ULONG WINAPI InstallEngine_AddRef(IInstallEngine2 *iface)
377 {
378     InstallEngine *This = impl_from_IInstallEngine2(iface);
379     LONG ref = InterlockedIncrement(&This->ref);
380 
381     TRACE("(%p) ref=%d\n", This, ref);
382 
383     return ref;
384 }
385 
InstallEngine_Release(IInstallEngine2 * iface)386 static ULONG WINAPI InstallEngine_Release(IInstallEngine2 *iface)
387 {
388     InstallEngine *This = impl_from_IInstallEngine2(iface);
389     LONG ref = InterlockedDecrement(&This->ref);
390 
391     TRACE("(%p) ref=%d\n", This, ref);
392 
393     if (!ref)
394     {
395         if (This->icif)
396             ICifFile_Release(This->icif);
397 
398         heap_free(This->baseurl);
399         heap_free(This->downloaddir);
400         heap_free(This);
401     }
402 
403     return ref;
404 }
405 
set_status(InstallEngine * This,DWORD status)406 static void set_status(InstallEngine *This, DWORD status)
407 {
408     This->status = status;
409 
410     if (This->callback)
411         IInstallEngineCallback_OnEngineStatusChange(This->callback, status, 0);
412 }
413 
calc_sizes(IEnumCifComponents * enum_comp,DWORD operation,DWORD * size_download,DWORD * size_install)414 static HRESULT calc_sizes(IEnumCifComponents *enum_comp, DWORD operation, DWORD *size_download, DWORD *size_install)
415 {
416     ICifComponent *comp;
417     DWORD download = 0;
418     DWORD install = 0;
419     HRESULT hr;
420 
421     /* FIXME: what about inactive dependencies and how does
422      * INSTALLOPTIONS_FORCEDEPENDENCIES play into this ?*/
423 
424     hr = IEnumCifComponents_Reset(enum_comp);
425     if (FAILED(hr)) return hr;
426 
427     while (SUCCEEDED(IEnumCifComponents_Next(enum_comp, &comp)))
428     {
429         if (ICifComponent_GetInstallQueueState(comp) != ActionInstall)
430             continue;
431 
432         /* FIXME: handle install options and find out the default options*/
433         if (operation == OP_DOWNLOAD && ICifComponent_IsComponentDownloaded(comp) == S_FALSE)
434             download = ICifComponent_GetDownloadSize(comp);
435         /*
436         if (operation == OP_INSTALL && ICifComponent_IsComponentInstalled(comp) == S_FALSE)
437             install = ICifComponent_GetInstalledSize(comp);
438         */
439     }
440 
441     *size_download = download;
442     *size_install = install;
443 
444     return S_OK;
445 }
446 
get_next_component(IEnumCifComponents * enum_comp,DWORD operation,ICifComponent ** ret_comp)447 static HRESULT get_next_component(IEnumCifComponents *enum_comp, DWORD operation, ICifComponent **ret_comp)
448 {
449     ICifComponent *comp;
450     HRESULT hr;
451 
452     hr = IEnumCifComponents_Reset(enum_comp);
453     if (FAILED(hr)) return hr;
454 
455     while (SUCCEEDED(IEnumCifComponents_Next(enum_comp, &comp)))
456     {
457         if (ICifComponent_GetInstallQueueState(comp) != ActionInstall)
458             continue;
459 
460         /* FIXME: handle install options and find out the default options*/
461         if (operation == OP_DOWNLOAD && ICifComponent_IsComponentDownloaded(comp) != S_FALSE)
462             continue;
463         if (operation == OP_INSTALL && ICifComponent_IsComponentInstalled(comp) != S_FALSE)
464             continue;
465 
466         *ret_comp = comp;
467         return S_OK;
468     }
469 
470     return S_FALSE;
471 }
472 
get_url(ICifComponent * comp,int index,char ** url,DWORD * flags)473 static HRESULT get_url(ICifComponent *comp, int index, char **url, DWORD *flags)
474 {
475     char *url_temp = NULL;
476     int size = MAX_PATH / 2;
477     HRESULT hr;
478 
479     /* FIXME: should we add an internal get function to prevent this ugly code ? */
480 
481     /* check if there is an url with such an index */
482     hr = ICifComponent_GetUrl(comp, index, NULL, 0, flags);
483     if (FAILED(hr))
484     {
485         *url = NULL;
486         *flags = 0;
487         return S_OK;
488     }
489 
490     do
491     {
492         size *= 2;
493         heap_free(url_temp);
494         url_temp = heap_alloc(size);
495         if (!url_temp) return E_OUTOFMEMORY;
496 
497         hr = ICifComponent_GetUrl(comp, index, url_temp, size, flags);
498         if (FAILED(hr))
499         {
500             heap_free(url_temp);
501             return hr;
502         }
503     }
504     while (strlen(url_temp) == size-1);
505 
506     *url = url_temp;
507     return S_OK;
508 }
509 
combine_url(char * baseurl,char * url)510 static char *combine_url(char *baseurl, char *url)
511 {
512     int len_base = strlen(baseurl);
513     int len_url = strlen(url);
514     char *combined;
515 
516     combined = heap_alloc(len_base + len_url + 2);
517     if (!combined) return NULL;
518 
519     strcpy(combined, baseurl);
520     if (len_base && combined[len_base-1] != '/')
521         strcat(combined, "/");
522     strcat(combined, url);
523 
524     return combined;
525 }
526 
generate_moniker(char * baseurl,char * url,DWORD flags,IMoniker ** moniker)527 static HRESULT generate_moniker(char *baseurl, char *url, DWORD flags, IMoniker **moniker)
528 {
529     WCHAR *urlW;
530     HRESULT hr;
531 
532     if (flags & URLF_RELATIVEURL)
533     {
534         char *combined;
535         if (!baseurl)
536             return E_FAIL;
537 
538         combined = combine_url(baseurl, url);
539         if (!combined) return E_OUTOFMEMORY;
540 
541         urlW = strAtoW(combined);
542         heap_free(combined);
543         if (!urlW) return E_OUTOFMEMORY;
544     }
545     else
546     {
547         urlW = strAtoW(url);
548         if (!urlW) return E_OUTOFMEMORY;
549     }
550 
551     hr = CreateURLMoniker(NULL, urlW, moniker);
552     heap_free(urlW);
553     return hr;
554 }
555 
merge_path(char * path1,char * path2)556 static char *merge_path(char *path1, char *path2)
557 {
558     int len = strlen(path1) + strlen(path2) + 2;
559     char *combined = heap_alloc(len);
560 
561     if (!combined) return NULL;
562     strcpy(combined, path1);
563     strcat(combined, "\\");
564     strcat(combined, path2);
565 
566     return combined;
567 }
568 
download_url(InstallEngine * This,char * id,char * display,char * url,DWORD flags,DWORD dl_size)569 static HRESULT download_url(InstallEngine *This, char *id, char *display, char *url, DWORD flags, DWORD dl_size)
570 {
571     struct downloadcb *callback = NULL;
572     char *filename    = NULL;
573     IUnknown *unk     = NULL;
574     IMoniker *mon     = NULL;
575     IBindCtx *bindctx = NULL;
576     HANDLE event      = NULL;
577     HRESULT hr;
578 
579     if (!This->downloaddir)
580     {
581         WARN("No download directory set\n");
582         return E_FAIL;
583     }
584 
585     hr = generate_moniker(This->baseurl, url, flags, &mon);
586     if (FAILED(hr))
587     {
588         FIXME("Failed to create moniker\n");
589         return hr;
590     }
591 
592     event = CreateEventW(NULL, TRUE, FALSE, NULL);
593     if (!event)
594     {
595         IMoniker_Release(mon);
596         return E_FAIL;
597     }
598 
599     filename = strrchr(url, '/');
600     if (!filename) filename = url;
601 
602     filename = merge_path(This->downloaddir, filename);
603     if (!filename)
604     {
605         hr = E_OUTOFMEMORY;
606         goto error;
607     }
608 
609     hr = downloadcb_create(This, event, filename, id, display, dl_size, &callback);
610     if (FAILED(hr)) goto error;
611 
612     hr = CreateAsyncBindCtx(0, &callback->IBindStatusCallback_iface, NULL, &bindctx);
613     if(FAILED(hr)) goto error;
614 
615     hr = IMoniker_BindToStorage(mon, bindctx, NULL, &IID_IUnknown, (void**)&unk);
616     if (FAILED(hr)) goto error;
617     if (unk) IUnknown_Release(unk);
618 
619     heap_free(filename);
620     IMoniker_Release(mon);
621     IBindCtx_Release(bindctx);
622 
623     WaitForSingleObject(event, INFINITE);
624     hr = callback->hr;
625 
626     CloseHandle(event);
627     IBindStatusCallback_Release(&callback->IBindStatusCallback_iface);
628     return hr;
629 
630 error:
631     if (mon) IMoniker_Release(mon);
632     if (event) CloseHandle(event);
633     if (callback) IBindStatusCallback_Release(&callback->IBindStatusCallback_iface);
634     if (bindctx) IBindCtx_Release(bindctx);
635     if (filename) heap_free(filename);
636     return hr;
637 }
638 
process_component_dependencies(InstallEngine * This,ICifComponent * comp)639 static HRESULT process_component_dependencies(InstallEngine *This, ICifComponent *comp)
640 {
641     char id[MAX_ID_LENGTH+1], type;
642     DWORD ver, build;
643     HRESULT hr;
644     int i;
645 
646     for (i = 0;; i++)
647     {
648         hr = ICifComponent_GetDependency(comp, i, id, sizeof(id), &type, &ver, &build);
649         if (SUCCEEDED(hr))
650             FIXME("Can't handle dependencies yet: %s\n", debugstr_a(id));
651         else
652             break;
653     }
654 
655     return S_OK;
656 }
657 
process_component(InstallEngine * This,ICifComponent * comp)658 static HRESULT process_component(InstallEngine *This, ICifComponent *comp)
659 {
660     DWORD size_dl, size_install, phase;
661     char display[MAX_DISPLAYNAME_LENGTH+1];
662     char id[MAX_ID_LENGTH+1];
663     HRESULT hr;
664     int i;
665 
666     hr = ICifComponent_GetID(comp, id, sizeof(id));
667     if (FAILED(hr)) return hr;
668 
669     TRACE("processing component %s\n", debugstr_a(id));
670 
671     hr = ICifComponent_GetDescription(comp, display, sizeof(display));
672     if (FAILED(hr)) return hr;
673 
674     size_dl      = (This->thread.operation == OP_DOWNLOAD) ? ICifComponent_GetDownloadSize(comp) : 0;
675     size_install = 0; /* (This->thread.operation == OP_INSTALL) ? ICifComponent_GetInstalledSize(comp) : 0; */
676 
677     if (This->callback)
678     {
679         IInstallEngineCallback_OnStartComponent(This->callback, id, size_dl, size_install, display);
680         IInstallEngineCallback_OnComponentProgress(This->callback, id, INSTALLSTATUS_INITIALIZING, display, NULL, 0, 0);
681         phase = INSTALLSTATUS_INITIALIZING;
682     }
683 
684     hr = process_component_dependencies(This, comp);
685     if (FAILED(hr)) return hr;
686 
687     if (This->thread.operation == OP_DOWNLOAD)
688     {
689         for (i = 0;; i++)
690         {
691             DWORD flags;
692             char *url;
693 
694             phase = INSTALLSTATUS_DOWNLOADING;
695 
696             hr = get_url(comp, i, &url, &flags);
697             if (FAILED(hr)) goto done;
698             if (!url) break;
699 
700             TRACE("processing url %s\n", debugstr_a(url));
701 
702             hr = download_url(This, id, display, url, flags, size_dl);
703             heap_free(url);
704             if (FAILED(hr))
705             {
706                 DWORD retry = 0;
707 
708                 if (This->callback)
709                     IInstallEngineCallback_OnEngineProblem(This->callback, ENGINEPROBLEM_DOWNLOADFAIL, &retry);
710                 if (!retry) goto done;
711 
712                 i--;
713                 continue;
714             }
715 
716             phase = INSTALLSTATUS_CHECKINGTRUST;
717             /* FIXME: check trust */
718             IInstallEngineCallback_OnComponentProgress(This->callback, id, INSTALLSTATUS_CHECKINGTRUST, display, NULL, 0, 0);
719         }
720 
721         component_set_downloaded(comp, TRUE);
722         phase = INSTALLSTATUS_DOWNLOADFINISHED;
723     }
724     else
725         FIXME("Installation not yet implemented\n");
726 
727 done:
728     IInstallEngineCallback_OnStopComponent(This->callback, id, hr, phase, display, 0);
729     return hr;
730 }
731 
thread_installation(LPVOID param)732 DWORD WINAPI thread_installation(LPVOID param)
733 {
734     InstallEngine *This = param;
735     ICifComponent *comp;
736     HRESULT hr;
737 
738     if (This->callback)
739         IInstallEngineCallback_OnStartInstall(This->callback, This->thread.download_size, This->thread.install_size);
740 
741     for (;;)
742     {
743         hr = get_next_component(This->thread.enum_comp, This->thread.operation, &comp);
744         if (FAILED(hr)) break;
745         if (hr == S_FALSE)
746         {
747             hr = S_OK;
748             break;
749         }
750 
751         hr = process_component(This, comp);
752         if (FAILED(hr)) break;
753     }
754 
755     if (This->callback)
756         IInstallEngineCallback_OnStopInstall(This->callback, hr, NULL, 0);
757 
758     IEnumCifComponents_Release(This->thread.enum_comp);
759     IInstallEngine2_Release(&This->IInstallEngine2_iface);
760 
761     set_status(This, ENGINESTATUS_READY);
762     return 0;
763 }
764 
start_installation(InstallEngine * This,DWORD operation,DWORD jobflags)765 static HRESULT start_installation(InstallEngine *This, DWORD operation, DWORD jobflags)
766 {
767     HANDLE thread;
768     HRESULT hr;
769 
770     This->thread.operation = operation;
771     This->thread.jobflags  = jobflags;
772     This->thread.downloaded_kb = 0;
773     This->thread.download_start = 0;
774 
775     /* Windows sends the OnStartInstall event from a different thread,
776      * but OnStartInstall already contains the required download and install size.
777      * The only way to signal an error from the thread is to send an OnStopComponent /
778      * OnStopInstall signal which can only occur after OnStartInstall. We need to
779      * precompute the sizes here to be able inform the application about errors while
780      * calculating the required sizes. */
781 
782     hr = ICifFile_EnumComponents(This->icif, &This->thread.enum_comp, 0, NULL);
783     if (FAILED(hr)) return hr;
784 
785     hr = calc_sizes(This->thread.enum_comp, operation, &This->thread.download_size, &This->thread.install_size);
786     if (FAILED(hr)) goto error;
787 
788     IInstallEngine2_AddRef(&This->IInstallEngine2_iface);
789 
790     thread = CreateThread(NULL, 0, thread_installation, This, 0, NULL);
791     if (!thread)
792     {
793         IInstallEngine2_Release(&This->IInstallEngine2_iface);
794         hr = E_FAIL;
795         goto error;
796     }
797 
798     CloseHandle(thread);
799     return S_OK;
800 
801 error:
802     IEnumCifComponents_Release(This->thread.enum_comp);
803     return hr;
804 }
805 
InstallEngine_GetEngineStatus(IInstallEngine2 * iface,DWORD * status)806 static HRESULT WINAPI InstallEngine_GetEngineStatus(IInstallEngine2 *iface, DWORD *status)
807 {
808     InstallEngine *This = impl_from_IInstallEngine2(iface);
809 
810     TRACE("(%p)->(%p)\n", This, status);
811 
812     if (!status)
813         return E_FAIL;
814 
815     *status = This->status;
816     return S_OK;
817 }
818 
InstallEngine_SetCifFile(IInstallEngine2 * iface,const char * cab_name,const char * cif_name)819 static HRESULT WINAPI InstallEngine_SetCifFile(IInstallEngine2 *iface, const char *cab_name, const char *cif_name)
820 {
821     InstallEngine *This = impl_from_IInstallEngine2(iface);
822 
823     FIXME("(%p)->(%s %s): stub\n", This, debugstr_a(cab_name), debugstr_a(cif_name));
824 
825     return E_NOTIMPL;
826 }
827 
InstallEngine_DownloadComponents(IInstallEngine2 * iface,DWORD flags)828 static HRESULT WINAPI InstallEngine_DownloadComponents(IInstallEngine2 *iface, DWORD flags)
829 {
830     InstallEngine *This = impl_from_IInstallEngine2(iface);
831 
832     TRACE("(%p)->(%x)\n", This, flags);
833 
834     /* The interface is not really threadsafe on windows, but we can at least prevent multiple installations */
835     if (InterlockedCompareExchange((LONG *)&This->status, ENGINESTATUS_INSTALLING, ENGINESTATUS_READY) != ENGINESTATUS_READY)
836         return E_FAIL;
837 
838     if (This->callback)
839         IInstallEngineCallback_OnEngineStatusChange(This->callback, ENGINESTATUS_INSTALLING, 0);
840 
841     return start_installation(This, OP_DOWNLOAD, flags);
842 }
843 
InstallEngine_InstallComponents(IInstallEngine2 * iface,DWORD flags)844 static HRESULT WINAPI InstallEngine_InstallComponents(IInstallEngine2 *iface, DWORD flags)
845 {
846     InstallEngine *This = impl_from_IInstallEngine2(iface);
847 
848     FIXME("(%p)->(%x): stub\n", This, flags);
849 
850     return E_NOTIMPL;
851 }
852 
InstallEngine_EnumInstallIDs(IInstallEngine2 * iface,UINT index,char ** id)853 static HRESULT WINAPI InstallEngine_EnumInstallIDs(IInstallEngine2 *iface, UINT index, char **id)
854 {
855     InstallEngine *This = impl_from_IInstallEngine2(iface);
856 
857     FIXME("(%p)->(%u %p): stub\n", This, index, id);
858 
859     return E_NOTIMPL;
860 }
861 
InstallEngine_EnumDownloadIDs(IInstallEngine2 * iface,UINT index,char ** id)862 static HRESULT WINAPI InstallEngine_EnumDownloadIDs(IInstallEngine2 *iface, UINT index, char **id)
863 {
864     InstallEngine *This = impl_from_IInstallEngine2(iface);
865     IEnumCifComponents *enum_components;
866     ICifComponent *comp;
867     HRESULT hr;
868 
869     TRACE("(%p)->(%u %p)\n", This, index, id);
870 
871     if (!This->icif || !id)
872         return E_FAIL;
873 
874     hr = ICifFile_EnumComponents(This->icif, &enum_components, 0, NULL);
875     if (FAILED(hr)) return hr;
876 
877     for (;;)
878     {
879         hr = IEnumCifComponents_Next(enum_components, &comp);
880         if (FAILED(hr)) goto done;
881 
882         if (ICifComponent_GetInstallQueueState(comp) != ActionInstall)
883             continue;
884 
885         if (ICifComponent_IsComponentDownloaded(comp) != S_FALSE)
886             continue;
887 
888         if (index == 0)
889         {
890             char *id_src = component_get_id(comp);
891             *id = CoTaskMemAlloc(strlen(id_src) + 1);
892 
893             if (*id)
894                 strcpy(*id, id_src);
895             else
896                 hr = E_OUTOFMEMORY;
897             goto done;
898         }
899 
900         index--;
901     }
902 
903 done:
904     IEnumCifComponents_Release(enum_components);
905     return hr;
906 }
907 
InstallEngine_IsComponentInstalled(IInstallEngine2 * iface,const char * id,DWORD * status)908 static HRESULT WINAPI InstallEngine_IsComponentInstalled(IInstallEngine2 *iface, const char *id, DWORD *status)
909 {
910     InstallEngine *This = impl_from_IInstallEngine2(iface);
911 
912     FIXME("(%p)->(%s %p): stub\n", This, debugstr_a(id), status);
913 
914     return E_NOTIMPL;
915 }
916 
InstallEngine_RegisterInstallEngineCallback(IInstallEngine2 * iface,IInstallEngineCallback * callback)917 static HRESULT WINAPI InstallEngine_RegisterInstallEngineCallback(IInstallEngine2 *iface, IInstallEngineCallback *callback)
918 {
919     InstallEngine *This = impl_from_IInstallEngine2(iface);
920 
921     TRACE("(%p)->(%p)\n", This, callback);
922 
923     This->callback = callback;
924     return S_OK;
925 }
926 
InstallEngine_UnregisterInstallEngineCallback(IInstallEngine2 * iface)927 static HRESULT WINAPI InstallEngine_UnregisterInstallEngineCallback(IInstallEngine2 *iface)
928 {
929     InstallEngine *This = impl_from_IInstallEngine2(iface);
930 
931     TRACE("(%p)\n", This);
932 
933     This->callback = NULL;
934     return S_OK;
935 }
936 
InstallEngine_SetAction(IInstallEngine2 * iface,const char * id,DWORD action,DWORD priority)937 static HRESULT WINAPI InstallEngine_SetAction(IInstallEngine2 *iface, const char *id, DWORD action, DWORD priority)
938 {
939     InstallEngine *This = impl_from_IInstallEngine2(iface);
940     ICifComponent *comp;
941     HRESULT hr;
942 
943     TRACE("(%p)->(%s %u %u)\n", This, debugstr_a(id), action, priority);
944 
945     if (!This->icif)
946         return E_FAIL; /* FIXME: check error code */
947 
948     hr = ICifFile_FindComponent(This->icif, id, &comp);
949     if (FAILED(hr)) return hr;
950 
951     hr = ICifComponent_SetInstallQueueState(comp, action);
952     if (FAILED(hr)) return hr;
953 
954     hr = ICifComponent_SetCurrentPriority(comp, priority);
955     return hr;
956 }
957 
InstallEngine_GetSizes(IInstallEngine2 * iface,const char * id,COMPONENT_SIZES * sizes)958 static HRESULT WINAPI InstallEngine_GetSizes(IInstallEngine2 *iface, const char *id, COMPONENT_SIZES *sizes)
959 {
960     InstallEngine *This = impl_from_IInstallEngine2(iface);
961 
962     FIXME("(%p)->(%s %p): stub\n", This, debugstr_a(id), sizes);
963 
964     return E_NOTIMPL;
965 }
966 
InstallEngine_LaunchExtraCommand(IInstallEngine2 * iface,const char * inf_name,const char * section)967 static HRESULT WINAPI InstallEngine_LaunchExtraCommand(IInstallEngine2 *iface, const char *inf_name, const char *section)
968 {
969     InstallEngine *This = impl_from_IInstallEngine2(iface);
970 
971     FIXME("(%p)->(%s %s): stub\n", This, debugstr_a(inf_name), debugstr_a(section));
972 
973     return E_NOTIMPL;
974 }
975 
InstallEngine_GetDisplayName(IInstallEngine2 * iface,const char * id,const char * name)976 static HRESULT WINAPI InstallEngine_GetDisplayName(IInstallEngine2 *iface, const char *id, const char *name)
977 {
978     InstallEngine *This = impl_from_IInstallEngine2(iface);
979 
980     FIXME("(%p)->(%s %s): stub\n", This, debugstr_a(id), debugstr_a(name));
981 
982     return E_NOTIMPL;
983 }
984 
InstallEngine_SetBaseUrl(IInstallEngine2 * iface,const char * base_name)985 static HRESULT WINAPI InstallEngine_SetBaseUrl(IInstallEngine2 *iface, const char *base_name)
986 {
987     InstallEngine *This = impl_from_IInstallEngine2(iface);
988 
989     TRACE("(%p)->(%s)\n", This, debugstr_a(base_name));
990 
991     if (This->baseurl)
992         heap_free(This->baseurl);
993 
994     This->baseurl = strdupA(base_name);
995     return This->baseurl ? S_OK : E_OUTOFMEMORY;
996 }
997 
InstallEngine_SetDownloadDir(IInstallEngine2 * iface,const char * download_dir)998 static HRESULT WINAPI InstallEngine_SetDownloadDir(IInstallEngine2 *iface, const char *download_dir)
999 {
1000     InstallEngine *This = impl_from_IInstallEngine2(iface);
1001 
1002     TRACE("(%p)->(%s)\n", This, debugstr_a(download_dir));
1003 
1004     if (This->downloaddir)
1005         heap_free(This->downloaddir);
1006 
1007     This->downloaddir = strdupA(download_dir);
1008     return This->downloaddir ? S_OK : E_OUTOFMEMORY;
1009 }
1010 
InstallEngine_SetInstallDrive(IInstallEngine2 * iface,char drive)1011 static HRESULT WINAPI InstallEngine_SetInstallDrive(IInstallEngine2 *iface, char drive)
1012 {
1013     InstallEngine *This = impl_from_IInstallEngine2(iface);
1014 
1015     FIXME("(%p)->(%c): stub\n", This, drive);
1016 
1017     return E_NOTIMPL;
1018 }
1019 
InstallEngine_SetInstallOptions(IInstallEngine2 * iface,DWORD flags)1020 static HRESULT WINAPI InstallEngine_SetInstallOptions(IInstallEngine2 *iface, DWORD flags)
1021 {
1022     InstallEngine *This = impl_from_IInstallEngine2(iface);
1023 
1024     FIXME("(%p)->(%x): stub\n", This, flags);
1025 
1026     return E_NOTIMPL;
1027 }
1028 
InstallEngine_SetHWND(IInstallEngine2 * iface,HWND hwnd)1029 static HRESULT WINAPI InstallEngine_SetHWND(IInstallEngine2 *iface, HWND hwnd)
1030 {
1031     InstallEngine *This = impl_from_IInstallEngine2(iface);
1032 
1033     FIXME("(%p)->(%p): stub\n", This, hwnd);
1034 
1035     return E_NOTIMPL;
1036 }
1037 
InstallEngine_SetIStream(IInstallEngine2 * iface,IStream * stream)1038 static HRESULT WINAPI InstallEngine_SetIStream(IInstallEngine2 *iface, IStream *stream)
1039 {
1040     InstallEngine *This = impl_from_IInstallEngine2(iface);
1041 
1042     FIXME("(%p)->(%p): stub\n", This, stream);
1043 
1044     return E_NOTIMPL;
1045 }
1046 
InstallEngine_Abort(IInstallEngine2 * iface,DWORD flags)1047 static HRESULT WINAPI InstallEngine_Abort(IInstallEngine2 *iface, DWORD flags)
1048 {
1049     InstallEngine *This = impl_from_IInstallEngine2(iface);
1050 
1051     FIXME("(%p)->(%x): stub\n", This, flags);
1052 
1053     return E_NOTIMPL;
1054 }
1055 
InstallEngine_Suspend(IInstallEngine2 * iface)1056 static HRESULT WINAPI InstallEngine_Suspend(IInstallEngine2 *iface)
1057 {
1058     InstallEngine *This = impl_from_IInstallEngine2(iface);
1059 
1060     FIXME("(%p): stub\n", This);
1061 
1062     return E_NOTIMPL;
1063 }
1064 
InstallEngine_Resume(IInstallEngine2 * iface)1065 static HRESULT WINAPI InstallEngine_Resume(IInstallEngine2 *iface)
1066 {
1067     InstallEngine *This = impl_from_IInstallEngine2(iface);
1068 
1069     FIXME("(%p): stub\n", This);
1070 
1071     return E_NOTIMPL;
1072 }
1073 
InstallEngine2_SetLocalCif(IInstallEngine2 * iface,const char * cif)1074 static HRESULT WINAPI InstallEngine2_SetLocalCif(IInstallEngine2 *iface, const char *cif)
1075 {
1076     InstallEngine *This = impl_from_IInstallEngine2(iface);
1077     HRESULT hr;
1078 
1079     TRACE("(%p)->(%s)\n", This, debugstr_a(cif));
1080 
1081     if (This->icif)
1082         ICifFile_Release(This->icif);
1083 
1084     set_status(This, ENGINESTATUS_LOADING);
1085 
1086     hr = GetICifFileFromFile(&This->icif, cif);
1087     if (SUCCEEDED(hr))
1088         set_status(This, ENGINESTATUS_READY);
1089     else
1090     {
1091         This->icif = NULL;
1092         set_status(This, ENGINESTATUS_NOTREADY);
1093     }
1094     return hr;
1095 }
1096 
InstallEngine2_GetICifFile(IInstallEngine2 * iface,ICifFile ** cif_file)1097 static HRESULT WINAPI InstallEngine2_GetICifFile(IInstallEngine2 *iface, ICifFile **cif_file)
1098 {
1099     InstallEngine *This = impl_from_IInstallEngine2(iface);
1100 
1101     TRACE("(%p)->(%p)\n", This, cif_file);
1102 
1103     if (!This->icif || !cif_file)
1104         return E_FAIL;
1105 
1106     ICifFile_AddRef(This->icif);
1107     *cif_file = This->icif;
1108     return S_OK;
1109 }
1110 
1111 static const IInstallEngine2Vtbl InstallEngine2Vtbl =
1112 {
1113     InstallEngine_QueryInterface,
1114     InstallEngine_AddRef,
1115     InstallEngine_Release,
1116     InstallEngine_GetEngineStatus,
1117     InstallEngine_SetCifFile,
1118     InstallEngine_DownloadComponents,
1119     InstallEngine_InstallComponents,
1120     InstallEngine_EnumInstallIDs,
1121     InstallEngine_EnumDownloadIDs,
1122     InstallEngine_IsComponentInstalled,
1123     InstallEngine_RegisterInstallEngineCallback,
1124     InstallEngine_UnregisterInstallEngineCallback,
1125     InstallEngine_SetAction,
1126     InstallEngine_GetSizes,
1127     InstallEngine_LaunchExtraCommand,
1128     InstallEngine_GetDisplayName,
1129     InstallEngine_SetBaseUrl,
1130     InstallEngine_SetDownloadDir,
1131     InstallEngine_SetInstallDrive,
1132     InstallEngine_SetInstallOptions,
1133     InstallEngine_SetHWND,
1134     InstallEngine_SetIStream,
1135     InstallEngine_Abort,
1136     InstallEngine_Suspend,
1137     InstallEngine_Resume,
1138     InstallEngine2_SetLocalCif,
1139     InstallEngine2_GetICifFile
1140 };
1141 
InstallEngineTiming_QueryInterface(IInstallEngineTiming * iface,REFIID riid,void ** ppv)1142 static HRESULT WINAPI InstallEngineTiming_QueryInterface(IInstallEngineTiming *iface, REFIID riid, void **ppv)
1143 {
1144     InstallEngine *This = impl_from_IInstallEngineTiming(iface);
1145     return IInstallEngine2_QueryInterface(&This->IInstallEngine2_iface, riid, ppv);
1146 }
1147 
InstallEngineTiming_AddRef(IInstallEngineTiming * iface)1148 static ULONG WINAPI InstallEngineTiming_AddRef(IInstallEngineTiming *iface)
1149 {
1150     InstallEngine *This = impl_from_IInstallEngineTiming(iface);
1151     return IInstallEngine2_AddRef(&This->IInstallEngine2_iface);
1152 }
1153 
InstallEngineTiming_Release(IInstallEngineTiming * iface)1154 static ULONG WINAPI InstallEngineTiming_Release(IInstallEngineTiming *iface)
1155 {
1156     InstallEngine *This = impl_from_IInstallEngineTiming(iface);
1157     return IInstallEngine2_Release(&This->IInstallEngine2_iface);
1158 }
1159 
InstallEngineTiming_GetRates(IInstallEngineTiming * iface,DWORD * download,DWORD * install)1160 static HRESULT WINAPI InstallEngineTiming_GetRates(IInstallEngineTiming *iface, DWORD *download, DWORD *install)
1161 {
1162     InstallEngine *This = impl_from_IInstallEngineTiming(iface);
1163 
1164     FIXME("(%p)->(%p, %p): stub\n", This, download, install);
1165 
1166     *download = 0;
1167     *install = 0;
1168 
1169     return S_OK;
1170 }
1171 
InstallEngineTiming_GetInstallProgress(IInstallEngineTiming * iface,INSTALLPROGRESS * progress)1172 static HRESULT WINAPI InstallEngineTiming_GetInstallProgress(IInstallEngineTiming *iface, INSTALLPROGRESS *progress)
1173 {
1174     InstallEngine *This = impl_from_IInstallEngineTiming(iface);
1175     ULONGLONG elapsed;
1176     static int once;
1177 
1178     if (!once)
1179         FIXME("(%p)->(%p): semi-stub\n", This, progress);
1180     else
1181         TRACE("(%p)->(%p): semi-stub\n", This, progress);
1182 
1183     progress->dwDownloadKBRemaining = max(This->thread.download_size, This->thread.downloaded_kb) - This->thread.downloaded_kb;
1184 
1185     elapsed = GetTickCount64() - This->thread.download_start;
1186     if (This->thread.download_start && This->thread.downloaded_kb && elapsed > 100)
1187         progress->dwDownloadSecsRemaining = (progress->dwDownloadKBRemaining * elapsed) / (This->thread.downloaded_kb * 1000);
1188     else
1189         progress->dwDownloadSecsRemaining = -1;
1190 
1191     progress->dwInstallKBRemaining = 0;
1192     progress->dwInstallSecsRemaining = -1;
1193 
1194     return S_OK;
1195 }
1196 
1197 static const IInstallEngineTimingVtbl InstallEngineTimingVtbl =
1198 {
1199     InstallEngineTiming_QueryInterface,
1200     InstallEngineTiming_AddRef,
1201     InstallEngineTiming_Release,
1202     InstallEngineTiming_GetRates,
1203     InstallEngineTiming_GetInstallProgress,
1204 };
1205 
ClassFactory_QueryInterface(IClassFactory * iface,REFIID riid,void ** ppv)1206 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
1207 {
1208     *ppv = NULL;
1209 
1210     if(IsEqualGUID(&IID_IUnknown, riid)) {
1211         TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
1212         *ppv = iface;
1213     }else if(IsEqualGUID(&IID_IClassFactory, riid)) {
1214         TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
1215         *ppv = iface;
1216     }
1217 
1218     if(*ppv) {
1219         IUnknown_AddRef((IUnknown*)*ppv);
1220         return S_OK;
1221     }
1222 
1223     FIXME("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppv);
1224     return E_NOINTERFACE;
1225 }
1226 
ClassFactory_AddRef(IClassFactory * iface)1227 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
1228 {
1229     return 2;
1230 }
1231 
ClassFactory_Release(IClassFactory * iface)1232 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
1233 {
1234     return 1;
1235 }
1236 
ClassFactory_LockServer(IClassFactory * iface,BOOL fLock)1237 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock)
1238 {
1239     return S_OK;
1240 }
1241 
InstallEngineCF_CreateInstance(IClassFactory * iface,IUnknown * outer,REFIID riid,void ** ppv)1242 static HRESULT WINAPI InstallEngineCF_CreateInstance(IClassFactory *iface, IUnknown *outer,
1243         REFIID riid, void **ppv)
1244 {
1245     InstallEngine *engine;
1246     HRESULT hres;
1247 
1248     TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
1249 
1250     engine = heap_alloc_zero(sizeof(*engine));
1251     if(!engine)
1252         return E_OUTOFMEMORY;
1253 
1254     engine->IInstallEngine2_iface.lpVtbl = &InstallEngine2Vtbl;
1255     engine->IInstallEngineTiming_iface.lpVtbl = &InstallEngineTimingVtbl;
1256     engine->ref = 1;
1257     engine->status = ENGINESTATUS_NOTREADY;
1258 
1259     hres = IInstallEngine2_QueryInterface(&engine->IInstallEngine2_iface, riid, ppv);
1260     IInstallEngine2_Release(&engine->IInstallEngine2_iface);
1261     return hres;
1262 }
1263 
1264 static const IClassFactoryVtbl InstallEngineCFVtbl = {
1265     ClassFactory_QueryInterface,
1266     ClassFactory_AddRef,
1267     ClassFactory_Release,
1268     InstallEngineCF_CreateInstance,
1269     ClassFactory_LockServer
1270 };
1271 
1272 static IClassFactory InstallEngineCF = { &InstallEngineCFVtbl };
1273 
DllMain(HINSTANCE hInstDLL,DWORD fdwReason,LPVOID lpv)1274 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
1275 {
1276     switch(fdwReason)
1277     {
1278     case DLL_WINE_PREATTACH:
1279         return FALSE;  /* prefer native version */
1280     case DLL_PROCESS_ATTACH:
1281         instance = hInstDLL;
1282         DisableThreadLibraryCalls(hInstDLL);
1283         break;
1284     }
1285     return TRUE;
1286 }
1287 
1288 /***********************************************************************
1289  *             DllGetClassObject (INSENG.@)
1290  */
DllGetClassObject(REFCLSID rclsid,REFIID iid,LPVOID * ppv)1291 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
1292 {
1293     if(IsEqualGUID(rclsid, &CLSID_InstallEngine)) {
1294         TRACE("(CLSID_InstallEngine %s %p)\n", debugstr_guid(iid), ppv);
1295         return IClassFactory_QueryInterface(&InstallEngineCF, iid, ppv);
1296     }
1297 
1298     FIXME("(%s %s %p)\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv);
1299     return CLASS_E_CLASSNOTAVAILABLE;
1300 }
1301 
1302 /***********************************************************************
1303  *              DllCanUnloadNow (INSENG.@)
1304  */
DllCanUnloadNow(void)1305 HRESULT WINAPI DllCanUnloadNow(void)
1306 {
1307     return S_FALSE;
1308 }
1309 
1310 /***********************************************************************
1311  *		DllRegisterServer (INSENG.@)
1312  */
DllRegisterServer(void)1313 HRESULT WINAPI DllRegisterServer(void)
1314 {
1315     return __wine_register_resources( instance );
1316 }
1317 
1318 /***********************************************************************
1319  *		DllUnregisterServer (INSENG.@)
1320  */
DllUnregisterServer(void)1321 HRESULT WINAPI DllUnregisterServer(void)
1322 {
1323     return __wine_unregister_resources( instance );
1324 }
1325 
CheckTrustEx(LPVOID a,LPVOID b,LPVOID c,LPVOID d,LPVOID e)1326 BOOL WINAPI CheckTrustEx( LPVOID a, LPVOID b, LPVOID c, LPVOID d, LPVOID e )
1327 {
1328     FIXME("%p %p %p %p %p\n", a, b, c, d, e );
1329     return TRUE;
1330 }
1331 
1332 /***********************************************************************
1333  *  DllInstall (INSENG.@)
1334  */
DllInstall(BOOL bInstall,LPCWSTR cmdline)1335 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
1336 {
1337     FIXME("(%s, %s): stub\n", bInstall ? "TRUE" : "FALSE", debugstr_w(cmdline));
1338     return S_OK;
1339 }
1340