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