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