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