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