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 */
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;
177 strcpy(lpszBuffer, vhstrlist[vhstr]->pStr);
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)
205 while (vn_last < vn_num)
207 if (pvnlist[vn_last] == NULL)
211 heap = GetProcessHeap();
212 if (vn_last == vn_num)
216 pvnlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, pvnlist,
217 sizeof(LPVIRTNODE *) * vn_num);
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];
226 lpvn->cbSize = sizeof(VIRTNODE);
229 lpvn->vfsSrc = *vfsSrc;
232 lpvn->vfsDst = *vfsDst;
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);
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);
264 VCP_Proc = (FARPROC16)vifproc;
265 VCP_MsgRef = lparamMsgRef;
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;
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,
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,
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,
344 VCPFILESPEC vfsSrc, vfsDst;
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)
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 ? */
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);
394 strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrDir));
396 strcat(buffer, "\\");
397 strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrFileName));
401 FIXME("%d unimplemented !\n", dwWhat);
402 strcpy(buffer, "Unknown error");
408 static RETERR16 VCP_CheckPaths(void)
414 cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKSTART, 0, 0, VCP_MsgRef);
415 for (n = 0; n < vn_num; n++)
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);
426 static RETERR16 VCP_CopyFiles(void)
428 char fn_src[MAX_PATH], fn_dst[MAX_PATH];
429 RETERR16 res = OK, cbres;
433 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYSTART, 0, 0, VCP_MsgRef);
434 for (n = 0; n < vn_num; 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);
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)
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) */
485 memset(&vcp_status, 0, sizeof(VCPSTATUS));
486 /* yes, vcp_status.cbSize is 0 ! */
488 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSESTART, 0, 0, VCP_MsgRef);
491 res = VCP_CheckPaths();
494 return res; /* is this ok ? */
498 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSEEND, 0, 0, VCP_MsgRef);
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;
513 FIXME("(%p, %04x, %04lx, %08lx, %08lx) - what to do here ?\n",
514 lpvObj, uMsg, wParam, lParam, lParamRef);
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);
538 static BOOL VCP_UI_GetDialogTemplate(LPCVOID *template32)
543 if (!(hResInfo = FindResourceA(SETUPAPI_hInstance, MAKEINTRESOURCEA(COPYFILEDLGORD), (LPSTR)RT_DIALOG)))
545 if (!(hDlgTmpl32 = LoadResource(SETUPAPI_hInstance, hResInfo )) ||
546 !(*template32 = LockResource( hDlgTmpl32 )))
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);
562 FIXME("%04x: unhandled.\n", uMsg);
568 static void VCP_UI_RegisterProgressClass(void)
570 static BOOL registered = FALSE;
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)
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)
600 char buf[256]; /* plenty */
604 /* FIXME: should be registered at DLL startup instead */
605 VCP_UI_RegisterProgressClass();
606 if (!(VCP_UI_GetDialogTemplate(&template32)))
609 if (vn_num > 10) /* hack */
611 hDlgCopy = CreateDialogIndirectParamA(SETUPAPI_hInstance, template32, 0,
612 VCP_UI_FileCopyDlgProc, 0);
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))
621 strcat(buf, REGPART_RENAME);
622 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyRename))
624 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT, &hKeyConflict))
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");
634 if (RegSetValueExA(hKeyConflict, "Dirty", 0, REG_BINARY, (LPBYTE)&dirty, 1))
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);
643 strcat(buf, BackupDir);
644 if (!(CreateDirectoryA(buf, NULL)))
646 if (RegSetValueExA(hKeyConflict, "BackupDirectory", 0, REG_SZ, (LPBYTE)buf, strlen(buf)+1))
648 RegCloseKey(hKeyConflict);
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;
663 FIXME("(%p, %04x, %04lx, %08lx, %08lx) - semi-stub\n",
664 lpvObj, uMsg, wParam, lParam, lParamRef);
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:
684 case VCPM_NODECOMPARE:
685 res = VCP_UI_NodeCompare((LPVIRTNODE)lpvObj, (LPVIRTNODE)lParam);
689 case VCPM_VSTATWRITE:
690 cbres = VCP_Callback(&vcp_status, VCPM_DISKPREPINFO, 0, 0, VCP_MsgRef);
692 case VCPM_VSTATCLOSEEND:
693 RegCloseKey(hKeyFiles);
694 RegCloseKey(hKeyRename);
695 RegDeleteKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT);
697 case VCPM_VSTATCOPYSTART:
698 res = VCP_UI_CopyStart();
700 case VCPM_VSTATCOPYEND:
701 if (hDlgCopy) DestroyWindow(hDlgCopy);
704 FIXME("unhandled msg 0x%04x\n", uMsg);