crypt32: Fix some chain failures on Win9x/NT4.
[wine/multimedia.git] / dlls / setupapi / virtcopy.c
blob9dddc889da47ab85bb4c68a69a8cf5e66441cb92
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(const VCPFILESPEC *vfsSrc, const VCPFILESPEC *vfsDst,
223 WORD fl, LPARAM lParam, LPEXPANDVTBL lpExpandVtbl)
225 HANDLE heap;
226 LPVIRTNODE lpvn;
227 RETERR16 cbres;
229 while (vn_last < vn_num)
231 if (pvnlist[vn_last] == NULL)
232 break;
233 vn_last++;
235 heap = GetProcessHeap();
236 if (vn_last == vn_num)
238 vn_num += 20;
239 if (pvnlist)
240 pvnlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, pvnlist,
241 sizeof(LPVIRTNODE *) * vn_num);
242 else
243 pvnlist = HeapAlloc(heap, HEAP_ZERO_MEMORY,
244 sizeof(LPVIRTNODE *) * vn_num);
246 pvnlist[vn_last] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VIRTNODE));
247 lpvn = pvnlist[vn_last];
248 vn_last++;
250 lpvn->cbSize = sizeof(VIRTNODE);
252 if (vfsSrc)
253 lpvn->vfsSrc = *vfsSrc;
255 if (vfsDst)
256 lpvn->vfsDst = *vfsDst;
258 lpvn->fl = fl;
259 lpvn->lParam = lParam;
260 lpvn->lpExpandVtbl = lpExpandVtbl;
262 lpvn->vhstrDstFinalName = 0xffff; /* FIXME: what is this ? */
264 cbres = VCP_Callback(lpvn, VCPM_NODECREATE, 0, 0, VCP_MsgRef);
265 lpvn->fl |= VFNL_CREATED;
266 cbres = VCP_Callback(lpvn, VCPM_NODEACCEPT, 0, 0, VCP_MsgRef);
268 return OK;
271 #if 0
272 static BOOL VCP_VirtnodeDelete(LPVIRTNODE lpvnDel)
274 DWORD n;
275 RETERR16 cbres;
277 for (n = 0; n < vn_last; n++)
279 if (pvnlist[n] == lpvnDel)
281 cbres = VCP_Callback(lpvnDel, VCPM_NODEDESTROY, 0, 0, VCP_MsgRef);
282 HeapFree(GetProcessHeap(), 0, lpvnDel);
283 pvnlist[n] = NULL;
284 return TRUE;
287 return FALSE;
289 #endif
291 /***********************************************************************
292 * VcpOpen (SETUPX.200)
294 * Sets up a virtual copy operation.
295 * This means that functions such as GenInstall()
296 * create a VIRTNODE struct for every file to be touched in a .INF file
297 * instead of actually touching the file.
298 * The actual copy/move/rename gets started when VcpClose or
299 * VcpFlush is called; several different callbacks are made
300 * (copy, rename, open, close, version conflicts, ...) on every file copied.
302 RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef)
304 TRACE("(%p, %08lx)\n", vifproc, lparamMsgRef);
305 if (VCP_opened)
306 return ERR_VCP_BUSY;
308 VCP_Proc = (FARPROC16)vifproc;
309 VCP_MsgRef = lparamMsgRef;
311 /* load SETUPAPI needed for dialog resources etc. */
312 SETUPAPI_hInstance = GetModuleHandleA("setupapi.dll");
313 if (!SETUPAPI_hInstance)
315 ERR("Could not load sibling setupapi.dll\n");
316 return ERR_VCP_NOMEM;
318 VCP_opened = TRUE;
319 return OK;
322 /***********************************************************************
323 * VcpQueueCopy [SETUPX.13]
325 * lpExpandVtbl seems to be deprecated.
326 * fl are the CNFL_xxx and VNFL_xxx flags.
327 * lParam are the VNLP_xxx flags.
329 RETERR16 WINAPI VcpQueueCopy16(
330 LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
331 LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
332 LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
333 LPEXPANDVTBL lpExpandVtbl,
334 WORD fl, LPARAM lParam
337 VCPFILESPEC vfsSrc, vfsDst;
339 if (!VCP_opened)
340 return ERR_VCP_NOTOPEN;
342 TRACE("srcdir: %s, srcfile: %s, dstdir: %s, dstfile: %s\n",
343 lpszSrcDir, lpszSrcFileName, lpszDstDir, lpszDstFileName);
345 TRACE("ldidSrc == %d, ldidDst == %d\n", ldidSrc, ldidDst);
347 vfsSrc.ldid = ldidSrc;
348 vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
349 vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
351 vfsDst.ldid = ldidDst;
352 vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
353 vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
355 return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, fl, lParam,
356 lpExpandVtbl);
359 /***********************************************************************
360 * VcpQueueDelete [SETUPX.17]
362 * Is lParamRef the same as lParam in VcpQueueCopy ?
363 * Damn docu !! Err... which docu ?
365 RETERR16 WINAPI VcpQueueDelete16(
366 LPCSTR lpszDstFileName,
367 LPCSTR lpszDstDir,
368 LOGDISKID16 ldidDst,
369 LPARAM lParamRef
372 VCPFILESPEC vfsDst;
374 if (!VCP_opened)
375 return ERR_VCP_NOTOPEN;
377 vfsDst.ldid = ldidDst;
378 vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
379 vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
381 return VCP_VirtnodeCreate(NULL, &vfsDst, VNFL_DELETE, lParamRef, 0);
384 /***********************************************************************
385 * VcpQueueRename [SETUPX.204]
388 RETERR16 WINAPI VcpQueueRename16(
389 LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
390 LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
391 LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
392 LPARAM lParam
395 VCPFILESPEC vfsSrc, vfsDst;
397 if (!VCP_opened)
398 return ERR_VCP_NOTOPEN;
400 vfsSrc.ldid = ldidSrc;
401 vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
402 vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
404 vfsDst.ldid = ldidDst;
405 vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
406 vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
408 return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, VNFL_RENAME, lParam,
412 /***********************************************************************
413 * VcpEnumFiles (SETUPX.@)
415 INT16 WINAPI VcpEnumFiles(VCPENUMPROC vep, LPARAM lParamRef)
417 WORD n;
419 for (n = 0; n < vn_last; n++)
420 vep(pvnlist[n], lParamRef);
422 return 0; /* FIXME: return value ? */
425 /***********************************************************************
426 * VcpExplain (SETUPX.411)
428 LPCSTR WINAPI VcpExplain16(LPVIRTNODE lpVn, DWORD dwWhat)
430 static char buffer[MAX_PATH]; /* FIXME: is this how it's done ? */
431 buffer[0] = '\0';
432 switch (dwWhat)
434 case VCPEX_SRC_FULL:
435 case VCPEX_DST_FULL:
437 LPVCPFILESPEC lpvfs =
438 (dwWhat == VCPEX_SRC_FULL) ? &lpVn->vfsSrc : &lpVn->vfsDst;
440 /* if we have an ldid, use it, otherwise use the string */
441 /* from the vhstrlist array */
442 if (lpvfs->ldid != 0xffff)
443 CtlGetLddPath16(lpvfs->ldid, buffer);
444 else
445 strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrDir));
447 strcat(buffer, "\\");
448 strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrFileName));
450 break;
451 default:
452 FIXME("%d unimplemented !\n", dwWhat);
453 strcpy(buffer, "Unknown error");
454 break;
456 return buffer;
459 static RETERR16 VCP_CheckPaths(void)
461 DWORD n;
462 LPVIRTNODE lpvn;
463 RETERR16 cbres;
465 cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKSTART, 0, 0, VCP_MsgRef);
466 for (n = 0; n < vn_num; n++)
468 lpvn = pvnlist[n];
469 if (!lpvn) continue;
470 /* FIXME: check paths of all VIRTNODEs here ! */
471 cbres = VCP_Callback(&lpvn->vfsDst, VCPM_CHECKPATH, 0, (DWORD)lpvn, VCP_MsgRef);
473 cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKEND, 0, 0, VCP_MsgRef);
474 return OK;
477 static RETERR16 VCP_CopyFiles(void)
479 char fn_src[MAX_PATH], fn_dst[MAX_PATH];
480 RETERR16 res = OK, cbres;
481 DWORD n;
482 LPVIRTNODE lpvn;
484 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYSTART, 0, 0, VCP_MsgRef);
485 for (n = 0; n < vn_num; n++)
487 lpvn = pvnlist[n];
488 if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_COPY)) continue;
489 /* FIXME: need to send VCPM_VSTATNEWDISK notification sometimes */
490 strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
491 strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
492 /* FIXME: what is this VCPM_VSTATWRITE here for ?
493 * I guess it's to signal successful destination file creation */
494 cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
496 /* FIXME: need to do the file copy in small chunks for notifications */
497 TRACE("copying '%s' to '%s'\n", fn_src, fn_dst);
498 /* perform the file copy */
499 if (!(CopyFileA(fn_src, fn_dst,
500 (lpvn->fl & VNLP_COPYIFEXISTS) ? FALSE : TRUE )))
502 ERR("error copying, src: %s -> dst: %s\n", fn_src, fn_dst);
503 res = ERR_VCP_IOFAIL;
506 vcp_status.prgFileRead.dwSoFar++;
507 cbres = VCP_Callback(&vcp_status, VCPM_VSTATREAD, 0, 0, VCP_MsgRef);
508 vcp_status.prgFileWrite.dwSoFar++;
509 cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
512 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYEND, 0, 0, VCP_MsgRef);
513 return res;
516 /***********************************************************************
517 * VcpFlush - internal (not exported), but documented
519 * VNFL_NOW is used for VcpFlush.
521 RETERR16 VcpFlush16(WORD fl, LPCSTR lpszBackupDest)
523 return OK;
526 /***********************************************************************
527 * VcpClose (SETUPX.201)
529 * Does callbacks (-> vifproc) with VCPM_VSTATCLOSESTART,
530 * VCPM_VSTATCLOSEEND.
532 * fl gets VCPFL_xxx flags to indicate what to do with the
533 * VIRTNODEs (files to mess with) created by e.g. GenInstall()
535 RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest)
537 RETERR16 res = OK;
538 WORD cbres = VCPN_PROCEED;
540 TRACE("(%04x, '%s')\n", fl, lpszBackupDest);
542 /* FIXME: needs to sort VIRTNODEs in case VCPFL_INSPECIFIEDORDER
543 * is not set. This is done by VCP_Callback(VCPM_NODECOMPARE) */
545 TRACE("#1\n");
546 memset(&vcp_status, 0, sizeof(VCPSTATUS));
547 /* yes, vcp_status.cbSize is 0 ! */
548 TRACE("#2\n");
549 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSESTART, 0, 0, VCP_MsgRef);
550 TRACE("#3\n");
552 res = VCP_CheckPaths();
553 TRACE("#4\n");
554 if (res != OK)
555 return res; /* is this ok ? */
556 VCP_CopyFiles();
558 TRACE("#5\n");
559 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSEEND, 0, 0, VCP_MsgRef);
560 TRACE("#6\n");
561 VCP_Proc = NULL;
562 VCP_opened = FALSE;
563 return OK;
566 #if 0
567 static RETERR16 VCP_RenameFiles(void)
569 char fn_src[MAX_PATH], fn_dst[MAX_PATH];
570 RETERR16 res = OK, cbres;
571 DWORD n;
572 LPVIRTNODE lpvn;
574 cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMESTART, 0, 0, VCP_MsgRef);
575 for (n = 0; n < vn_num; n++)
577 lpvn = pvnlist[n];
578 if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_RENAME)) continue;
579 strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
580 strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
581 cbres = VCP_Callback(&lpvn->vfsDst, VCPM_FILEOPENOUT, 0, (LPARAM)lpvn, VCP_MsgRef);
582 if (!(MoveFileExA(fn_src, fn_dst, MOVEFILE_REPLACE_EXISTING)))
583 res = ERR_VCP_IOFAIL;
584 else
585 VCP_VirtnodeDelete(lpvn);
587 cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMEEND, 0, 0, VCP_MsgRef);
588 return res;
590 #endif
592 /***********************************************************************
593 * vcpDefCallbackProc (SETUPX.202)
595 RETERR16 WINAPI vcpDefCallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
596 LPARAM lParam, LPARAM lParamRef)
598 static int count = 0;
599 if (count < 10)
600 FIXME("(%p, %04x, %04lx, %08lx, %08lx) - what to do here ?\n",
601 lpvObj, uMsg, wParam, lParam, lParamRef);
602 count++;
603 return OK;
606 /********************* point-and-click stuff from here ***********************/
608 static HWND hDlgCopy = 0;
609 static HKEY hKeyFiles = 0, hKeyRename = 0, hKeyConflict = 0;
610 static char BackupDir[12];
612 static INT_PTR CALLBACK VCP_UI_FileCopyDlgProc(HWND hWndDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
614 INT_PTR retval = FALSE;
616 if (iMsg == WM_INITDIALOG)
618 ShowWindow(hWndDlg, SW_SHOWNORMAL);
619 UpdateWindow(hWndDlg);
620 retval = TRUE;
622 return retval;
625 static BOOL VCP_UI_GetDialogTemplate(LPCVOID *template32)
627 HRSRC hResInfo;
628 HGLOBAL hDlgTmpl32;
630 if (!(hResInfo = FindResourceA(SETUPAPI_hInstance, MAKEINTRESOURCEA(COPYFILEDLGORD), (LPSTR)RT_DIALOG)))
631 return FALSE;
632 if (!(hDlgTmpl32 = LoadResource(SETUPAPI_hInstance, hResInfo )) ||
633 !(*template32 = LockResource( hDlgTmpl32 )))
634 return FALSE;
635 return TRUE;
638 static LRESULT WINAPI
639 VCP_UI_FileCopyWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
641 if (uMsg != WM_CREATE)
642 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
644 switch (uMsg)
646 case WM_CREATE:
647 return 0;
648 default:
649 FIXME("%04x: unhandled.\n", uMsg);
652 return 0;
655 static void VCP_UI_RegisterProgressClass(void)
657 static BOOL registered = FALSE;
658 WNDCLASSA wndClass;
660 if (registered)
661 return;
663 registered = TRUE;
664 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
665 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
666 wndClass.lpfnWndProc = VCP_UI_FileCopyWndProc;
667 wndClass.cbClsExtra = 0;
668 wndClass.cbWndExtra = 0;
669 wndClass.hCursor = LoadCursorA (0, (LPSTR)IDC_ARROW);
670 wndClass.hbrBackground = NULL;
671 wndClass.lpszClassName = "setupx_progress";
673 RegisterClassA (&wndClass);
676 static RETERR16 VCP_UI_NodeCompare(LPVIRTNODE vn1, LPVIRTNODE vn2)
678 LPCSTR file1, file2;
679 file1 = vsmGetStringRawName16(vn1->vfsSrc.vhstrFileName);
680 file2 = vsmGetStringRawName16(vn2->vfsSrc.vhstrFileName);
681 return (RETERR16)strcmp(file1, file2);
684 static RETERR16 VCP_UI_CopyStart(void)
686 LPCVOID template32;
687 char buf[256]; /* plenty */
688 BOOL dirty;
689 DWORD len;
691 /* FIXME: should be registered at DLL startup instead */
692 VCP_UI_RegisterProgressClass();
693 if (!(VCP_UI_GetDialogTemplate(&template32)))
694 return VCPN_FAIL;
696 if (vn_num > 10) /* hack */
698 hDlgCopy = CreateDialogIndirectParamA(SETUPAPI_hInstance, template32, 0,
699 VCP_UI_FileCopyDlgProc, 0);
700 if (!hDlgCopy)
701 return VCPN_FAIL;
702 SetDlgItemTextA(hDlgCopy, SOURCESTRORD, "Scanning ...");
703 SetDlgItemTextA(hDlgCopy, DESTSTRORD, "NOT_IMPLEMENTED_YET");
705 strcpy(buf, REG_INSTALLEDFILES);
706 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyFiles))
707 return VCPN_FAIL;
708 strcat(buf, REGPART_RENAME);
709 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyRename))
710 return VCPN_FAIL;
711 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT, &hKeyConflict))
712 return VCPN_FAIL;
713 len = 1;
714 if (!(RegQueryValueExA(hKeyConflict, "Dirty", NULL, 0, (LPBYTE)&dirty, &len)))
716 /* FIXME: what does SETUPX.DLL do in this case ? */
717 MESSAGE("Warning: another program using SETUPX is already running ! Failed.\n");
718 return VCPN_FAIL;
720 dirty = TRUE;
721 if (RegSetValueExA(hKeyConflict, "Dirty", 0, REG_BINARY, (LPBYTE)&dirty, 1))
722 return VCPN_FAIL;
723 len = 12;
724 if (!(RegQueryValueExA(hKeyConflict, "BackupDirectory", NULL, 0, (LPBYTE)BackupDir, &len)))
725 strcpy(BackupDir, "VCM");
727 /* create C:\WINDOWS\[BackupDir] and set registry key to it */
728 GetWindowsDirectoryA(buf, 256);
729 strcat(buf, "\\");
730 strcat(buf, BackupDir);
731 if (!(CreateDirectoryA(buf, NULL)))
732 return VCPN_FAIL;
733 if (RegSetValueExA(hKeyConflict, "BackupDirectory", 0, REG_SZ, (LPBYTE)buf, strlen(buf)+1))
734 return VCPN_FAIL;
735 RegCloseKey(hKeyConflict);
737 return VCPN_OK;
740 /***********************************************************************
741 * vcpUICallbackProc (SETUPX.213)
743 RETERR16 WINAPI vcpUICallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
744 LPARAM lParam, LPARAM lParamRef)
746 static int count = 0;
747 RETERR16 res = VCPN_OK, cbres;
749 if (count < 5)
750 FIXME("(%p, %04x, %04lx, %08lx, %08lx) - semi-stub\n",
751 lpvObj, uMsg, wParam, lParam, lParamRef);
752 count++;
753 switch (uMsg)
755 /* unused messages, it seems */
756 case VCPM_DISKPREPINFO:
758 case VCPM_FILENEEDED:
760 case VCPM_NODECREATE:
761 case VCPM_NODEACCEPT:
763 case VCPM_VSTATCLOSESTART:
764 case VCPM_VSTATPATHCHECKSTART:
765 case VCPM_VSTATPATHCHECKEND:
767 case VCPM_CHECKPATH:
768 break;
770 /* the real stuff */
771 case VCPM_NODECOMPARE:
772 res = VCP_UI_NodeCompare((LPVIRTNODE)lpvObj, (LPVIRTNODE)lParam);
773 break;
774 case VCPM_VSTATREAD:
775 break;
776 case VCPM_VSTATWRITE:
777 cbres = VCP_Callback(&vcp_status, VCPM_DISKPREPINFO, 0, 0, VCP_MsgRef);
778 break;
779 case VCPM_VSTATCLOSEEND:
780 RegCloseKey(hKeyFiles);
781 RegCloseKey(hKeyRename);
782 RegDeleteKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT);
783 break;
784 case VCPM_VSTATCOPYSTART:
785 res = VCP_UI_CopyStart();
786 break;
787 case VCPM_VSTATCOPYEND:
788 if (hDlgCopy) DestroyWindow(hDlgCopy);
789 break;
790 default:
791 FIXME("unhandled msg 0x%04x\n", uMsg);
793 return res;