2 * SetupAPI virtual copy operations
4 * Copyright 2001 Andreas Mohr
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.
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.
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
20 * FIXME: we now rely on builtin setupapi.dll for dialog resources.
21 * This is bad ! We ought to have 16bit resource handling working.
34 #include "setupapi_private.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
39 static FARPROC16 VCP_Proc = NULL;
40 static LPARAM VCP_MsgRef = 0;
42 static BOOL VCP_opened = FALSE;
44 static VCPSTATUS vcp_status;
46 static WORD VCP_Callback( LPVOID obj, UINT16 msg, WPARAM16 wParam, LPARAM lParam, LPARAM lParamRef )
52 args[7] = HIWORD(obj);
53 args[6] = LOWORD(obj);
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 );
65 /****************************** VHSTR management ******************************/
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 ! :-)
78 static VHSTR_STRUCT **vhstrlist = NULL;
79 static VHSTR vhstr_alloc = 0;
81 #define VALID_VHSTR(x) ((x < vhstr_alloc) && (vhstrlist[x]) && (vhstrlist[x]->refcount))
83 /***********************************************************************
84 * vsmStringAdd (SETUPX.207)
86 VHSTR WINAPI vsmStringAdd16(LPCSTR lpszName)
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++)
98 if ((vhstrlist[n]) && (vhstrlist[n]->refcount))
100 TRACE("checking item: %d\n", n);
101 if (!strcmp(vhstrlist[n]->pStr, lpszName))
104 vhstrlist[n]->refcount++;
110 /* hmm, not found yet, let's insert it */
111 TRACE("inserting item\n");
112 for (n = 0; n < vhstr_alloc; n++)
114 if ((!(vhstrlist[n])) || (!(vhstrlist[n]->refcount)))
120 heap = GetProcessHeap();
121 if (n == vhstr_alloc) /* hmm, no free index found yet */
127 vhstrlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, vhstrlist,
128 sizeof(VHSTR_STRUCT *) * vhstr_alloc);
130 vhstrlist = HeapAlloc(heap, HEAP_ZERO_MEMORY,
131 sizeof(VHSTR_STRUCT *) * vhstr_alloc);
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;
144 /***********************************************************************
145 * vsmStringDelete (SETUPX.206)
147 INT16 WINAPI vsmStringDelete16(VHSTR vhstr)
149 if (VALID_VHSTR(vhstr))
151 vhstrlist[vhstr]->refcount--;
152 if (!vhstrlist[vhstr]->refcount)
154 HeapFree(GetProcessHeap(), 0, (LPSTR)vhstrlist[vhstr]->pStr);
155 vhstrlist[vhstr]->pStr = NULL;
160 /* string not found */
165 * vsmStringFind() - not exported from a standard SETUPX.DLL, it seems
167 VHSTR WINAPI vsmStringFind16(LPCSTR lpszName)
170 for (n = 0; n < vhstr_alloc; n++)
171 if ((vhstrlist[n]) && (vhstrlist[n]->refcount) && (!strcmp(vhstrlist[n]->pStr, lpszName)))
176 /***********************************************************************
177 * vsmGetStringName (SETUPX.205)
179 * Pretty correct, I guess
181 INT16 WINAPI vsmGetStringName16(VHSTR vhstr, LPSTR lpszBuffer, int cbBuffer)
183 if (VALID_VHSTR(vhstr))
185 int len = strlen(vhstrlist[vhstr]->pStr)+1;
189 strcpy(lpszBuffer, vhstrlist[vhstr]->pStr);
196 /***********************************************************************
197 * vsmStringCompare (not exported from a standard SETUPX.DLL, it seems)
199 INT16 WINAPI vsmStringCompare16(VHSTR vhstrA, VHSTR vhstrB)
201 if ((!VALID_VHSTR(vhstrA)) || (!VALID_VHSTR(vhstrB)))
202 return VCPN_FAIL; /* correct ? */
203 return strcmp(vhstrlist[vhstrA]->pStr, vhstrlist[vhstrB]->pStr);
206 /***********************************************************************
207 * vsmGetStringRawName (SETUPX.208)
209 LPCSTR WINAPI vsmGetStringRawName16(VHSTR vhstr)
211 return (VALID_VHSTR(vhstr)) ? vhstrlist[vhstr]->pStr : NULL;
215 /***************************** VIRTNODE management ****************************/
216 static LPVIRTNODE *pvnlist = NULL;
217 static DWORD vn_num = 0;
218 static DWORD vn_last = 0;
220 static RETERR16 VCP_VirtnodeCreate(const VCPFILESPEC *vfsSrc, const VCPFILESPEC *vfsDst,
221 WORD fl, LPARAM lParam, LPEXPANDVTBL lpExpandVtbl)
227 while (vn_last < vn_num)
229 if (pvnlist[vn_last] == NULL)
233 heap = GetProcessHeap();
234 if (vn_last == vn_num)
238 pvnlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, pvnlist,
239 sizeof(LPVIRTNODE *) * vn_num);
241 pvnlist = HeapAlloc(heap, HEAP_ZERO_MEMORY,
242 sizeof(LPVIRTNODE *) * vn_num);
244 pvnlist[vn_last] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VIRTNODE));
245 lpvn = pvnlist[vn_last];
248 lpvn->cbSize = sizeof(VIRTNODE);
251 lpvn->vfsSrc = *vfsSrc;
254 lpvn->vfsDst = *vfsDst;
257 lpvn->lParam = lParam;
258 lpvn->lpExpandVtbl = lpExpandVtbl;
260 lpvn->vhstrDstFinalName = 0xffff; /* FIXME: what is this ? */
262 cbres = VCP_Callback(lpvn, VCPM_NODECREATE, 0, 0, VCP_MsgRef);
263 lpvn->fl |= VFNL_CREATED;
264 cbres = VCP_Callback(lpvn, VCPM_NODEACCEPT, 0, 0, VCP_MsgRef);
270 static BOOL VCP_VirtnodeDelete(LPVIRTNODE lpvnDel)
275 for (n = 0; n < vn_last; n++)
277 if (pvnlist[n] == lpvnDel)
279 cbres = VCP_Callback(lpvnDel, VCPM_NODEDESTROY, 0, 0, VCP_MsgRef);
280 HeapFree(GetProcessHeap(), 0, lpvnDel);
289 /***********************************************************************
290 * VcpOpen (SETUPX.200)
292 * Sets up a virtual copy operation.
293 * This means that functions such as GenInstall()
294 * create a VIRTNODE struct for every file to be touched in a .INF file
295 * instead of actually touching the file.
296 * The actual copy/move/rename gets started when VcpClose or
297 * VcpFlush is called; several different callbacks are made
298 * (copy, rename, open, close, version conflicts, ...) on every file copied.
300 RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef)
302 TRACE("(%p, %08lx)\n", vifproc, lparamMsgRef);
306 VCP_Proc = (FARPROC16)vifproc;
307 VCP_MsgRef = lparamMsgRef;
313 /***********************************************************************
314 * VcpQueueCopy [SETUPX.13]
316 * lpExpandVtbl seems to be deprecated.
317 * fl are the CNFL_xxx and VNFL_xxx flags.
318 * lParam are the VNLP_xxx flags.
320 RETERR16 WINAPI VcpQueueCopy16(
321 LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
322 LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
323 LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
324 LPEXPANDVTBL lpExpandVtbl,
325 WORD fl, LPARAM lParam
328 VCPFILESPEC vfsSrc, vfsDst;
331 return ERR_VCP_NOTOPEN;
333 TRACE("srcdir: %s, srcfile: %s, dstdir: %s, dstfile: %s\n",
334 lpszSrcDir, lpszSrcFileName, lpszDstDir, lpszDstFileName);
336 TRACE("ldidSrc == %d, ldidDst == %d\n", ldidSrc, ldidDst);
338 vfsSrc.ldid = ldidSrc;
339 vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
340 vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
342 vfsDst.ldid = ldidDst;
343 vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
344 vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
346 return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, fl, lParam,
350 /***********************************************************************
351 * VcpQueueDelete [SETUPX.17]
353 * Is lParamRef the same as lParam in VcpQueueCopy ?
354 * Damn docu !! Err... which docu ?
356 RETERR16 WINAPI VcpQueueDelete16(
357 LPCSTR lpszDstFileName,
366 return ERR_VCP_NOTOPEN;
368 vfsDst.ldid = ldidDst;
369 vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
370 vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
372 return VCP_VirtnodeCreate(NULL, &vfsDst, VNFL_DELETE, lParamRef, 0);
375 /***********************************************************************
376 * VcpQueueRename [SETUPX.204]
379 RETERR16 WINAPI VcpQueueRename16(
380 LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
381 LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
382 LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
386 VCPFILESPEC vfsSrc, vfsDst;
389 return ERR_VCP_NOTOPEN;
391 vfsSrc.ldid = ldidSrc;
392 vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
393 vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
395 vfsDst.ldid = ldidDst;
396 vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
397 vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
399 return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, VNFL_RENAME, lParam,
403 /***********************************************************************
404 * VcpEnumFiles (SETUPX.@)
406 INT16 WINAPI VcpEnumFiles(VCPENUMPROC vep, LPARAM lParamRef)
410 for (n = 0; n < vn_last; n++)
411 vep(pvnlist[n], lParamRef);
413 return 0; /* FIXME: return value ? */
416 /***********************************************************************
417 * VcpExplain (SETUPX.411)
419 LPCSTR WINAPI VcpExplain16(LPVIRTNODE lpVn, DWORD dwWhat)
421 static char buffer[MAX_PATH]; /* FIXME: is this how it's done ? */
428 LPVCPFILESPEC lpvfs =
429 (dwWhat == VCPEX_SRC_FULL) ? &lpVn->vfsSrc : &lpVn->vfsDst;
431 /* if we have an ldid, use it, otherwise use the string */
432 /* from the vhstrlist array */
433 if (lpvfs->ldid != 0xffff)
434 CtlGetLddPath16(lpvfs->ldid, buffer);
436 strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrDir));
438 strcat(buffer, "\\");
439 strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrFileName));
443 FIXME("%d unimplemented !\n", dwWhat);
444 strcpy(buffer, "Unknown error");
450 static RETERR16 VCP_CheckPaths(void)
456 cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKSTART, 0, 0, VCP_MsgRef);
457 for (n = 0; n < vn_num; n++)
461 /* FIXME: check paths of all VIRTNODEs here ! */
462 cbres = VCP_Callback(&lpvn->vfsDst, VCPM_CHECKPATH, 0, (DWORD)lpvn, VCP_MsgRef);
464 cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKEND, 0, 0, VCP_MsgRef);
468 static RETERR16 VCP_CopyFiles(void)
470 char fn_src[MAX_PATH], fn_dst[MAX_PATH];
471 RETERR16 res = OK, cbres;
475 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYSTART, 0, 0, VCP_MsgRef);
476 for (n = 0; n < vn_num; n++)
479 if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_COPY)) continue;
480 /* FIXME: need to send VCPM_VSTATNEWDISK notification sometimes */
481 strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
482 strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
483 /* FIXME: what is this VCPM_VSTATWRITE here for ?
484 * I guess it's to signal successful destination file creation */
485 cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
487 /* FIXME: need to do the file copy in small chunks for notifications */
488 TRACE("copying '%s' to '%s'\n", fn_src, fn_dst);
489 /* perform the file copy */
490 if (!(CopyFileA(fn_src, fn_dst,
491 (lpvn->fl & VNLP_COPYIFEXISTS) ? FALSE : TRUE )))
493 ERR("error copying, src: %s -> dst: %s\n", fn_src, fn_dst);
494 res = ERR_VCP_IOFAIL;
497 vcp_status.prgFileRead.dwSoFar++;
498 cbres = VCP_Callback(&vcp_status, VCPM_VSTATREAD, 0, 0, VCP_MsgRef);
499 vcp_status.prgFileWrite.dwSoFar++;
500 cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
503 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYEND, 0, 0, VCP_MsgRef);
507 /***********************************************************************
508 * VcpFlush - internal (not exported), but documented
510 * VNFL_NOW is used for VcpFlush.
512 RETERR16 VcpFlush16(WORD fl, LPCSTR lpszBackupDest)
517 /***********************************************************************
518 * VcpClose (SETUPX.201)
520 * Does callbacks (-> vifproc) with VCPM_VSTATCLOSESTART,
521 * VCPM_VSTATCLOSEEND.
523 * fl gets VCPFL_xxx flags to indicate what to do with the
524 * VIRTNODEs (files to mess with) created by e.g. GenInstall()
526 RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest)
529 WORD cbres = VCPN_PROCEED;
531 TRACE("(%04x, '%s')\n", fl, lpszBackupDest);
533 /* FIXME: needs to sort VIRTNODEs in case VCPFL_INSPECIFIEDORDER
534 * is not set. This is done by VCP_Callback(VCPM_NODECOMPARE) */
537 memset(&vcp_status, 0, sizeof(VCPSTATUS));
538 /* yes, vcp_status.cbSize is 0 ! */
540 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSESTART, 0, 0, VCP_MsgRef);
543 res = VCP_CheckPaths();
546 return res; /* is this ok ? */
550 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSEEND, 0, 0, VCP_MsgRef);
558 static RETERR16 VCP_RenameFiles(void)
560 char fn_src[MAX_PATH], fn_dst[MAX_PATH];
561 RETERR16 res = OK, cbres;
565 cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMESTART, 0, 0, VCP_MsgRef);
566 for (n = 0; n < vn_num; n++)
569 if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_RENAME)) continue;
570 strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
571 strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
572 cbres = VCP_Callback(&lpvn->vfsDst, VCPM_FILEOPENOUT, 0, (LPARAM)lpvn, VCP_MsgRef);
573 if (!(MoveFileExA(fn_src, fn_dst, MOVEFILE_REPLACE_EXISTING)))
574 res = ERR_VCP_IOFAIL;
576 VCP_VirtnodeDelete(lpvn);
578 cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMEEND, 0, 0, VCP_MsgRef);
583 /***********************************************************************
584 * vcpDefCallbackProc (SETUPX.202)
586 RETERR16 WINAPI vcpDefCallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
587 LPARAM lParam, LPARAM lParamRef)
589 static int count = 0;
591 FIXME("(%p, %04x, %04lx, %08lx, %08lx) - what to do here ?\n",
592 lpvObj, uMsg, wParam, lParam, lParamRef);
597 /********************* point-and-click stuff from here ***********************/
599 static HWND hDlgCopy = 0;
600 static HKEY hKeyFiles = 0, hKeyRename = 0, hKeyConflict = 0;
601 static char BackupDir[12];
603 static INT_PTR CALLBACK VCP_UI_FileCopyDlgProc(HWND hWndDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
605 INT_PTR retval = FALSE;
607 if (iMsg == WM_INITDIALOG)
609 ShowWindow(hWndDlg, SW_SHOWNORMAL);
610 UpdateWindow(hWndDlg);
616 static BOOL VCP_UI_GetDialogTemplate(LPCVOID *template32)
621 if (!(hResInfo = FindResourceA(SETUPAPI_hInstance, MAKEINTRESOURCEA(COPYFILEDLGORD), (LPSTR)RT_DIALOG)))
623 if (!(hDlgTmpl32 = LoadResource(SETUPAPI_hInstance, hResInfo )) ||
624 !(*template32 = LockResource( hDlgTmpl32 )))
629 static LRESULT WINAPI
630 VCP_UI_FileCopyWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
632 if (uMsg != WM_CREATE)
633 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
640 FIXME("%04x: unhandled.\n", uMsg);
646 static void VCP_UI_RegisterProgressClass(void)
648 static BOOL registered = FALSE;
655 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
656 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
657 wndClass.lpfnWndProc = VCP_UI_FileCopyWndProc;
658 wndClass.cbClsExtra = 0;
659 wndClass.cbWndExtra = 0;
660 wndClass.hCursor = LoadCursorA (0, (LPSTR)IDC_ARROW);
661 wndClass.hbrBackground = NULL;
662 wndClass.lpszClassName = "setupx_progress";
664 RegisterClassA (&wndClass);
667 static RETERR16 VCP_UI_NodeCompare(LPVIRTNODE vn1, LPVIRTNODE vn2)
670 file1 = vsmGetStringRawName16(vn1->vfsSrc.vhstrFileName);
671 file2 = vsmGetStringRawName16(vn2->vfsSrc.vhstrFileName);
672 return (RETERR16)strcmp(file1, file2);
675 static RETERR16 VCP_UI_CopyStart(void)
678 char buf[256]; /* plenty */
682 /* FIXME: should be registered at DLL startup instead */
683 VCP_UI_RegisterProgressClass();
684 if (!(VCP_UI_GetDialogTemplate(&template32)))
687 if (vn_num > 10) /* hack */
689 hDlgCopy = CreateDialogIndirectParamA(SETUPAPI_hInstance, template32, 0,
690 VCP_UI_FileCopyDlgProc, 0);
693 SetDlgItemTextA(hDlgCopy, SOURCESTRORD, "Scanning ...");
694 SetDlgItemTextA(hDlgCopy, DESTSTRORD, "NOT_IMPLEMENTED_YET");
696 strcpy(buf, REG_INSTALLEDFILES);
697 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyFiles))
699 strcat(buf, REGPART_RENAME);
700 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyRename))
702 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT, &hKeyConflict))
705 if (!(RegQueryValueExA(hKeyConflict, "Dirty", NULL, 0, (LPBYTE)&dirty, &len)))
707 /* FIXME: what does SETUPX.DLL do in this case ? */
708 MESSAGE("Warning: another program using SETUPX is already running ! Failed.\n");
712 if (RegSetValueExA(hKeyConflict, "Dirty", 0, REG_BINARY, (LPBYTE)&dirty, 1))
715 if (!(RegQueryValueExA(hKeyConflict, "BackupDirectory", NULL, 0, (LPBYTE)BackupDir, &len)))
716 strcpy(BackupDir, "VCM");
718 /* create C:\WINDOWS\[BackupDir] and set registry key to it */
719 GetWindowsDirectoryA(buf, 256);
721 strcat(buf, BackupDir);
722 if (!(CreateDirectoryA(buf, NULL)))
724 if (RegSetValueExA(hKeyConflict, "BackupDirectory", 0, REG_SZ, (LPBYTE)buf, strlen(buf)+1))
726 RegCloseKey(hKeyConflict);
731 /***********************************************************************
732 * vcpUICallbackProc (SETUPX.213)
734 RETERR16 WINAPI vcpUICallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
735 LPARAM lParam, LPARAM lParamRef)
737 static int count = 0;
738 RETERR16 res = VCPN_OK, cbres;
741 FIXME("(%p, %04x, %04lx, %08lx, %08lx) - semi-stub\n",
742 lpvObj, uMsg, wParam, lParam, lParamRef);
746 /* unused messages, it seems */
747 case VCPM_DISKPREPINFO:
749 case VCPM_FILENEEDED:
751 case VCPM_NODECREATE:
752 case VCPM_NODEACCEPT:
754 case VCPM_VSTATCLOSESTART:
755 case VCPM_VSTATPATHCHECKSTART:
756 case VCPM_VSTATPATHCHECKEND:
762 case VCPM_NODECOMPARE:
763 res = VCP_UI_NodeCompare((LPVIRTNODE)lpvObj, (LPVIRTNODE)lParam);
767 case VCPM_VSTATWRITE:
768 cbres = VCP_Callback(&vcp_status, VCPM_DISKPREPINFO, 0, 0, VCP_MsgRef);
770 case VCPM_VSTATCLOSEEND:
771 RegCloseKey(hKeyFiles);
772 RegCloseKey(hKeyRename);
773 RegDeleteKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT);
775 case VCPM_VSTATCOPYSTART:
776 res = VCP_UI_CopyStart();
778 case VCPM_VSTATCOPYEND:
779 if (hDlgCopy) DestroyWindow(hDlgCopy);
782 FIXME("unhandled msg 0x%04x\n", uMsg);