push 6c2bed22d4a356b01aae243fbf554b5dba1af534
[wine/hacks.git] / dlls / setupapi / virtcopy.c
blob2506a6a29bd7f595673d731bffd7c680bb9edb1b
1 /*
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.
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"
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 )
48 WORD args[8];
49 DWORD ret = OK;
50 if (VCP_Proc)
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 );
62 return (WORD)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 ! :-)
73 typedef struct {
74 DWORD refcount;
75 LPCSTR pStr;
76 } VHSTR_STRUCT;
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)
88 VHSTR n;
89 VHSTR index = 0xffff;
90 HANDLE heap;
91 LPSTR str;
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))
103 TRACE("found\n");
104 vhstrlist[n]->refcount++;
105 return n;
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)))
116 index = n;
117 break;
120 heap = GetProcessHeap();
121 if (n == vhstr_alloc) /* hmm, no free index found yet */
123 index = vhstr_alloc;
124 vhstr_alloc += 20;
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);
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;
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;
157 return VCPN_OK;
160 /* string not found */
161 return VCPN_FAIL;
164 /***********************************************************************
165 * vsmGetStringName (SETUPX.205)
167 * Pretty correct, I guess
169 INT16 WINAPI vsmGetStringName16(VHSTR vhstr, LPSTR lpszBuffer, int cbBuffer)
171 if (VALID_VHSTR(vhstr))
173 int len = strlen(vhstrlist[vhstr]->pStr)+1;
174 if (cbBuffer >= len)
176 if (lpszBuffer)
177 strcpy(lpszBuffer, vhstrlist[vhstr]->pStr);
178 return len;
181 return VCPN_FAIL;
184 /***********************************************************************
185 * vsmGetStringRawName (SETUPX.208)
187 LPCSTR WINAPI vsmGetStringRawName16(VHSTR vhstr)
189 return (VALID_VHSTR(vhstr)) ? vhstrlist[vhstr]->pStr : NULL;
193 /***************************** VIRTNODE management ****************************/
194 static LPVIRTNODE *pvnlist = NULL;
195 static DWORD vn_num = 0;
196 static DWORD vn_last = 0;
198 static RETERR16 VCP_VirtnodeCreate(const VCPFILESPEC *vfsSrc, const VCPFILESPEC *vfsDst,
199 WORD fl, LPARAM lParam, LPEXPANDVTBL lpExpandVtbl)
201 HANDLE heap;
202 LPVIRTNODE lpvn;
203 RETERR16 cbres;
205 while (vn_last < vn_num)
207 if (pvnlist[vn_last] == NULL)
208 break;
209 vn_last++;
211 heap = GetProcessHeap();
212 if (vn_last == vn_num)
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);
222 pvnlist[vn_last] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VIRTNODE));
223 lpvn = pvnlist[vn_last];
224 vn_last++;
226 lpvn->cbSize = sizeof(VIRTNODE);
228 if (vfsSrc)
229 lpvn->vfsSrc = *vfsSrc;
231 if (vfsDst)
232 lpvn->vfsDst = *vfsDst;
234 lpvn->fl = fl;
235 lpvn->lParam = lParam;
236 lpvn->lpExpandVtbl = lpExpandVtbl;
238 lpvn->vhstrDstFinalName = 0xffff; /* FIXME: what is this ? */
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);
244 return OK;
247 /***********************************************************************
248 * VcpOpen (SETUPX.200)
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.
258 RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef)
260 TRACE("(%p, %08lx)\n", vifproc, lparamMsgRef);
261 if (VCP_opened)
262 return ERR_VCP_BUSY;
264 VCP_Proc = (FARPROC16)vifproc;
265 VCP_MsgRef = lparamMsgRef;
267 VCP_opened = TRUE;
268 return OK;
271 /***********************************************************************
272 * VcpQueueCopy [SETUPX.13]
274 * lpExpandVtbl seems to be deprecated.
275 * fl are the CNFL_xxx and VNFL_xxx flags.
276 * lParam are the VNLP_xxx flags.
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
286 VCPFILESPEC vfsSrc, vfsDst;
288 if (!VCP_opened)
289 return ERR_VCP_NOTOPEN;
291 TRACE("srcdir: %s, srcfile: %s, dstdir: %s, dstfile: %s\n",
292 lpszSrcDir, lpszSrcFileName, lpszDstDir, lpszDstFileName);
294 TRACE("ldidSrc == %d, ldidDst == %d\n", ldidSrc, ldidDst);
296 vfsSrc.ldid = ldidSrc;
297 vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
298 vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
300 vfsDst.ldid = ldidDst;
301 vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
302 vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
304 return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, fl, lParam,
305 lpExpandVtbl);
308 /***********************************************************************
309 * VcpQueueDelete [SETUPX.17]
311 * Is lParamRef the same as lParam in VcpQueueCopy ?
312 * Damn docu !! Err... which docu ?
314 RETERR16 WINAPI VcpQueueDelete16(
315 LPCSTR lpszDstFileName,
316 LPCSTR lpszDstDir,
317 LOGDISKID16 ldidDst,
318 LPARAM lParamRef
321 VCPFILESPEC vfsDst;
323 if (!VCP_opened)
324 return ERR_VCP_NOTOPEN;
326 vfsDst.ldid = ldidDst;
327 vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
328 vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
330 return VCP_VirtnodeCreate(NULL, &vfsDst, VNFL_DELETE, lParamRef, 0);
333 /***********************************************************************
334 * VcpQueueRename [SETUPX.204]
337 RETERR16 WINAPI VcpQueueRename16(
338 LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
339 LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
340 LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
341 LPARAM lParam
344 VCPFILESPEC vfsSrc, vfsDst;
346 if (!VCP_opened)
347 return ERR_VCP_NOTOPEN;
349 vfsSrc.ldid = ldidSrc;
350 vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
351 vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
353 vfsDst.ldid = ldidDst;
354 vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
355 vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
357 return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, VNFL_RENAME, lParam,
361 /***********************************************************************
362 * VcpEnumFiles (SETUPX.@)
364 INT16 WINAPI VcpEnumFiles(VCPENUMPROC vep, LPARAM lParamRef)
366 WORD n;
368 for (n = 0; n < vn_last; n++)
369 vep(pvnlist[n], lParamRef);
371 return 0; /* FIXME: return value ? */
374 /***********************************************************************
375 * VcpExplain (SETUPX.411)
377 LPCSTR WINAPI VcpExplain16(LPVIRTNODE lpVn, DWORD dwWhat)
379 static char buffer[MAX_PATH]; /* FIXME: is this how it's done ? */
380 buffer[0] = '\0';
381 switch (dwWhat)
383 case VCPEX_SRC_FULL:
384 case VCPEX_DST_FULL:
386 LPVCPFILESPEC lpvfs =
387 (dwWhat == VCPEX_SRC_FULL) ? &lpVn->vfsSrc : &lpVn->vfsDst;
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));
396 strcat(buffer, "\\");
397 strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrFileName));
399 break;
400 default:
401 FIXME("%d unimplemented !\n", dwWhat);
402 strcpy(buffer, "Unknown error");
403 break;
405 return buffer;
408 static RETERR16 VCP_CheckPaths(void)
410 DWORD n;
411 LPVIRTNODE lpvn;
412 RETERR16 cbres;
414 cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKSTART, 0, 0, VCP_MsgRef);
415 for (n = 0; n < vn_num; n++)
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);
422 cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKEND, 0, 0, VCP_MsgRef);
423 return OK;
426 static RETERR16 VCP_CopyFiles(void)
428 char fn_src[MAX_PATH], fn_dst[MAX_PATH];
429 RETERR16 res = OK, cbres;
430 DWORD n;
431 LPVIRTNODE lpvn;
433 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYSTART, 0, 0, VCP_MsgRef);
434 for (n = 0; n < vn_num; n++)
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);
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 )))
451 ERR("error copying, src: %s -> dst: %s\n", fn_src, fn_dst);
452 res = ERR_VCP_IOFAIL;
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);
461 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYEND, 0, 0, VCP_MsgRef);
462 return res;
465 /***********************************************************************
466 * VcpClose (SETUPX.201)
468 * Does callbacks (-> vifproc) with VCPM_VSTATCLOSESTART,
469 * VCPM_VSTATCLOSEEND.
471 * fl gets VCPFL_xxx flags to indicate what to do with the
472 * VIRTNODEs (files to mess with) created by e.g. GenInstall()
474 RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest)
476 RETERR16 res = OK;
477 WORD cbres = VCPN_PROCEED;
479 TRACE("(%04x, '%s')\n", fl, lpszBackupDest);
481 /* FIXME: needs to sort VIRTNODEs in case VCPFL_INSPECIFIEDORDER
482 * is not set. This is done by VCP_Callback(VCPM_NODECOMPARE) */
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");
491 res = VCP_CheckPaths();
492 TRACE("#4\n");
493 if (res != OK)
494 return res; /* is this ok ? */
495 VCP_CopyFiles();
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;
505 /***********************************************************************
506 * vcpDefCallbackProc (SETUPX.202)
508 RETERR16 WINAPI vcpDefCallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
509 LPARAM lParam, LPARAM lParamRef)
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;
519 /********************* point-and-click stuff from here ***********************/
521 static HWND hDlgCopy = 0;
522 static HKEY hKeyFiles = 0, hKeyRename = 0, hKeyConflict = 0;
523 static char BackupDir[12];
525 static INT_PTR CALLBACK VCP_UI_FileCopyDlgProc(HWND hWndDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
527 INT_PTR retval = FALSE;
529 if (iMsg == WM_INITDIALOG)
531 ShowWindow(hWndDlg, SW_SHOWNORMAL);
532 UpdateWindow(hWndDlg);
533 retval = TRUE;
535 return retval;
538 static BOOL VCP_UI_GetDialogTemplate(LPCVOID *template32)
540 HRSRC hResInfo;
541 HGLOBAL hDlgTmpl32;
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;
551 static LRESULT WINAPI
552 VCP_UI_FileCopyWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
554 if (uMsg != WM_CREATE)
555 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
557 switch (uMsg)
559 case WM_CREATE:
560 return 0;
561 default:
562 FIXME("%04x: unhandled.\n", uMsg);
565 return 0;
568 static void VCP_UI_RegisterProgressClass(void)
570 static BOOL registered = FALSE;
571 WNDCLASSA wndClass;
573 if (registered)
574 return;
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";
586 RegisterClassA (&wndClass);
589 static RETERR16 VCP_UI_NodeCompare(LPVIRTNODE vn1, LPVIRTNODE vn2)
591 LPCSTR file1, file2;
592 file1 = vsmGetStringRawName16(vn1->vfsSrc.vhstrFileName);
593 file2 = vsmGetStringRawName16(vn2->vfsSrc.vhstrFileName);
594 return (RETERR16)strcmp(file1, file2);
597 static RETERR16 VCP_UI_CopyStart(void)
599 LPCVOID template32;
600 char buf[256]; /* plenty */
601 BOOL dirty;
602 DWORD len;
604 /* FIXME: should be registered at DLL startup instead */
605 VCP_UI_RegisterProgressClass();
606 if (!(VCP_UI_GetDialogTemplate(&template32)))
607 return VCPN_FAIL;
609 if (vn_num > 10) /* hack */
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");
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)))
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;
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");
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);
650 return VCPN_OK;
653 /***********************************************************************
654 * vcpUICallbackProc (SETUPX.213)
656 RETERR16 WINAPI vcpUICallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
657 LPARAM lParam, LPARAM lParamRef)
659 static int count = 0;
660 RETERR16 res = VCPN_OK, cbres;
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)
668 /* unused messages, it seems */
669 case VCPM_DISKPREPINFO:
671 case VCPM_FILENEEDED:
673 case VCPM_NODECREATE:
674 case VCPM_NODEACCEPT:
676 case VCPM_VSTATCLOSESTART:
677 case VCPM_VSTATPATHCHECKSTART:
678 case VCPM_VSTATPATHCHECKEND:
680 case VCPM_CHECKPATH:
681 break;
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);
706 return res;