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