oleaut32/tests: Replace realloc() with HeapReAlloc().
[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  *              vsmGetStringName (SETUPX.205)
166  *
167  * Pretty correct, I guess
168  */
169 INT16 WINAPI vsmGetStringName16(VHSTR vhstr, LPSTR lpszBuffer, int cbBuffer)
170 {
171     if (VALID_VHSTR(vhstr))
172     {
173         int len = strlen(vhstrlist[vhstr]->pStr)+1;
174         if (cbBuffer >= len)
175         {
176             if (lpszBuffer)
177                 strcpy(lpszBuffer, vhstrlist[vhstr]->pStr);
178             return len;
179         }
180     }
181     return VCPN_FAIL;
182 }
183
184 /***********************************************************************
185  *              vsmGetStringRawName (SETUPX.208)
186  */
187 LPCSTR WINAPI vsmGetStringRawName16(VHSTR vhstr)
188 {
189     return (VALID_VHSTR(vhstr)) ? vhstrlist[vhstr]->pStr : NULL;
190 }
191
192
193 /***************************** VIRTNODE management ****************************/
194 static LPVIRTNODE *pvnlist = NULL;
195 static DWORD vn_num = 0;
196 static DWORD vn_last = 0;
197
198 static RETERR16 VCP_VirtnodeCreate(const VCPFILESPEC *vfsSrc, const VCPFILESPEC *vfsDst,
199                                    WORD fl, LPARAM lParam, LPEXPANDVTBL lpExpandVtbl)
200 {
201     HANDLE heap;
202     LPVIRTNODE lpvn;
203     RETERR16 cbres;
204
205     while (vn_last < vn_num)
206     {
207         if (pvnlist[vn_last] == NULL)
208             break;
209         vn_last++;
210     }
211     heap = GetProcessHeap();
212     if (vn_last == vn_num)
213     {
214         vn_num += 20;
215         if (pvnlist)
216             pvnlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, pvnlist,
217                                 sizeof(LPVIRTNODE *) * vn_num);
218         else
219             pvnlist = HeapAlloc(heap, HEAP_ZERO_MEMORY, 
220                                 sizeof(LPVIRTNODE *) * vn_num);
221     }
222     pvnlist[vn_last] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VIRTNODE));
223     lpvn = pvnlist[vn_last];
224     vn_last++;
225
226     lpvn->cbSize = sizeof(VIRTNODE);
227
228     if (vfsSrc)
229         lpvn->vfsSrc = *vfsSrc;
230
231     if (vfsDst)
232         lpvn->vfsDst = *vfsDst;
233
234     lpvn->fl = fl;
235     lpvn->lParam = lParam;
236     lpvn->lpExpandVtbl = lpExpandVtbl;
237
238     lpvn->vhstrDstFinalName = 0xffff; /* FIXME: what is this ? */
239
240     cbres = VCP_Callback(lpvn, VCPM_NODECREATE, 0, 0, VCP_MsgRef);
241     lpvn->fl |= VFNL_CREATED;
242     cbres = VCP_Callback(lpvn, VCPM_NODEACCEPT, 0, 0, VCP_MsgRef);
243
244     return OK;
245 }
246
247 /***********************************************************************
248  *              VcpOpen (SETUPX.200)
249  *
250  * Sets up a virtual copy operation.
251  * This means that functions such as GenInstall()
252  * create a VIRTNODE struct for every file to be touched in a .INF file
253  * instead of actually touching the file.
254  * The actual copy/move/rename gets started when VcpClose or
255  * VcpFlush is called; several different callbacks are made
256  * (copy, rename, open, close, version conflicts, ...) on every file copied.
257  */
258 RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef)
259 {
260     TRACE("(%p, %08lx)\n", vifproc, lparamMsgRef);
261     if (VCP_opened)
262         return ERR_VCP_BUSY;
263
264     VCP_Proc = (FARPROC16)vifproc;
265     VCP_MsgRef = lparamMsgRef;
266
267     VCP_opened = TRUE;
268     return OK;
269 }
270
271 /***********************************************************************
272  *              VcpQueueCopy            [SETUPX.13]
273  *
274  * lpExpandVtbl seems to be deprecated.
275  * fl are the CNFL_xxx and VNFL_xxx flags.
276  * lParam are the VNLP_xxx flags.
277  */
278 RETERR16 WINAPI VcpQueueCopy16(
279         LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
280         LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
281         LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
282         LPEXPANDVTBL lpExpandVtbl,
283         WORD fl, LPARAM lParam
284 )
285 {
286     VCPFILESPEC vfsSrc, vfsDst;
287
288     if (!VCP_opened)
289         return ERR_VCP_NOTOPEN;
290
291     TRACE("srcdir: %s, srcfile: %s, dstdir: %s, dstfile: %s\n",
292       lpszSrcDir, lpszSrcFileName, lpszDstDir, lpszDstFileName);
293
294     TRACE("ldidSrc == %d, ldidDst == %d\n", ldidSrc, ldidDst);
295
296     vfsSrc.ldid = ldidSrc;
297     vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
298     vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
299
300     vfsDst.ldid = ldidDst;
301     vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
302     vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
303
304     return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, fl, lParam,
305                     lpExpandVtbl);
306 }
307
308 /***********************************************************************
309  *              VcpQueueDelete          [SETUPX.17]
310  *
311  * Is lParamRef the same as lParam in VcpQueueCopy ?
312  * Damn docu !! Err... which docu ?
313  */
314 RETERR16 WINAPI VcpQueueDelete16(
315         LPCSTR lpszDstFileName,
316         LPCSTR lpszDstDir,
317         LOGDISKID16 ldidDst,
318         LPARAM lParamRef
319 )
320 {
321     VCPFILESPEC vfsDst;
322
323     if (!VCP_opened)
324         return ERR_VCP_NOTOPEN;
325
326     vfsDst.ldid = ldidDst;
327     vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
328     vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
329
330     return VCP_VirtnodeCreate(NULL, &vfsDst, VNFL_DELETE, lParamRef, 0);
331 }
332
333 /***********************************************************************
334  *              VcpQueueRename          [SETUPX.204]
335  *
336  */
337 RETERR16 WINAPI VcpQueueRename16(
338         LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
339         LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
340         LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
341         LPARAM lParam
342 )
343 {
344     VCPFILESPEC vfsSrc, vfsDst;
345
346     if (!VCP_opened)
347         return ERR_VCP_NOTOPEN;
348
349     vfsSrc.ldid = ldidSrc;
350     vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
351     vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
352
353     vfsDst.ldid = ldidDst;
354     vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
355     vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
356
357     return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, VNFL_RENAME, lParam,
358                     0);
359 }
360
361 /***********************************************************************
362  *              VcpEnumFiles (SETUPX.@)
363  */
364 INT16 WINAPI VcpEnumFiles(VCPENUMPROC vep, LPARAM lParamRef)
365 {
366     WORD n;
367
368     for (n = 0; n < vn_last; n++)
369         vep(pvnlist[n], lParamRef);
370
371     return 0; /* FIXME: return value ? */
372 }
373
374 /***********************************************************************
375  *              VcpExplain (SETUPX.411)
376  */
377 LPCSTR WINAPI VcpExplain16(LPVIRTNODE lpVn, DWORD dwWhat)
378 {
379     static char buffer[MAX_PATH]; /* FIXME: is this how it's done ? */
380     buffer[0] = '\0';
381     switch (dwWhat)
382     {
383         case VCPEX_SRC_FULL:
384         case VCPEX_DST_FULL:
385             {
386                 LPVCPFILESPEC lpvfs =
387                     (dwWhat == VCPEX_SRC_FULL) ?  &lpVn->vfsSrc : &lpVn->vfsDst;
388
389                 /* if we have an ldid, use it, otherwise use the string */
390                 /* from the vhstrlist array */
391                 if (lpvfs->ldid != 0xffff)
392                   CtlGetLddPath16(lpvfs->ldid, buffer);
393                 else
394                   strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrDir));
395
396                 strcat(buffer, "\\");
397                 strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrFileName));
398             }
399             break;
400         default:
401             FIXME("%d unimplemented !\n", dwWhat);
402             strcpy(buffer, "Unknown error");
403             break;
404     }
405     return buffer;
406 }
407
408 static RETERR16 VCP_CheckPaths(void)
409 {
410     DWORD n;
411     LPVIRTNODE lpvn;
412     RETERR16 cbres;
413
414     cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKSTART, 0, 0, VCP_MsgRef);
415     for (n = 0; n < vn_num; n++)
416     {
417         lpvn = pvnlist[n];
418         if (!lpvn) continue;
419         /* FIXME: check paths of all VIRTNODEs here ! */
420         cbres = VCP_Callback(&lpvn->vfsDst, VCPM_CHECKPATH, 0, (DWORD)lpvn, VCP_MsgRef);
421     }
422     cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKEND, 0, 0, VCP_MsgRef);
423     return OK;
424 }
425
426 static RETERR16 VCP_CopyFiles(void)
427 {
428     char fn_src[MAX_PATH], fn_dst[MAX_PATH];
429     RETERR16 res = OK, cbres;
430     DWORD n;
431     LPVIRTNODE lpvn;
432
433     cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYSTART, 0, 0, VCP_MsgRef);
434     for (n = 0; n < vn_num; n++)
435     {
436         lpvn = pvnlist[n];
437         if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_COPY)) continue;
438         /* FIXME: need to send VCPM_VSTATNEWDISK notification sometimes */
439         strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
440         strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
441         /* FIXME: what is this VCPM_VSTATWRITE here for ?
442          * I guess it's to signal successful destination file creation */
443         cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
444
445         /* FIXME: need to do the file copy in small chunks for notifications */
446         TRACE("copying '%s' to '%s'\n", fn_src, fn_dst);
447         /* perform the file copy */
448         if (!(CopyFileA(fn_src, fn_dst,
449                (lpvn->fl & VNLP_COPYIFEXISTS) ? FALSE : TRUE )))
450         {
451             ERR("error copying, src: %s -> dst: %s\n", fn_src, fn_dst);
452             res = ERR_VCP_IOFAIL;
453         }
454
455         vcp_status.prgFileRead.dwSoFar++;
456         cbres = VCP_Callback(&vcp_status, VCPM_VSTATREAD, 0, 0, VCP_MsgRef);
457         vcp_status.prgFileWrite.dwSoFar++;
458         cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
459     }
460
461     cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYEND, 0, 0, VCP_MsgRef);
462     return res;
463 }
464
465 /***********************************************************************
466  *              VcpClose (SETUPX.201)
467  *
468  * Does callbacks (-> vifproc) with VCPM_VSTATCLOSESTART,
469  * VCPM_VSTATCLOSEEND.
470  *
471  * fl gets VCPFL_xxx flags to indicate what to do with the
472  * VIRTNODEs (files to mess with) created by e.g. GenInstall()
473  */
474 RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest)
475 {
476     RETERR16 res = OK;
477     WORD cbres = VCPN_PROCEED;
478
479     TRACE("(%04x, '%s')\n", fl, lpszBackupDest);
480
481     /* FIXME: needs to sort VIRTNODEs in case VCPFL_INSPECIFIEDORDER
482      * is not set. This is done by VCP_Callback(VCPM_NODECOMPARE) */
483
484     TRACE("#1\n");
485     memset(&vcp_status, 0, sizeof(VCPSTATUS));
486     /* yes, vcp_status.cbSize is 0 ! */
487     TRACE("#2\n");
488     cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSESTART, 0, 0, VCP_MsgRef);
489     TRACE("#3\n");
490
491     res = VCP_CheckPaths();
492     TRACE("#4\n");
493     if (res != OK)
494         return res; /* is this ok ? */
495     VCP_CopyFiles();
496
497     TRACE("#5\n");
498     cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSEEND, 0, 0, VCP_MsgRef);
499     TRACE("#6\n");
500     VCP_Proc = NULL;
501     VCP_opened = FALSE;
502     return OK;
503 }
504
505 /***********************************************************************
506  *              vcpDefCallbackProc (SETUPX.202)
507  */
508 RETERR16 WINAPI vcpDefCallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
509                                         LPARAM lParam, LPARAM lParamRef)
510 {
511     static int count = 0;
512     if (count < 10)
513         FIXME("(%p, %04x, %04lx, %08lx, %08lx) - what to do here ?\n",
514                 lpvObj, uMsg, wParam, lParam, lParamRef);
515     count++;
516     return OK;
517 }
518
519 /********************* point-and-click stuff from here ***********************/
520
521 static HWND hDlgCopy = 0;
522 static HKEY hKeyFiles = 0, hKeyRename = 0, hKeyConflict = 0;
523 static char BackupDir[12];
524
525 static INT_PTR CALLBACK VCP_UI_FileCopyDlgProc(HWND hWndDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
526 {
527     INT_PTR retval = FALSE;
528
529     if (iMsg == WM_INITDIALOG)
530     {
531         ShowWindow(hWndDlg, SW_SHOWNORMAL);
532         UpdateWindow(hWndDlg);
533         retval = TRUE;
534     }
535     return retval;
536 }
537
538 static BOOL VCP_UI_GetDialogTemplate(LPCVOID *template32)
539 {
540     HRSRC hResInfo;
541     HGLOBAL hDlgTmpl32;
542
543     if (!(hResInfo = FindResourceA(SETUPAPI_hInstance, MAKEINTRESOURCEA(COPYFILEDLGORD), (LPSTR)RT_DIALOG)))
544         return FALSE;
545     if (!(hDlgTmpl32 = LoadResource(SETUPAPI_hInstance, hResInfo )) ||
546         !(*template32 = LockResource( hDlgTmpl32 )))
547         return FALSE;
548     return TRUE;
549 }
550
551 static LRESULT WINAPI
552 VCP_UI_FileCopyWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
553 {
554     if (uMsg != WM_CREATE)
555         return DefWindowProcA (hwnd, uMsg, wParam, lParam);
556
557     switch (uMsg)
558     {
559         case WM_CREATE:
560             return 0;
561         default:
562             FIXME("%04x: unhandled.\n", uMsg);
563     }
564
565     return 0;
566 }
567
568 static void VCP_UI_RegisterProgressClass(void)
569 {
570     static BOOL registered = FALSE;
571     WNDCLASSA wndClass;
572
573     if (registered)
574         return;
575
576     registered = TRUE;
577     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
578     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
579     wndClass.lpfnWndProc   = VCP_UI_FileCopyWndProc;
580     wndClass.cbClsExtra    = 0;
581     wndClass.cbWndExtra    = 0;
582     wndClass.hCursor       = LoadCursorA (0, (LPSTR)IDC_ARROW);
583     wndClass.hbrBackground = NULL;
584     wndClass.lpszClassName = "setupx_progress";
585
586     RegisterClassA (&wndClass);
587 }
588
589 static RETERR16 VCP_UI_NodeCompare(LPVIRTNODE vn1, LPVIRTNODE vn2)
590 {
591     LPCSTR file1, file2;
592     file1 = vsmGetStringRawName16(vn1->vfsSrc.vhstrFileName);
593     file2 = vsmGetStringRawName16(vn2->vfsSrc.vhstrFileName);
594     return (RETERR16)strcmp(file1, file2);
595 }
596
597 static RETERR16 VCP_UI_CopyStart(void)
598 {
599     LPCVOID template32;
600     char buf[256]; /* plenty */
601     BOOL dirty;
602     DWORD len;
603
604     /* FIXME: should be registered at DLL startup instead */
605     VCP_UI_RegisterProgressClass();
606     if (!(VCP_UI_GetDialogTemplate(&template32)))
607         return VCPN_FAIL;
608
609     if (vn_num > 10)  /* hack */
610     {
611         hDlgCopy = CreateDialogIndirectParamA(SETUPAPI_hInstance, template32, 0,
612                                               VCP_UI_FileCopyDlgProc, 0);
613         if (!hDlgCopy)
614             return VCPN_FAIL;
615         SetDlgItemTextA(hDlgCopy, SOURCESTRORD, "Scanning ...");
616         SetDlgItemTextA(hDlgCopy, DESTSTRORD, "NOT_IMPLEMENTED_YET");
617     }
618     strcpy(buf, REG_INSTALLEDFILES);
619     if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyFiles))
620         return VCPN_FAIL;
621     strcat(buf, REGPART_RENAME);
622     if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyRename))
623         return VCPN_FAIL;
624     if (RegCreateKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT, &hKeyConflict))
625         return VCPN_FAIL;
626     len = 1;
627     if (!(RegQueryValueExA(hKeyConflict, "Dirty", NULL, 0, (LPBYTE)&dirty, &len)))
628     {
629         /* FIXME: what does SETUPX.DLL do in this case ? */
630         MESSAGE("Warning: another program using SETUPX is already running ! Failed.\n");
631         return VCPN_FAIL;
632     }
633     dirty = TRUE;
634     if (RegSetValueExA(hKeyConflict, "Dirty", 0, REG_BINARY, (LPBYTE)&dirty, 1))
635         return VCPN_FAIL;
636     len = 12;
637     if (!(RegQueryValueExA(hKeyConflict, "BackupDirectory", NULL, 0, (LPBYTE)BackupDir, &len)))
638         strcpy(BackupDir, "VCM");
639
640     /* create C:\WINDOWS\[BackupDir] and set registry key to it */
641     GetWindowsDirectoryA(buf, 256);
642     strcat(buf, "\\");
643     strcat(buf, BackupDir);
644     if (!(CreateDirectoryA(buf, NULL)))
645         return VCPN_FAIL;
646     if (RegSetValueExA(hKeyConflict, "BackupDirectory", 0, REG_SZ, (LPBYTE)buf, strlen(buf)+1))
647         return VCPN_FAIL;
648     RegCloseKey(hKeyConflict);
649
650     return VCPN_OK;
651 }
652
653 /***********************************************************************
654  *              vcpUICallbackProc (SETUPX.213)
655  */
656 RETERR16 WINAPI vcpUICallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
657                                         LPARAM lParam, LPARAM lParamRef)
658 {
659     static int count = 0;
660     RETERR16 res = VCPN_OK, cbres;
661
662     if (count < 5)
663         FIXME("(%p, %04x, %04lx, %08lx, %08lx) - semi-stub\n",
664                 lpvObj, uMsg, wParam, lParam, lParamRef);
665     count++;
666     switch (uMsg)
667     {
668         /* unused messages, it seems */
669         case VCPM_DISKPREPINFO:
670
671         case VCPM_FILENEEDED:
672
673         case VCPM_NODECREATE:
674         case VCPM_NODEACCEPT:
675
676         case VCPM_VSTATCLOSESTART:
677         case VCPM_VSTATPATHCHECKSTART:
678         case VCPM_VSTATPATHCHECKEND:
679
680         case VCPM_CHECKPATH:
681             break;
682
683         /* the real stuff */
684         case VCPM_NODECOMPARE:
685             res = VCP_UI_NodeCompare((LPVIRTNODE)lpvObj, (LPVIRTNODE)lParam);
686             break;
687         case VCPM_VSTATREAD:
688             break;
689         case VCPM_VSTATWRITE:
690             cbres = VCP_Callback(&vcp_status, VCPM_DISKPREPINFO, 0, 0, VCP_MsgRef);
691             break;
692         case VCPM_VSTATCLOSEEND:
693             RegCloseKey(hKeyFiles);
694             RegCloseKey(hKeyRename);
695             RegDeleteKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT);
696             break;
697         case VCPM_VSTATCOPYSTART:
698             res = VCP_UI_CopyStart();
699             break;
700         case VCPM_VSTATCOPYEND:
701             if (hDlgCopy) DestroyWindow(hDlgCopy);
702             break;
703         default:
704             FIXME("unhandled msg 0x%04x\n", uMsg);
705     }
706     return res;
707 }