msi: If the UserData product key exists, but the user product key doesn't, the produc...
[wine/hacks.git] / dlls / setupapi / virtcopy.c
blobcceca3cdef73b374ad899f6cdf042b88c160e8bb
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 HINSTANCE SETUPAPI_hInstance;
48 static WORD VCP_Callback( LPVOID obj, UINT16 msg, WPARAM16 wParam, LPARAM lParam, LPARAM lParamRef )
50 WORD args[8];
51 DWORD ret = OK;
52 if (VCP_Proc)
54 args[7] = HIWORD(obj);
55 args[6] = LOWORD(obj);
56 args[5] = msg;
57 args[4] = wParam;
58 args[3] = HIWORD(lParam);
59 args[2] = LOWORD(lParam);
60 args[1] = HIWORD(lParamRef);
61 args[0] = LOWORD(lParamRef);
62 WOWCallback16Ex( (DWORD)VCP_Proc, WCB16_PASCAL, sizeof(args), args, &ret );
64 return (WORD)ret;
67 /****************************** VHSTR management ******************************/
70 * This is a totally braindead implementation for now;
71 * I don't care about speed at all ! Size and implementation time
72 * is much more important IMHO. I could have created some sophisticated
73 * tree structure, but... what the hell ! :-)
75 typedef struct {
76 DWORD refcount;
77 LPCSTR pStr;
78 } VHSTR_STRUCT;
80 static VHSTR_STRUCT **vhstrlist = NULL;
81 static VHSTR vhstr_alloc = 0;
83 #define VALID_VHSTR(x) ((x < vhstr_alloc) && (vhstrlist[x]) && (vhstrlist[x]->refcount))
85 /***********************************************************************
86 * vsmStringAdd (SETUPX.207)
88 VHSTR WINAPI vsmStringAdd16(LPCSTR lpszName)
90 VHSTR n;
91 VHSTR index = 0xffff;
92 HANDLE heap;
93 LPSTR str;
95 TRACE("add string '%s'\n", lpszName);
96 /* search whether string already inserted */
97 TRACE("searching for existing string...\n");
98 for (n = 0; n < vhstr_alloc; n++)
100 if ((vhstrlist[n]) && (vhstrlist[n]->refcount))
102 TRACE("checking item: %d\n", n);
103 if (!strcmp(vhstrlist[n]->pStr, lpszName))
105 TRACE("found\n");
106 vhstrlist[n]->refcount++;
107 return n;
112 /* hmm, not found yet, let's insert it */
113 TRACE("inserting item\n");
114 for (n = 0; n < vhstr_alloc; n++)
116 if ((!(vhstrlist[n])) || (!(vhstrlist[n]->refcount)))
118 index = n;
119 break;
122 heap = GetProcessHeap();
123 if (n == vhstr_alloc) /* hmm, no free index found yet */
125 index = vhstr_alloc;
126 vhstr_alloc += 20;
128 if (vhstrlist)
129 vhstrlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, vhstrlist,
130 sizeof(VHSTR_STRUCT *) * vhstr_alloc);
131 else
132 vhstrlist = HeapAlloc(heap, HEAP_ZERO_MEMORY,
133 sizeof(VHSTR_STRUCT *) * vhstr_alloc);
135 if (index == 0xffff)
136 return 0xffff; /* failure */
137 if (!vhstrlist[index])
138 vhstrlist[index] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VHSTR_STRUCT));
139 vhstrlist[index]->refcount = 1;
140 str = HeapAlloc(heap, 0, strlen(lpszName)+1);
141 strcpy(str, lpszName);
142 vhstrlist[index]->pStr = str;
143 return index;
146 /***********************************************************************
147 * vsmStringDelete (SETUPX.206)
149 INT16 WINAPI vsmStringDelete16(VHSTR vhstr)
151 if (VALID_VHSTR(vhstr))
153 vhstrlist[vhstr]->refcount--;
154 if (!vhstrlist[vhstr]->refcount)
156 HeapFree(GetProcessHeap(), 0, (LPSTR)vhstrlist[vhstr]->pStr);
157 vhstrlist[vhstr]->pStr = NULL;
159 return VCPN_OK;
162 /* string not found */
163 return VCPN_FAIL;
167 * vsmStringFind() - not exported from a standard SETUPX.DLL, it seems
169 VHSTR WINAPI vsmStringFind16(LPCSTR lpszName)
171 WORD n;
172 for (n = 0; n < vhstr_alloc; n++)
173 if ((vhstrlist[n]) && (vhstrlist[n]->refcount) && (!strcmp(vhstrlist[n]->pStr, lpszName)))
174 return n;
175 return 0xffff;
178 /***********************************************************************
179 * vsmGetStringName (SETUPX.205)
181 * Pretty correct, I guess
183 INT16 WINAPI vsmGetStringName16(VHSTR vhstr, LPSTR lpszBuffer, int cbBuffer)
185 if (VALID_VHSTR(vhstr))
187 int len = strlen(vhstrlist[vhstr]->pStr)+1;
188 if (cbBuffer >= len)
190 if (lpszBuffer)
191 strcpy(lpszBuffer, vhstrlist[vhstr]->pStr);
192 return len;
195 return VCPN_FAIL;
198 /***********************************************************************
199 * vsmStringCompare (not exported from a standard SETUPX.DLL, it seems)
201 INT16 WINAPI vsmStringCompare16(VHSTR vhstrA, VHSTR vhstrB)
203 if ((!VALID_VHSTR(vhstrA)) || (!VALID_VHSTR(vhstrB)))
204 return VCPN_FAIL; /* correct ? */
205 return strcmp(vhstrlist[vhstrA]->pStr, vhstrlist[vhstrB]->pStr);
208 /***********************************************************************
209 * vsmGetStringRawName (SETUPX.208)
211 LPCSTR WINAPI vsmGetStringRawName16(VHSTR vhstr)
213 return (VALID_VHSTR(vhstr)) ? vhstrlist[vhstr]->pStr : NULL;
217 /***************************** VIRTNODE management ****************************/
218 static LPVIRTNODE *pvnlist = NULL;
219 static DWORD vn_num = 0;
220 static DWORD vn_last = 0;
222 static RETERR16 VCP_VirtnodeCreate(LPVCPFILESPEC vfsSrc, LPVCPFILESPEC vfsDst, WORD fl, LPARAM lParam, LPEXPANDVTBL lpExpandVtbl)
224 HANDLE heap;
225 LPVIRTNODE lpvn;
226 RETERR16 cbres;
228 while (vn_last < vn_num)
230 if (pvnlist[vn_last] == NULL)
231 break;
232 vn_last++;
234 heap = GetProcessHeap();
235 if (vn_last == vn_num)
237 vn_num += 20;
238 if (pvnlist)
239 pvnlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, pvnlist,
240 sizeof(LPVIRTNODE *) * vn_num);
241 else
242 pvnlist = HeapAlloc(heap, HEAP_ZERO_MEMORY,
243 sizeof(LPVIRTNODE *) * vn_num);
245 pvnlist[vn_last] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VIRTNODE));
246 lpvn = pvnlist[vn_last];
247 vn_last++;
249 lpvn->cbSize = sizeof(VIRTNODE);
251 if (vfsSrc)
252 memcpy(&lpvn->vfsSrc, vfsSrc, sizeof(VCPFILESPEC));
254 if (vfsDst)
255 memcpy(&lpvn->vfsDst, vfsDst, sizeof(VCPFILESPEC));
257 lpvn->fl = fl;
258 lpvn->lParam = lParam;
259 lpvn->lpExpandVtbl = lpExpandVtbl;
261 lpvn->vhstrDstFinalName = 0xffff; /* FIXME: what is this ? */
263 cbres = VCP_Callback(lpvn, VCPM_NODECREATE, 0, 0, VCP_MsgRef);
264 lpvn->fl |= VFNL_CREATED;
265 cbres = VCP_Callback(lpvn, VCPM_NODEACCEPT, 0, 0, VCP_MsgRef);
267 return OK;
270 #if 0
271 static BOOL VCP_VirtnodeDelete(LPVIRTNODE lpvnDel)
273 DWORD n;
274 RETERR16 cbres;
276 for (n = 0; n < vn_last; n++)
278 if (pvnlist[n] == lpvnDel)
280 cbres = VCP_Callback(lpvnDel, VCPM_NODEDESTROY, 0, 0, VCP_MsgRef);
281 HeapFree(GetProcessHeap(), 0, lpvnDel);
282 pvnlist[n] = NULL;
283 return TRUE;
286 return FALSE;
288 #endif
290 /***********************************************************************
291 * VcpOpen (SETUPX.200)
293 * Sets up a virtual copy operation.
294 * This means that functions such as GenInstall()
295 * create a VIRTNODE struct for every file to be touched in a .INF file
296 * instead of actually touching the file.
297 * The actual copy/move/rename gets started when VcpClose or
298 * VcpFlush is called; several different callbacks are made
299 * (copy, rename, open, close, version conflicts, ...) on every file copied.
301 RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef)
303 TRACE("(%p, %08lx)\n", vifproc, lparamMsgRef);
304 if (VCP_opened)
305 return ERR_VCP_BUSY;
307 VCP_Proc = (FARPROC16)vifproc;
308 VCP_MsgRef = lparamMsgRef;
310 /* load SETUPAPI needed for dialog resources etc. */
311 SETUPAPI_hInstance = GetModuleHandleA("setupapi.dll");
312 if (!SETUPAPI_hInstance)
314 ERR("Could not load sibling setupapi.dll\n");
315 return ERR_VCP_NOMEM;
317 VCP_opened = TRUE;
318 return OK;
321 /***********************************************************************
322 * VcpQueueCopy [SETUPX.13]
324 * lpExpandVtbl seems to be deprecated.
325 * fl are the CNFL_xxx and VNFL_xxx flags.
326 * lParam are the VNLP_xxx flags.
328 RETERR16 WINAPI VcpQueueCopy16(
329 LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
330 LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
331 LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
332 LPEXPANDVTBL lpExpandVtbl,
333 WORD fl, LPARAM lParam
336 VCPFILESPEC vfsSrc, vfsDst;
338 if (!VCP_opened)
339 return ERR_VCP_NOTOPEN;
341 TRACE("srcdir: %s, srcfile: %s, dstdir: %s, dstfile: %s\n",
342 lpszSrcDir, lpszSrcFileName, lpszDstDir, lpszDstFileName);
344 TRACE("ldidSrc == %d, ldidDst == %d\n", ldidSrc, ldidDst);
346 vfsSrc.ldid = ldidSrc;
347 vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
348 vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
350 vfsDst.ldid = ldidDst;
351 vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
352 vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
354 return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, fl, lParam,
355 lpExpandVtbl);
358 /***********************************************************************
359 * VcpQueueDelete [SETUPX.17]
361 * Is lParamRef the same as lParam in VcpQueueCopy ?
362 * Damn docu !! Err... which docu ?
364 RETERR16 WINAPI VcpQueueDelete16(
365 LPCSTR lpszDstFileName,
366 LPCSTR lpszDstDir,
367 LOGDISKID16 ldidDst,
368 LPARAM lParamRef
371 VCPFILESPEC vfsDst;
373 if (!VCP_opened)
374 return ERR_VCP_NOTOPEN;
376 vfsDst.ldid = ldidDst;
377 vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
378 vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
380 return VCP_VirtnodeCreate(NULL, &vfsDst, VNFL_DELETE, lParamRef, 0);
383 /***********************************************************************
384 * VcpQueueRename [SETUPX.204]
387 RETERR16 WINAPI VcpQueueRename16(
388 LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
389 LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
390 LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
391 LPARAM lParam
394 VCPFILESPEC vfsSrc, vfsDst;
396 if (!VCP_opened)
397 return ERR_VCP_NOTOPEN;
399 vfsSrc.ldid = ldidSrc;
400 vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
401 vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
403 vfsDst.ldid = ldidDst;
404 vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
405 vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
407 return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, VNFL_RENAME, lParam,
411 /***********************************************************************
412 * VcpEnumFiles (SETUPX.@)
414 INT16 WINAPI VcpEnumFiles(VCPENUMPROC vep, LPARAM lParamRef)
416 WORD n;
418 for (n = 0; n < vn_last; n++)
419 vep(pvnlist[n], lParamRef);
421 return 0; /* FIXME: return value ? */
424 /***********************************************************************
425 * VcpExplain (SETUPX.411)
427 LPCSTR WINAPI VcpExplain16(LPVIRTNODE lpVn, DWORD dwWhat)
429 static char buffer[MAX_PATH]; /* FIXME: is this how it's done ? */
430 buffer[0] = '\0';
431 switch (dwWhat)
433 case VCPEX_SRC_FULL:
434 case VCPEX_DST_FULL:
436 LPVCPFILESPEC lpvfs =
437 (dwWhat == VCPEX_SRC_FULL) ? &lpVn->vfsSrc : &lpVn->vfsDst;
439 /* if we have an ldid, use it, otherwise use the string */
440 /* from the vhstrlist array */
441 if (lpvfs->ldid != 0xffff)
442 CtlGetLddPath16(lpvfs->ldid, buffer);
443 else
444 strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrDir));
446 strcat(buffer, "\\");
447 strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrFileName));
449 break;
450 default:
451 FIXME("%d unimplemented !\n", dwWhat);
452 strcpy(buffer, "Unknown error");
453 break;
455 return buffer;
458 static RETERR16 VCP_CheckPaths(void)
460 DWORD n;
461 LPVIRTNODE lpvn;
462 RETERR16 cbres;
464 cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKSTART, 0, 0, VCP_MsgRef);
465 for (n = 0; n < vn_num; n++)
467 lpvn = pvnlist[n];
468 if (!lpvn) continue;
469 /* FIXME: check paths of all VIRTNODEs here ! */
470 cbres = VCP_Callback(&lpvn->vfsDst, VCPM_CHECKPATH, 0, (DWORD)lpvn, VCP_MsgRef);
472 cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKEND, 0, 0, VCP_MsgRef);
473 return OK;
476 static RETERR16 VCP_CopyFiles(void)
478 char fn_src[MAX_PATH], fn_dst[MAX_PATH];
479 RETERR16 res = OK, cbres;
480 DWORD n;
481 LPVIRTNODE lpvn;
483 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYSTART, 0, 0, VCP_MsgRef);
484 for (n = 0; n < vn_num; n++)
486 lpvn = pvnlist[n];
487 if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_COPY)) continue;
488 /* FIXME: need to send VCPM_VSTATNEWDISK notification sometimes */
489 strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
490 strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
491 /* FIXME: what is this VCPM_VSTATWRITE here for ?
492 * I guess it's to signal successful destination file creation */
493 cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
495 /* FIXME: need to do the file copy in small chunks for notifications */
496 TRACE("copying '%s' to '%s'\n", fn_src, fn_dst);
497 /* perform the file copy */
498 if (!(CopyFileA(fn_src, fn_dst,
499 (lpvn->fl & VNLP_COPYIFEXISTS) ? FALSE : TRUE )))
501 ERR("error copying, src: %s -> dst: %s\n", fn_src, fn_dst);
502 res = ERR_VCP_IOFAIL;
505 vcp_status.prgFileRead.dwSoFar++;
506 cbres = VCP_Callback(&vcp_status, VCPM_VSTATREAD, 0, 0, VCP_MsgRef);
507 vcp_status.prgFileWrite.dwSoFar++;
508 cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
511 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYEND, 0, 0, VCP_MsgRef);
512 return res;
515 /***********************************************************************
516 * VcpFlush - internal (not exported), but documented
518 * VNFL_NOW is used for VcpFlush.
520 RETERR16 VcpFlush16(WORD fl, LPCSTR lpszBackupDest)
522 return OK;
525 /***********************************************************************
526 * VcpClose (SETUPX.201)
528 * Does callbacks (-> vifproc) with VCPM_VSTATCLOSESTART,
529 * VCPM_VSTATCLOSEEND.
531 * fl gets VCPFL_xxx flags to indicate what to do with the
532 * VIRTNODEs (files to mess with) created by e.g. GenInstall()
534 RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest)
536 RETERR16 res = OK;
537 WORD cbres = VCPN_PROCEED;
539 TRACE("(%04x, '%s')\n", fl, lpszBackupDest);
541 /* FIXME: needs to sort virtnodes in case VCPFL_INSPECIFIEDORDER
542 * is not set. This is done by VCP_Callback(VCPM_NODECOMPARE) */
544 TRACE("#1\n");
545 memset(&vcp_status, 0, sizeof(VCPSTATUS));
546 /* yes, vcp_status.cbSize is 0 ! */
547 TRACE("#2\n");
548 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSESTART, 0, 0, VCP_MsgRef);
549 TRACE("#3\n");
551 res = VCP_CheckPaths();
552 TRACE("#4\n");
553 if (res != OK)
554 return res; /* is this ok ? */
555 VCP_CopyFiles();
557 TRACE("#5\n");
558 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSEEND, 0, 0, VCP_MsgRef);
559 TRACE("#6\n");
560 VCP_Proc = NULL;
561 VCP_opened = FALSE;
562 return OK;
565 #if 0
566 static RETERR16 VCP_RenameFiles(void)
568 char fn_src[MAX_PATH], fn_dst[MAX_PATH];
569 RETERR16 res = OK, cbres;
570 DWORD n;
571 LPVIRTNODE lpvn;
573 cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMESTART, 0, 0, VCP_MsgRef);
574 for (n = 0; n < vn_num; n++)
576 lpvn = pvnlist[n];
577 if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_RENAME)) continue;
578 strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
579 strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
580 cbres = VCP_Callback(&lpvn->vfsDst, VCPM_FILEOPENOUT, 0, (LPARAM)lpvn, VCP_MsgRef);
581 if (!(MoveFileExA(fn_src, fn_dst, MOVEFILE_REPLACE_EXISTING)))
582 res = ERR_VCP_IOFAIL;
583 else
584 VCP_VirtnodeDelete(lpvn);
586 cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMEEND, 0, 0, VCP_MsgRef);
587 return res;
589 #endif
591 /***********************************************************************
592 * vcpDefCallbackProc (SETUPX.202)
594 RETERR16 WINAPI vcpDefCallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
595 LPARAM lParam, LPARAM lParamRef)
597 static int count = 0;
598 if (count < 10)
599 FIXME("(%p, %04x, %04lx, %08lx, %08lx) - what to do here ?\n",
600 lpvObj, uMsg, wParam, lParam, lParamRef);
601 count++;
602 return OK;
605 /********************* point-and-click stuff from here ***********************/
607 static HWND hDlgCopy = 0;
608 static HKEY hKeyFiles = 0, hKeyRename = 0, hKeyConflict = 0;
609 static char BackupDir[12];
611 static INT_PTR CALLBACK VCP_UI_FileCopyDlgProc(HWND hWndDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
613 INT_PTR retval = FALSE;
615 if (iMsg == WM_INITDIALOG)
617 ShowWindow(hWndDlg, SW_SHOWNORMAL);
618 UpdateWindow(hWndDlg);
619 retval = TRUE;
621 return retval;
624 static BOOL VCP_UI_GetDialogTemplate(LPCVOID *template32)
626 HRSRC hResInfo;
627 HGLOBAL hDlgTmpl32;
629 if (!(hResInfo = FindResourceA(SETUPAPI_hInstance, MAKEINTRESOURCEA(COPYFILEDLGORD), (LPSTR)RT_DIALOG)))
630 return FALSE;
631 if (!(hDlgTmpl32 = LoadResource(SETUPAPI_hInstance, hResInfo )) ||
632 !(*template32 = LockResource( hDlgTmpl32 )))
633 return FALSE;
634 return TRUE;
637 static LRESULT WINAPI
638 VCP_UI_FileCopyWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
640 if (uMsg != WM_CREATE)
641 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
643 switch (uMsg)
645 case WM_CREATE:
646 return 0;
647 default:
648 FIXME("%04x: unhandled.\n", uMsg);
651 return 0;
654 static void VCP_UI_RegisterProgressClass(void)
656 static BOOL registered = FALSE;
657 WNDCLASSA wndClass;
659 if (registered)
660 return;
662 registered = TRUE;
663 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
664 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
665 wndClass.lpfnWndProc = VCP_UI_FileCopyWndProc;
666 wndClass.cbClsExtra = 0;
667 wndClass.cbWndExtra = 0;
668 wndClass.hCursor = LoadCursorA (0, (LPSTR)IDC_ARROW);
669 wndClass.hbrBackground = NULL;
670 wndClass.lpszClassName = "setupx_progress";
672 RegisterClassA (&wndClass);
675 static RETERR16 VCP_UI_NodeCompare(LPVIRTNODE vn1, LPVIRTNODE vn2)
677 LPCSTR file1, file2;
678 file1 = vsmGetStringRawName16(vn1->vfsSrc.vhstrFileName);
679 file2 = vsmGetStringRawName16(vn2->vfsSrc.vhstrFileName);
680 return (RETERR16)strcmp(file1, file2);
683 static RETERR16 VCP_UI_CopyStart(void)
685 LPCVOID template32;
686 char buf[256]; /* plenty */
687 BOOL dirty;
688 DWORD len;
690 /* FIXME: should be registered at DLL startup instead */
691 VCP_UI_RegisterProgressClass();
692 if (!(VCP_UI_GetDialogTemplate(&template32)))
693 return VCPN_FAIL;
695 if (vn_num > 10) /* hack */
697 hDlgCopy = CreateDialogIndirectParamA(SETUPAPI_hInstance, template32, 0,
698 VCP_UI_FileCopyDlgProc, 0);
699 if (!hDlgCopy)
700 return VCPN_FAIL;
701 SetDlgItemTextA(hDlgCopy, SOURCESTRORD, "Scanning ...");
702 SetDlgItemTextA(hDlgCopy, DESTSTRORD, "NOT_IMPLEMENTED_YET");
704 strcpy(buf, REG_INSTALLEDFILES);
705 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyFiles))
706 return VCPN_FAIL;
707 strcat(buf, REGPART_RENAME);
708 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyRename))
709 return VCPN_FAIL;
710 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT, &hKeyConflict))
711 return VCPN_FAIL;
712 len = 1;
713 if (!(RegQueryValueExA(hKeyConflict, "Dirty", NULL, 0, (LPBYTE)&dirty, &len)))
715 /* FIXME: what does SETUPX.DLL do in this case ? */
716 MESSAGE("Warning: another program using SETUPX is already running ! Failed.\n");
717 return VCPN_FAIL;
719 dirty = TRUE;
720 if (RegSetValueExA(hKeyConflict, "Dirty", 0, REG_BINARY, (LPBYTE)&dirty, 1))
721 return VCPN_FAIL;
722 len = 12;
723 if (!(RegQueryValueExA(hKeyConflict, "BackupDirectory", NULL, 0, (LPBYTE)BackupDir, &len)))
724 strcpy(BackupDir, "VCM");
726 /* create C:\WINDOWS\[BackupDir] and set registry key to it */
727 GetWindowsDirectoryA(buf, 256);
728 strcat(buf, "\\");
729 strcat(buf, BackupDir);
730 if (!(CreateDirectoryA(buf, NULL)))
731 return VCPN_FAIL;
732 if (RegSetValueExA(hKeyConflict, "BackupDirectory", 0, REG_SZ, (LPBYTE)buf, strlen(buf)+1))
733 return VCPN_FAIL;
734 RegCloseKey(hKeyConflict);
736 return VCPN_OK;
739 /***********************************************************************
740 * vcpUICallbackProc (SETUPX.213)
742 RETERR16 WINAPI vcpUICallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
743 LPARAM lParam, LPARAM lParamRef)
745 static int count = 0;
746 RETERR16 res = VCPN_OK, cbres;
748 if (count < 5)
749 FIXME("(%p, %04x, %04lx, %08lx, %08lx) - semi-stub\n",
750 lpvObj, uMsg, wParam, lParam, lParamRef);
751 count++;
752 switch (uMsg)
754 /* unused messages, it seems */
755 case VCPM_DISKPREPINFO:
757 case VCPM_FILENEEDED:
759 case VCPM_NODECREATE:
760 case VCPM_NODEACCEPT:
762 case VCPM_VSTATCLOSESTART:
763 case VCPM_VSTATPATHCHECKSTART:
764 case VCPM_VSTATPATHCHECKEND:
766 case VCPM_CHECKPATH:
767 break;
769 /* the real stuff */
770 case VCPM_NODECOMPARE:
771 res = VCP_UI_NodeCompare((LPVIRTNODE)lpvObj, (LPVIRTNODE)lParam);
772 break;
773 case VCPM_VSTATREAD:
774 break;
775 case VCPM_VSTATWRITE:
776 cbres = VCP_Callback(&vcp_status, VCPM_DISKPREPINFO, 0, 0, VCP_MsgRef);
777 break;
778 case VCPM_VSTATCLOSEEND:
779 RegCloseKey(hKeyFiles);
780 RegCloseKey(hKeyRename);
781 RegDeleteKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT);
782 break;
783 case VCPM_VSTATCOPYSTART:
784 res = VCP_UI_CopyStart();
785 break;
786 case VCPM_VSTATCOPYEND:
787 if (hDlgCopy) DestroyWindow(hDlgCopy);
788 break;
789 default:
790 FIXME("unhandled msg 0x%04x\n", uMsg);
792 return res;