winhttp, wininet: Load i2d_X509 from libcrypto.so.
[wine] / dlls / setupapi / virtcopy.c
1 /*
2  * SetupAPI virtual copy operations
3  *
4  * Copyright 2001 Andreas Mohr
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * FIXME: we now rely on builtin setupapi.dll for dialog resources.
21  *        This is bad ! We ought to have 16bit resource handling working.
22  */
23
24 #include <stdarg.h>
25 #include <string.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "wownt32.h"
31 #include "winnls.h"
32 #include "setupapi.h"
33 #include "setupx16.h"
34 #include "setupapi_private.h"
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
38
39 static FARPROC16 VCP_Proc = NULL;
40 static LPARAM VCP_MsgRef = 0;
41
42 static BOOL VCP_opened = FALSE;
43
44 static VCPSTATUS vcp_status;
45
46 static WORD VCP_Callback( LPVOID obj, UINT16 msg, WPARAM16 wParam, LPARAM lParam, LPARAM lParamRef )
47 {
48     WORD args[8];
49     DWORD ret = OK;
50     if (VCP_Proc)
51     {
52         args[7] = HIWORD(obj);
53         args[6] = LOWORD(obj);
54         args[5] = msg;
55         args[4] = wParam;
56         args[3] = HIWORD(lParam);
57         args[2] = LOWORD(lParam);
58         args[1] = HIWORD(lParamRef);
59         args[0] = LOWORD(lParamRef);
60         WOWCallback16Ex( (DWORD)VCP_Proc, WCB16_PASCAL, sizeof(args), args, &ret );
61     }
62     return (WORD)ret;
63 }
64
65 /****************************** VHSTR management ******************************/
66
67 /*
68  * This is a totally braindead implementation for now;
69  * I don't care about speed at all ! Size and implementation time
70  * is much more important IMHO. I could have created some sophisticated
71  * tree structure, but... what the hell ! :-)
72  */
73 typedef struct {
74     DWORD refcount;
75     LPCSTR pStr;
76 } VHSTR_STRUCT;
77
78 static VHSTR_STRUCT **vhstrlist = NULL;
79 static VHSTR vhstr_alloc = 0;
80
81 #define VALID_VHSTR(x)          ((x < vhstr_alloc) && (vhstrlist[x]) && (vhstrlist[x]->refcount))
82
83 /***********************************************************************
84  *              vsmStringAdd (SETUPX.207)
85  */
86 VHSTR WINAPI vsmStringAdd16(LPCSTR lpszName)
87 {
88     VHSTR n;
89     VHSTR index = 0xffff;
90     HANDLE heap;
91     LPSTR str;
92
93     TRACE("add string '%s'\n", lpszName);
94     /* search whether string already inserted */
95     TRACE("searching for existing string...\n");
96     for (n = 0; n < vhstr_alloc; n++)
97     {
98         if ((vhstrlist[n]) && (vhstrlist[n]->refcount))
99         {
100                 TRACE("checking item: %d\n", n);
101             if (!strcmp(vhstrlist[n]->pStr, lpszName))
102             {
103                 TRACE("found\n");
104                 vhstrlist[n]->refcount++;
105                 return n;
106             }
107         }
108     }
109
110     /* hmm, not found yet, let's insert it */
111     TRACE("inserting item\n");
112     for (n = 0; n < vhstr_alloc; n++)
113     {
114         if ((!(vhstrlist[n])) || (!(vhstrlist[n]->refcount)))
115         {
116             index = n;
117             break;
118         }
119     }
120     heap = GetProcessHeap();
121     if (n == vhstr_alloc) /* hmm, no free index found yet */
122     {
123         index = vhstr_alloc;
124         vhstr_alloc += 20;
125
126         if (vhstrlist)
127             vhstrlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, vhstrlist,
128                                         sizeof(VHSTR_STRUCT *) * vhstr_alloc);
129         else
130             vhstrlist = HeapAlloc(heap, HEAP_ZERO_MEMORY,
131                                         sizeof(VHSTR_STRUCT *) * vhstr_alloc);
132     }
133     if (index == 0xffff)
134         return 0xffff; /* failure */
135     if (!vhstrlist[index])
136         vhstrlist[index] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VHSTR_STRUCT));
137     vhstrlist[index]->refcount = 1;
138     str = HeapAlloc(heap, 0, strlen(lpszName)+1);
139     strcpy(str, lpszName);
140     vhstrlist[index]->pStr = str;
141     return index;
142 }
143
144 /***********************************************************************
145  *              vsmStringDelete (SETUPX.206)
146  */
147 INT16 WINAPI vsmStringDelete16(VHSTR vhstr)
148 {
149     if (VALID_VHSTR(vhstr))
150     {
151         vhstrlist[vhstr]->refcount--;
152         if (!vhstrlist[vhstr]->refcount)
153         {
154             HeapFree(GetProcessHeap(), 0, (LPSTR)vhstrlist[vhstr]->pStr);
155             vhstrlist[vhstr]->pStr = NULL;
156         }
157         return VCPN_OK;
158     }
159
160     /* string not found */
161     return VCPN_FAIL;
162 }
163
164 /*
165  * vsmStringFind() - not exported from a standard SETUPX.DLL, it seems
166  */
167 VHSTR WINAPI vsmStringFind16(LPCSTR lpszName)
168 {
169     WORD n;
170     for (n = 0; n < vhstr_alloc; n++)
171         if ((vhstrlist[n]) && (vhstrlist[n]->refcount) && (!strcmp(vhstrlist[n]->pStr, lpszName)))
172             return n;
173     return 0xffff;
174 }
175
176 /***********************************************************************
177  *              vsmGetStringName (SETUPX.205)
178  *
179  * Pretty correct, I guess
180  */
181 INT16 WINAPI vsmGetStringName16(VHSTR vhstr, LPSTR lpszBuffer, int cbBuffer)
182 {
183     if (VALID_VHSTR(vhstr))
184     {
185         int len = strlen(vhstrlist[vhstr]->pStr)+1;
186         if (cbBuffer >= len)
187         {
188             if (lpszBuffer)
189                 strcpy(lpszBuffer, vhstrlist[vhstr]->pStr);
190             return len;
191         }
192     }
193     return VCPN_FAIL;
194 }
195
196 /***********************************************************************
197  *              vsmStringCompare (not exported from a standard SETUPX.DLL, it seems)
198  */
199 INT16 WINAPI vsmStringCompare16(VHSTR vhstrA, VHSTR vhstrB)
200 {
201     if ((!VALID_VHSTR(vhstrA)) || (!VALID_VHSTR(vhstrB)))
202         return VCPN_FAIL; /* correct ? */
203     return strcmp(vhstrlist[vhstrA]->pStr, vhstrlist[vhstrB]->pStr);
204 }
205
206 /***********************************************************************
207  *              vsmGetStringRawName (SETUPX.208)
208  */
209 LPCSTR WINAPI vsmGetStringRawName16(VHSTR vhstr)
210 {
211     return (VALID_VHSTR(vhstr)) ? vhstrlist[vhstr]->pStr : NULL;
212 }
213
214
215 /***************************** VIRTNODE management ****************************/
216 static LPVIRTNODE *pvnlist = NULL;
217 static DWORD vn_num = 0;
218 static DWORD vn_last = 0;
219
220 static RETERR16 VCP_VirtnodeCreate(const VCPFILESPEC *vfsSrc, const VCPFILESPEC *vfsDst,
221                                    WORD fl, LPARAM lParam, LPEXPANDVTBL lpExpandVtbl)
222 {
223     HANDLE heap;
224     LPVIRTNODE lpvn;
225     RETERR16 cbres;
226
227     while (vn_last < vn_num)
228     {
229         if (pvnlist[vn_last] == NULL)
230             break;
231         vn_last++;
232     }
233     heap = GetProcessHeap();
234     if (vn_last == vn_num)
235     {
236         vn_num += 20;
237         if (pvnlist)
238             pvnlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, pvnlist,
239                                 sizeof(LPVIRTNODE *) * vn_num);
240         else
241             pvnlist = HeapAlloc(heap, HEAP_ZERO_MEMORY, 
242                                 sizeof(LPVIRTNODE *) * vn_num);
243     }
244     pvnlist[vn_last] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VIRTNODE));
245     lpvn = pvnlist[vn_last];
246     vn_last++;
247
248     lpvn->cbSize = sizeof(VIRTNODE);
249
250     if (vfsSrc)
251         lpvn->vfsSrc = *vfsSrc;
252
253     if (vfsDst)
254         lpvn->vfsDst = *vfsDst;
255
256     lpvn->fl = fl;
257     lpvn->lParam = lParam;
258     lpvn->lpExpandVtbl = lpExpandVtbl;
259
260     lpvn->vhstrDstFinalName = 0xffff; /* FIXME: what is this ? */
261
262     cbres = VCP_Callback(lpvn, VCPM_NODECREATE, 0, 0, VCP_MsgRef);
263     lpvn->fl |= VFNL_CREATED;
264     cbres = VCP_Callback(lpvn, VCPM_NODEACCEPT, 0, 0, VCP_MsgRef);
265
266     return OK;
267 }
268
269 #if 0
270 static BOOL VCP_VirtnodeDelete(LPVIRTNODE lpvnDel)
271 {
272     DWORD n;
273     RETERR16 cbres;
274
275     for (n = 0; n < vn_last; n++)
276     {
277         if (pvnlist[n] == lpvnDel)
278         {
279             cbres = VCP_Callback(lpvnDel, VCPM_NODEDESTROY, 0, 0, VCP_MsgRef);
280             HeapFree(GetProcessHeap(), 0, lpvnDel);
281             pvnlist[n] = NULL;
282             return TRUE;
283         }
284     }
285     return FALSE;
286 }
287 #endif
288
289 /***********************************************************************
290  *              VcpOpen (SETUPX.200)
291  *
292  * Sets up a virtual copy operation.
293  * This means that functions such as GenInstall()
294  * create a VIRTNODE struct for every file to be touched in a .INF file
295  * instead of actually touching the file.
296  * The actual copy/move/rename gets started when VcpClose or
297  * VcpFlush is called; several different callbacks are made
298  * (copy, rename, open, close, version conflicts, ...) on every file copied.
299  */
300 RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef)
301 {
302     TRACE("(%p, %08lx)\n", vifproc, lparamMsgRef);
303     if (VCP_opened)
304         return ERR_VCP_BUSY;
305
306     VCP_Proc = (FARPROC16)vifproc;
307     VCP_MsgRef = lparamMsgRef;
308
309     VCP_opened = TRUE;
310     return OK;
311 }
312
313 /***********************************************************************
314  *              VcpQueueCopy            [SETUPX.13]
315  *
316  * lpExpandVtbl seems to be deprecated.
317  * fl are the CNFL_xxx and VNFL_xxx flags.
318  * lParam are the VNLP_xxx flags.
319  */
320 RETERR16 WINAPI VcpQueueCopy16(
321         LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
322         LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
323         LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
324         LPEXPANDVTBL lpExpandVtbl,
325         WORD fl, LPARAM lParam
326 )
327 {
328     VCPFILESPEC vfsSrc, vfsDst;
329
330     if (!VCP_opened)
331         return ERR_VCP_NOTOPEN;
332
333     TRACE("srcdir: %s, srcfile: %s, dstdir: %s, dstfile: %s\n",
334       lpszSrcDir, lpszSrcFileName, lpszDstDir, lpszDstFileName);
335
336     TRACE("ldidSrc == %d, ldidDst == %d\n", ldidSrc, ldidDst);
337
338     vfsSrc.ldid = ldidSrc;
339     vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
340     vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
341
342     vfsDst.ldid = ldidDst;
343     vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
344     vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
345
346     return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, fl, lParam,
347                     lpExpandVtbl);
348 }
349
350 /***********************************************************************
351  *              VcpQueueDelete          [SETUPX.17]
352  *
353  * Is lParamRef the same as lParam in VcpQueueCopy ?
354  * Damn docu !! Err... which docu ?
355  */
356 RETERR16 WINAPI VcpQueueDelete16(
357         LPCSTR lpszDstFileName,
358         LPCSTR lpszDstDir,
359         LOGDISKID16 ldidDst,
360         LPARAM lParamRef
361 )
362 {
363     VCPFILESPEC vfsDst;
364
365     if (!VCP_opened)
366         return ERR_VCP_NOTOPEN;
367
368     vfsDst.ldid = ldidDst;
369     vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
370     vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
371
372     return VCP_VirtnodeCreate(NULL, &vfsDst, VNFL_DELETE, lParamRef, 0);
373 }
374
375 /***********************************************************************
376  *              VcpQueueRename          [SETUPX.204]
377  *
378  */
379 RETERR16 WINAPI VcpQueueRename16(
380         LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
381         LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
382         LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
383         LPARAM lParam
384 )
385 {
386     VCPFILESPEC vfsSrc, vfsDst;
387
388     if (!VCP_opened)
389         return ERR_VCP_NOTOPEN;
390
391     vfsSrc.ldid = ldidSrc;
392     vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
393     vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
394
395     vfsDst.ldid = ldidDst;
396     vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
397     vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
398
399     return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, VNFL_RENAME, lParam,
400                     0);
401 }
402
403 /***********************************************************************
404  *              VcpEnumFiles (SETUPX.@)
405  */
406 INT16 WINAPI VcpEnumFiles(VCPENUMPROC vep, LPARAM lParamRef)
407 {
408     WORD n;
409
410     for (n = 0; n < vn_last; n++)
411         vep(pvnlist[n], lParamRef);
412
413     return 0; /* FIXME: return value ? */
414 }
415
416 /***********************************************************************
417  *              VcpExplain (SETUPX.411)
418  */
419 LPCSTR WINAPI VcpExplain16(LPVIRTNODE lpVn, DWORD dwWhat)
420 {
421     static char buffer[MAX_PATH]; /* FIXME: is this how it's done ? */
422     buffer[0] = '\0';
423     switch (dwWhat)
424     {
425         case VCPEX_SRC_FULL:
426         case VCPEX_DST_FULL:
427             {
428                 LPVCPFILESPEC lpvfs =
429                     (dwWhat == VCPEX_SRC_FULL) ?  &lpVn->vfsSrc : &lpVn->vfsDst;
430
431                 /* if we have an ldid, use it, otherwise use the string */
432                 /* from the vhstrlist array */
433                 if (lpvfs->ldid != 0xffff)
434                   CtlGetLddPath16(lpvfs->ldid, buffer);
435                 else
436                   strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrDir));
437
438                 strcat(buffer, "\\");
439                 strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrFileName));
440             }
441             break;
442         default:
443             FIXME("%d unimplemented !\n", dwWhat);
444             strcpy(buffer, "Unknown error");
445             break;
446     }
447     return buffer;
448 }
449
450 static RETERR16 VCP_CheckPaths(void)
451 {
452     DWORD n;
453     LPVIRTNODE lpvn;
454     RETERR16 cbres;
455
456     cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKSTART, 0, 0, VCP_MsgRef);
457     for (n = 0; n < vn_num; n++)
458     {
459         lpvn = pvnlist[n];
460         if (!lpvn) continue;
461         /* FIXME: check paths of all VIRTNODEs here ! */
462         cbres = VCP_Callback(&lpvn->vfsDst, VCPM_CHECKPATH, 0, (DWORD)lpvn, VCP_MsgRef);
463     }
464     cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKEND, 0, 0, VCP_MsgRef);
465     return OK;
466 }
467
468 static RETERR16 VCP_CopyFiles(void)
469 {
470     char fn_src[MAX_PATH], fn_dst[MAX_PATH];
471     RETERR16 res = OK, cbres;
472     DWORD n;
473     LPVIRTNODE lpvn;
474
475     cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYSTART, 0, 0, VCP_MsgRef);
476     for (n = 0; n < vn_num; n++)
477     {
478         lpvn = pvnlist[n];
479         if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_COPY)) continue;
480         /* FIXME: need to send VCPM_VSTATNEWDISK notification sometimes */
481         strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
482         strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
483         /* FIXME: what is this VCPM_VSTATWRITE here for ?
484          * I guess it's to signal successful destination file creation */
485         cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
486
487         /* FIXME: need to do the file copy in small chunks for notifications */
488         TRACE("copying '%s' to '%s'\n", fn_src, fn_dst);
489         /* perform the file copy */
490         if (!(CopyFileA(fn_src, fn_dst,
491                (lpvn->fl & VNLP_COPYIFEXISTS) ? FALSE : TRUE )))
492         {
493             ERR("error copying, src: %s -> dst: %s\n", fn_src, fn_dst);
494             res = ERR_VCP_IOFAIL;
495         }
496
497         vcp_status.prgFileRead.dwSoFar++;
498         cbres = VCP_Callback(&vcp_status, VCPM_VSTATREAD, 0, 0, VCP_MsgRef);
499         vcp_status.prgFileWrite.dwSoFar++;
500         cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
501     }
502
503     cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYEND, 0, 0, VCP_MsgRef);
504     return res;
505 }
506
507 /***********************************************************************
508  *              VcpFlush - internal (not exported), but documented
509  *
510  * VNFL_NOW is used for VcpFlush.
511  */
512 RETERR16 VcpFlush16(WORD fl, LPCSTR lpszBackupDest)
513 {
514     return OK;
515 }
516
517 /***********************************************************************
518  *              VcpClose (SETUPX.201)
519  *
520  * Does callbacks (-> vifproc) with VCPM_VSTATCLOSESTART,
521  * VCPM_VSTATCLOSEEND.
522  *
523  * fl gets VCPFL_xxx flags to indicate what to do with the
524  * VIRTNODEs (files to mess with) created by e.g. GenInstall()
525  */
526 RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest)
527 {
528     RETERR16 res = OK;
529     WORD cbres = VCPN_PROCEED;
530
531     TRACE("(%04x, '%s')\n", fl, lpszBackupDest);
532
533     /* FIXME: needs to sort VIRTNODEs in case VCPFL_INSPECIFIEDORDER
534      * is not set. This is done by VCP_Callback(VCPM_NODECOMPARE) */
535
536     TRACE("#1\n");
537     memset(&vcp_status, 0, sizeof(VCPSTATUS));
538     /* yes, vcp_status.cbSize is 0 ! */
539     TRACE("#2\n");
540     cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSESTART, 0, 0, VCP_MsgRef);
541     TRACE("#3\n");
542
543     res = VCP_CheckPaths();
544     TRACE("#4\n");
545     if (res != OK)
546         return res; /* is this ok ? */
547     VCP_CopyFiles();
548
549     TRACE("#5\n");
550     cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSEEND, 0, 0, VCP_MsgRef);
551     TRACE("#6\n");
552     VCP_Proc = NULL;
553     VCP_opened = FALSE;
554     return OK;
555 }
556
557 #if 0
558 static RETERR16 VCP_RenameFiles(void)
559 {
560     char fn_src[MAX_PATH], fn_dst[MAX_PATH];
561     RETERR16 res = OK, cbres;
562     DWORD n;
563     LPVIRTNODE lpvn;
564
565     cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMESTART, 0, 0, VCP_MsgRef);
566     for (n = 0; n < vn_num; n++)
567     {
568         lpvn = pvnlist[n];
569         if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_RENAME)) continue;
570         strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
571         strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
572         cbres = VCP_Callback(&lpvn->vfsDst, VCPM_FILEOPENOUT, 0, (LPARAM)lpvn, VCP_MsgRef);
573         if (!(MoveFileExA(fn_src, fn_dst, MOVEFILE_REPLACE_EXISTING)))
574             res = ERR_VCP_IOFAIL;
575         else
576             VCP_VirtnodeDelete(lpvn);
577     }
578     cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMEEND, 0, 0, VCP_MsgRef);
579     return res;
580 }
581 #endif
582
583 /***********************************************************************
584  *              vcpDefCallbackProc (SETUPX.202)
585  */
586 RETERR16 WINAPI vcpDefCallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
587                                         LPARAM lParam, LPARAM lParamRef)
588 {
589     static int count = 0;
590     if (count < 10)
591         FIXME("(%p, %04x, %04lx, %08lx, %08lx) - what to do here ?\n",
592                 lpvObj, uMsg, wParam, lParam, lParamRef);
593     count++;
594     return OK;
595 }
596
597 /********************* point-and-click stuff from here ***********************/
598
599 static HWND hDlgCopy = 0;
600 static HKEY hKeyFiles = 0, hKeyRename = 0, hKeyConflict = 0;
601 static char BackupDir[12];
602
603 static INT_PTR CALLBACK VCP_UI_FileCopyDlgProc(HWND hWndDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
604 {
605     INT_PTR retval = FALSE;
606
607     if (iMsg == WM_INITDIALOG)
608     {
609         ShowWindow(hWndDlg, SW_SHOWNORMAL);
610         UpdateWindow(hWndDlg);
611         retval = TRUE;
612     }
613     return retval;
614 }
615
616 static BOOL VCP_UI_GetDialogTemplate(LPCVOID *template32)
617 {
618     HRSRC hResInfo;
619     HGLOBAL hDlgTmpl32;
620
621     if (!(hResInfo = FindResourceA(SETUPAPI_hInstance, MAKEINTRESOURCEA(COPYFILEDLGORD), (LPSTR)RT_DIALOG)))
622         return FALSE;
623     if (!(hDlgTmpl32 = LoadResource(SETUPAPI_hInstance, hResInfo )) ||
624         !(*template32 = LockResource( hDlgTmpl32 )))
625         return FALSE;
626     return TRUE;
627 }
628
629 static LRESULT WINAPI
630 VCP_UI_FileCopyWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
631 {
632     if (uMsg != WM_CREATE)
633         return DefWindowProcA (hwnd, uMsg, wParam, lParam);
634
635     switch (uMsg)
636     {
637         case WM_CREATE:
638             return 0;
639         default:
640             FIXME("%04x: unhandled.\n", uMsg);
641     }
642
643     return 0;
644 }
645
646 static void VCP_UI_RegisterProgressClass(void)
647 {
648     static BOOL registered = FALSE;
649     WNDCLASSA wndClass;
650
651     if (registered)
652         return;
653
654     registered = TRUE;
655     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
656     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
657     wndClass.lpfnWndProc   = VCP_UI_FileCopyWndProc;
658     wndClass.cbClsExtra    = 0;
659     wndClass.cbWndExtra    = 0;
660     wndClass.hCursor       = LoadCursorA (0, (LPSTR)IDC_ARROW);
661     wndClass.hbrBackground = NULL;
662     wndClass.lpszClassName = "setupx_progress";
663
664     RegisterClassA (&wndClass);
665 }
666
667 static RETERR16 VCP_UI_NodeCompare(LPVIRTNODE vn1, LPVIRTNODE vn2)
668 {
669     LPCSTR file1, file2;
670     file1 = vsmGetStringRawName16(vn1->vfsSrc.vhstrFileName);
671     file2 = vsmGetStringRawName16(vn2->vfsSrc.vhstrFileName);
672     return (RETERR16)strcmp(file1, file2);
673 }
674
675 static RETERR16 VCP_UI_CopyStart(void)
676 {
677     LPCVOID template32;
678     char buf[256]; /* plenty */
679     BOOL dirty;
680     DWORD len;
681
682     /* FIXME: should be registered at DLL startup instead */
683     VCP_UI_RegisterProgressClass();
684     if (!(VCP_UI_GetDialogTemplate(&template32)))
685         return VCPN_FAIL;
686
687     if (vn_num > 10)  /* hack */
688     {
689         hDlgCopy = CreateDialogIndirectParamA(SETUPAPI_hInstance, template32, 0,
690                                               VCP_UI_FileCopyDlgProc, 0);
691         if (!hDlgCopy)
692             return VCPN_FAIL;
693         SetDlgItemTextA(hDlgCopy, SOURCESTRORD, "Scanning ...");
694         SetDlgItemTextA(hDlgCopy, DESTSTRORD, "NOT_IMPLEMENTED_YET");
695     }
696     strcpy(buf, REG_INSTALLEDFILES);
697     if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyFiles))
698         return VCPN_FAIL;
699     strcat(buf, REGPART_RENAME);
700     if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyRename))
701         return VCPN_FAIL;
702     if (RegCreateKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT, &hKeyConflict))
703         return VCPN_FAIL;
704     len = 1;
705     if (!(RegQueryValueExA(hKeyConflict, "Dirty", NULL, 0, (LPBYTE)&dirty, &len)))
706     {
707         /* FIXME: what does SETUPX.DLL do in this case ? */
708         MESSAGE("Warning: another program using SETUPX is already running ! Failed.\n");
709         return VCPN_FAIL;
710     }
711     dirty = TRUE;
712     if (RegSetValueExA(hKeyConflict, "Dirty", 0, REG_BINARY, (LPBYTE)&dirty, 1))
713         return VCPN_FAIL;
714     len = 12;
715     if (!(RegQueryValueExA(hKeyConflict, "BackupDirectory", NULL, 0, (LPBYTE)BackupDir, &len)))
716         strcpy(BackupDir, "VCM");
717
718     /* create C:\WINDOWS\[BackupDir] and set registry key to it */
719     GetWindowsDirectoryA(buf, 256);
720     strcat(buf, "\\");
721     strcat(buf, BackupDir);
722     if (!(CreateDirectoryA(buf, NULL)))
723         return VCPN_FAIL;
724     if (RegSetValueExA(hKeyConflict, "BackupDirectory", 0, REG_SZ, (LPBYTE)buf, strlen(buf)+1))
725         return VCPN_FAIL;
726     RegCloseKey(hKeyConflict);
727
728     return VCPN_OK;
729 }
730
731 /***********************************************************************
732  *              vcpUICallbackProc (SETUPX.213)
733  */
734 RETERR16 WINAPI vcpUICallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
735                                         LPARAM lParam, LPARAM lParamRef)
736 {
737     static int count = 0;
738     RETERR16 res = VCPN_OK, cbres;
739
740     if (count < 5)
741         FIXME("(%p, %04x, %04lx, %08lx, %08lx) - semi-stub\n",
742                 lpvObj, uMsg, wParam, lParam, lParamRef);
743     count++;
744     switch (uMsg)
745     {
746         /* unused messages, it seems */
747         case VCPM_DISKPREPINFO:
748
749         case VCPM_FILENEEDED:
750
751         case VCPM_NODECREATE:
752         case VCPM_NODEACCEPT:
753
754         case VCPM_VSTATCLOSESTART:
755         case VCPM_VSTATPATHCHECKSTART:
756         case VCPM_VSTATPATHCHECKEND:
757
758         case VCPM_CHECKPATH:
759             break;
760
761         /* the real stuff */
762         case VCPM_NODECOMPARE:
763             res = VCP_UI_NodeCompare((LPVIRTNODE)lpvObj, (LPVIRTNODE)lParam);
764             break;
765         case VCPM_VSTATREAD:
766             break;
767         case VCPM_VSTATWRITE:
768             cbres = VCP_Callback(&vcp_status, VCPM_DISKPREPINFO, 0, 0, VCP_MsgRef);
769             break;
770         case VCPM_VSTATCLOSEEND:
771             RegCloseKey(hKeyFiles);
772             RegCloseKey(hKeyRename);
773             RegDeleteKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT);
774             break;
775         case VCPM_VSTATCOPYSTART:
776             res = VCP_UI_CopyStart();
777             break;
778         case VCPM_VSTATCOPYEND:
779             if (hDlgCopy) DestroyWindow(hDlgCopy);
780             break;
781         default:
782             FIXME("unhandled msg 0x%04x\n", uMsg);
783     }
784     return res;
785 }