Keep minimal amount of differences with Wine code
[reactos.git] / reactos / dll / win32 / setupapi / virtcopy.c
1 /*
2 * SetupAPI virtual copy operations
3 *
4 * Copyright 2001 Andreas Mohr
5 *
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.
10 *
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.
15 *
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
19 *
20 * FIXME: we now rely on builtin setupapi.dll for dialog resources.
21 * This is bad ! We ought to have 16bit resource handling working.
22 */
23
24 #include "setupapi_private.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
27
28 static FARPROC16 VCP_Proc = NULL;
29 static LPARAM VCP_MsgRef = 0;
30
31 static BOOL VCP_opened = FALSE;
32
33 static VCPSTATUS vcp_status;
34
35 static HINSTANCE SETUPAPI_hInstance;
36
37 static WORD VCP_Callback( LPVOID obj, UINT16 msg, WPARAM16 wParam, LPARAM lParam, LPARAM lParamRef )
38 {
39 WORD args[8];
40 DWORD ret = OK;
41 if (VCP_Proc)
42 {
43 args[7] = HIWORD(obj);
44 args[6] = LOWORD(obj);
45 args[5] = msg;
46 args[4] = wParam;
47 args[3] = HIWORD(lParam);
48 args[2] = LOWORD(lParam);
49 args[1] = HIWORD(lParamRef);
50 args[0] = LOWORD(lParamRef);
51 WOWCallback16Ex( (DWORD)VCP_Proc, WCB16_PASCAL, sizeof(args), args, &ret );
52 }
53 return (WORD)ret;
54 }
55
56 /****************************** VHSTR management ******************************/
57
58 /*
59 * This is a totally braindead implementation for now;
60 * I don't care about speed at all ! Size and implementation time
61 * is much more important IMHO. I could have created some sophisticated
62 * tree structure, but... what the hell ! :-)
63 */
64 typedef struct {
65 DWORD refcount;
66 LPCSTR pStr;
67 } VHSTR_STRUCT;
68
69 static VHSTR_STRUCT **vhstrlist = NULL;
70 static VHSTR vhstr_alloc = 0;
71
72 #define VALID_VHSTR(x) ((x < vhstr_alloc) && (vhstrlist[x]) && (vhstrlist[x]->refcount))
73
74 /***********************************************************************
75 * vsmStringAdd (SETUPX.207)
76 */
77 VHSTR WINAPI vsmStringAdd16(LPCSTR lpszName)
78 {
79 VHSTR n;
80 VHSTR index = 0xffff;
81 HANDLE heap;
82
83 TRACE("add string '%s'\n", lpszName);
84 /* search whether string already inserted */
85 TRACE("searching for existing string...\n");
86 for (n = 0; n < vhstr_alloc; n++)
87 {
88 if ((vhstrlist[n]) && (vhstrlist[n]->refcount))
89 {
90 TRACE("checking item: %d\n", n);
91 if (!strcmp(vhstrlist[n]->pStr, lpszName))
92 {
93 TRACE("found\n");
94 vhstrlist[n]->refcount++;
95 return n;
96 }
97 }
98 }
99
100 /* hmm, not found yet, let's insert it */
101 TRACE("inserting item\n");
102 for (n = 0; n < vhstr_alloc; n++)
103 {
104 if ((!(vhstrlist[n])) || (!(vhstrlist[n]->refcount)))
105 {
106 index = n;
107 break;
108 }
109 }
110 heap = GetProcessHeap();
111 if (n == vhstr_alloc) /* hmm, no free index found yet */
112 {
113 index = vhstr_alloc;
114 vhstr_alloc += 20;
115
116 if (vhstrlist)
117 vhstrlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, vhstrlist,
118 sizeof(VHSTR_STRUCT *) * vhstr_alloc);
119 else
120 vhstrlist = HeapAlloc(heap, HEAP_ZERO_MEMORY,
121 sizeof(VHSTR_STRUCT *) * vhstr_alloc);
122 }
123 if (index == 0xffff)
124 return 0xffff; /* failure */
125 if (!vhstrlist[index])
126 vhstrlist[index] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VHSTR_STRUCT));
127 vhstrlist[index]->refcount = 1;
128 vhstrlist[index]->pStr = HeapAlloc(heap, 0, strlen(lpszName)+1);
129 strcpy((LPSTR)vhstrlist[index]->pStr, lpszName);
130 return index;
131 }
132
133 /***********************************************************************
134 * vsmStringDelete (SETUPX.206)
135 */
136 INT16 WINAPI vsmStringDelete16(VHSTR vhstr)
137 {
138 if (VALID_VHSTR(vhstr))
139 {
140 vhstrlist[vhstr]->refcount--;
141 if (!vhstrlist[vhstr]->refcount)
142 {
143 HeapFree(GetProcessHeap(), 0, (LPSTR)vhstrlist[vhstr]->pStr);
144 vhstrlist[vhstr]->pStr = NULL;
145 }
146 return VCPN_OK;
147 }
148
149 /* string not found */
150 return VCPN_FAIL;
151 }
152
153 /*
154 * vsmStringFind() - not exported from a standard SETUPX.DLL, it seems
155 */
156 VHSTR WINAPI vsmStringFind16(LPCSTR lpszName)
157 {
158 WORD n;
159 for (n = 0; n < vhstr_alloc; n++)
160 if ((vhstrlist[n]) && (vhstrlist[n]->refcount) && (!strcmp(vhstrlist[n]->pStr, lpszName)))
161 return n;
162 return 0xffff;
163 }
164
165 /***********************************************************************
166 * vsmGetStringName (SETUPX.205)
167 *
168 * Pretty correct, I guess
169 */
170 INT16 WINAPI vsmGetStringName16(VHSTR vhstr, LPSTR lpszBuffer, int cbBuffer)
171 {
172 if (VALID_VHSTR(vhstr))
173 {
174 int len = strlen(vhstrlist[vhstr]->pStr)+1;
175 if (cbBuffer >= len)
176 {
177 if (lpszBuffer)
178 strcpy(lpszBuffer, vhstrlist[vhstr]->pStr);
179 return len;
180 }
181 }
182 return VCPN_FAIL;
183 }
184
185 /***********************************************************************
186 * vsmStringCompare (not exported from a standard SETUPX.DLL, it seems)
187 */
188 INT16 WINAPI vsmStringCompare16(VHSTR vhstrA, VHSTR vhstrB)
189 {
190 if ((!VALID_VHSTR(vhstrA)) || (!VALID_VHSTR(vhstrB)))
191 return VCPN_FAIL; /* correct ? */
192 return strcmp(vhstrlist[vhstrA]->pStr, vhstrlist[vhstrB]->pStr);
193 }
194
195 /***********************************************************************
196 * vsmGetStringRawName (SETUPX.208)
197 */
198 LPCSTR WINAPI vsmGetStringRawName16(VHSTR vhstr)
199 {
200 return (VALID_VHSTR(vhstr)) ? vhstrlist[vhstr]->pStr : NULL;
201 }
202
203
204 /***************************** VIRTNODE management ****************************/
205 static LPVIRTNODE *pvnlist = NULL;
206 static DWORD vn_num = 0;
207 static DWORD vn_last = 0;
208
209 static RETERR16 VCP_VirtnodeCreate(LPVCPFILESPEC vfsSrc, LPVCPFILESPEC vfsDst, WORD fl, LPARAM lParam, LPEXPANDVTBL lpExpandVtbl)
210 {
211 HANDLE heap;
212 LPVIRTNODE lpvn;
213 RETERR16 cbres;
214
215 while (vn_last < vn_num)
216 {
217 if (pvnlist[vn_last] == NULL)
218 break;
219 vn_last++;
220 }
221 heap = GetProcessHeap();
222 if (vn_last == vn_num)
223 {
224 vn_num += 20;
225 if (pvnlist)
226 pvnlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, pvnlist,
227 sizeof(LPVIRTNODE *) * vn_num);
228 else
229 pvnlist = HeapAlloc(heap, HEAP_ZERO_MEMORY,
230 sizeof(LPVIRTNODE *) * vn_num);
231 }
232 pvnlist[vn_last] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VIRTNODE));
233 lpvn = pvnlist[vn_last];
234 vn_last++;
235
236 lpvn->cbSize = sizeof(VIRTNODE);
237
238 if (vfsSrc)
239 memcpy(&lpvn->vfsSrc, vfsSrc, sizeof(VCPFILESPEC));
240
241 if (vfsDst)
242 memcpy(&lpvn->vfsDst, vfsDst, sizeof(VCPFILESPEC));
243
244 lpvn->fl = fl;
245 lpvn->lParam = lParam;
246 lpvn->lpExpandVtbl = lpExpandVtbl;
247
248 lpvn->vhstrDstFinalName = 0xffff; /* FIXME: what is this ? */
249
250 cbres = VCP_Callback(lpvn, VCPM_NODECREATE, 0, 0, VCP_MsgRef);
251 lpvn->fl |= VFNL_CREATED;
252 cbres = VCP_Callback(lpvn, VCPM_NODEACCEPT, 0, 0, VCP_MsgRef);
253
254 return OK;
255 }
256
257 #if 0
258 static BOOL VCP_VirtnodeDelete(LPVIRTNODE lpvnDel)
259 {
260 DWORD n;
261 RETERR16 cbres;
262
263 for (n = 0; n < vn_last; n++)
264 {
265 if (pvnlist[n] == lpvnDel)
266 {
267 cbres = VCP_Callback(lpvnDel, VCPM_NODEDESTROY, 0, 0, VCP_MsgRef);
268 HeapFree(GetProcessHeap(), 0, lpvnDel);
269 pvnlist[n] = NULL;
270 return TRUE;
271 }
272 }
273 return FALSE;
274 }
275 #endif
276
277 /***********************************************************************
278 * VcpOpen (SETUPX.200)
279 *
280 * Sets up a virtual copy operation.
281 * This means that functions such as GenInstall()
282 * create a VIRTNODE struct for every file to be touched in a .INF file
283 * instead of actually touching the file.
284 * The actual copy/move/rename gets started when VcpClose or
285 * VcpFlush is called; several different callbacks are made
286 * (copy, rename, open, close, version conflicts, ...) on every file copied.
287 */
288 RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef)
289 {
290 TRACE("(%p, %08lx)\n", vifproc, lparamMsgRef);
291 if (VCP_opened)
292 return ERR_VCP_BUSY;
293
294 VCP_Proc = (FARPROC16)vifproc;
295 VCP_MsgRef = lparamMsgRef;
296
297 /* load SETUPAPI needed for dialog resources etc. */
298 SETUPAPI_hInstance = GetModuleHandleA("setupapi.dll");
299 if (!SETUPAPI_hInstance)
300 {
301 ERR("Could not load sibling setupapi.dll\n");
302 return ERR_VCP_NOMEM;
303 }
304 VCP_opened = TRUE;
305 return OK;
306 }
307
308 /***********************************************************************
309 * VcpQueueCopy [SETUPX.13]
310 *
311 * lpExpandVtbl seems to be deprecated.
312 * fl are the CNFL_xxx and VNFL_xxx flags.
313 * lParam are the VNLP_xxx flags.
314 */
315 RETERR16 WINAPI VcpQueueCopy16(
316 LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
317 LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
318 LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
319 LPEXPANDVTBL lpExpandVtbl,
320 WORD fl, LPARAM lParam
321 )
322 {
323 VCPFILESPEC vfsSrc, vfsDst;
324
325 if (!VCP_opened)
326 return ERR_VCP_NOTOPEN;
327
328 TRACE("srcdir: %s, srcfile: %s, dstdir: %s, dstfile: %s\n",
329 lpszSrcDir, lpszSrcFileName, lpszDstDir, lpszDstFileName);
330
331 TRACE("ldidSrc == %d, ldidDst == %d\n", ldidSrc, ldidDst);
332
333 vfsSrc.ldid = ldidSrc;
334 vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
335 vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
336
337 vfsDst.ldid = ldidDst;
338 vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
339 vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
340
341 return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, fl, lParam,
342 lpExpandVtbl);
343 }
344
345 /***********************************************************************
346 * VcpQueueDelete [SETUPX.17]
347 *
348 * Is lParamRef the same as lParam in VcpQueueCopy ?
349 * Damn docu !! Err... which docu ?
350 */
351 RETERR16 WINAPI VcpQueueDelete16(
352 LPCSTR lpszDstFileName,
353 LPCSTR lpszDstDir,
354 LOGDISKID16 ldidDst,
355 LPARAM lParamRef
356 )
357 {
358 VCPFILESPEC vfsDst;
359
360 if (!VCP_opened)
361 return ERR_VCP_NOTOPEN;
362
363 vfsDst.ldid = ldidDst;
364 vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
365 vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
366
367 return VCP_VirtnodeCreate(NULL, &vfsDst, VNFL_DELETE, lParamRef, 0);
368 }
369
370 /***********************************************************************
371 * VcpQueueRename [SETUPX.204]
372 *
373 */
374 RETERR16 WINAPI VcpQueueRename16(
375 LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
376 LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
377 LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
378 LPARAM lParam
379 )
380 {
381 VCPFILESPEC vfsSrc, vfsDst;
382
383 if (!VCP_opened)
384 return ERR_VCP_NOTOPEN;
385
386 vfsSrc.ldid = ldidSrc;
387 vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
388 vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
389
390 vfsDst.ldid = ldidDst;
391 vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
392 vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
393
394 return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, VNFL_RENAME, lParam,
395 0);
396 }
397
398 /***********************************************************************
399 * VcpEnumFiles (SETUPX.@)
400 */
401 INT16 WINAPI VcpEnumFiles(VCPENUMPROC vep, LPARAM lParamRef)
402 {
403 WORD n;
404
405 for (n = 0; n < vn_last; n++)
406 vep(pvnlist[n], lParamRef);
407
408 return 0; /* FIXME: return value ? */
409 }
410
411 /***********************************************************************
412 * VcpExplain (SETUPX.411)
413 */
414 LPCSTR WINAPI VcpExplain16(LPVIRTNODE lpVn, DWORD dwWhat)
415 {
416 static char buffer[MAX_PATH]; /* FIXME: is this how it's done ? */
417 buffer[0] = '\0';
418 switch (dwWhat)
419 {
420 case VCPEX_SRC_FULL:
421 case VCPEX_DST_FULL:
422 {
423 LPVCPFILESPEC lpvfs =
424 (dwWhat == VCPEX_SRC_FULL) ? &lpVn->vfsSrc : &lpVn->vfsDst;
425
426 /* if we have an ldid, use it, otherwise use the string */
427 /* from the vhstrlist array */
428 if (lpvfs->ldid != 0xffff)
429 CtlGetLddPath16(lpvfs->ldid, buffer);
430 else
431 strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrDir));
432
433 strcat(buffer, "\\");
434 strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrFileName));
435 }
436 break;
437 default:
438 FIXME("%ld unimplemented !\n", dwWhat);
439 strcpy(buffer, "Unknown error");
440 break;
441 }
442 return buffer;
443 }
444
445 static RETERR16 VCP_CheckPaths(void)
446 {
447 DWORD n;
448 LPVIRTNODE lpvn;
449 RETERR16 cbres;
450
451 cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKSTART, 0, 0, VCP_MsgRef);
452 for (n = 0; n < vn_num; n++)
453 {
454 lpvn = pvnlist[n];
455 if (!lpvn) continue;
456 /* FIXME: check paths of all VIRTNODEs here ! */
457 cbres = VCP_Callback(&lpvn->vfsDst, VCPM_CHECKPATH, 0, (DWORD)lpvn, VCP_MsgRef);
458 }
459 cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKEND, 0, 0, VCP_MsgRef);
460 return OK;
461 }
462
463 static RETERR16 VCP_CopyFiles(void)
464 {
465 char fn_src[MAX_PATH], fn_dst[MAX_PATH];
466 RETERR16 res = OK, cbres;
467 DWORD n;
468 LPVIRTNODE lpvn;
469
470 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYSTART, 0, 0, VCP_MsgRef);
471 for (n = 0; n < vn_num; n++)
472 {
473 lpvn = pvnlist[n];
474 if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_COPY)) continue;
475 /* FIXME: need to send VCPM_VSTATNEWDISK notification sometimes */
476 strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
477 strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
478 /* FIXME: what is this VCPM_VSTATWRITE here for ?
479 * I guess it's to signal successful destination file creation */
480 cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
481
482 /* FIXME: need to do the file copy in small chunks for notifications */
483 TRACE("copying '%s' to '%s'\n", fn_src, fn_dst);
484 /* perform the file copy */
485 if (!(CopyFileA(fn_src, fn_dst,
486 (lpvn->fl & VNLP_COPYIFEXISTS) ? FALSE : TRUE )))
487 {
488 ERR("error copying, src: %s -> dst: %s\n", fn_src, fn_dst);
489 res = ERR_VCP_IOFAIL;
490 }
491
492 vcp_status.prgFileRead.dwSoFar++;
493 cbres = VCP_Callback(&vcp_status, VCPM_VSTATREAD, 0, 0, VCP_MsgRef);
494 vcp_status.prgFileWrite.dwSoFar++;
495 cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
496 }
497
498 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYEND, 0, 0, VCP_MsgRef);
499 return res;
500 }
501
502 /***********************************************************************
503 * VcpFlush - internal (not exported), but documented
504 *
505 * VNFL_NOW is used for VcpFlush.
506 */
507 RETERR16 VcpFlush16(WORD fl, LPCSTR lpszBackupDest)
508 {
509 return OK;
510 }
511
512 /***********************************************************************
513 * VcpClose (SETUPX.201)
514 *
515 * Does callbacks (-> vifproc) with VCPM_VSTATCLOSESTART,
516 * VCPM_VSTATCLOSEEND.
517 *
518 * fl gets VCPFL_xxx flags to indicate what to do with the
519 * VIRTNODEs (files to mess with) created by e.g. GenInstall()
520 */
521 RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest)
522 {
523 RETERR16 res = OK;
524 WORD cbres = VCPN_PROCEED;
525
526 TRACE("(%04x, '%s')\n", fl, lpszBackupDest);
527
528 /* FIXME: needs to sort virtnodes in case VCPFL_INSPECIFIEDORDER
529 * is not set. This is done by VCP_Callback(VCPM_NODECOMPARE) */
530
531 TRACE("#1\n");
532 memset(&vcp_status, 0, sizeof(VCPSTATUS));
533 /* yes, vcp_status.cbSize is 0 ! */
534 TRACE("#2\n");
535 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSESTART, 0, 0, VCP_MsgRef);
536 TRACE("#3\n");
537
538 res = VCP_CheckPaths();
539 TRACE("#4\n");
540 if (res != OK)
541 return res; /* is this ok ? */
542 VCP_CopyFiles();
543
544 TRACE("#5\n");
545 cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSEEND, 0, 0, VCP_MsgRef);
546 TRACE("#6\n");
547 VCP_Proc = NULL;
548 VCP_opened = FALSE;
549 return OK;
550 }
551
552 #if 0
553 static RETERR16 VCP_RenameFiles(void)
554 {
555 char fn_src[MAX_PATH], fn_dst[MAX_PATH];
556 RETERR16 res = OK, cbres;
557 DWORD n;
558 LPVIRTNODE lpvn;
559
560 cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMESTART, 0, 0, VCP_MsgRef);
561 for (n = 0; n < vn_num; n++)
562 {
563 lpvn = pvnlist[n];
564 if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_RENAME)) continue;
565 strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
566 strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
567 cbres = VCP_Callback(&lpvn->vfsDst, VCPM_FILEOPENOUT, 0, (LPARAM)lpvn, VCP_MsgRef);
568 if (!(MoveFileExA(fn_src, fn_dst, MOVEFILE_REPLACE_EXISTING)))
569 res = ERR_VCP_IOFAIL;
570 else
571 VCP_VirtnodeDelete(lpvn);
572 }
573 cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMEEND, 0, 0, VCP_MsgRef);
574 return res;
575 }
576 #endif
577
578 /***********************************************************************
579 * vcpDefCallbackProc (SETUPX.202)
580 */
581 RETERR16 WINAPI vcpDefCallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
582 LPARAM lParam, LPARAM lParamRef)
583 {
584 static int count = 0;
585 if (count < 10)
586 FIXME("(%p, %04x, %04x, %08lx, %08lx) - what to do here ?\n",
587 lpvObj, uMsg, wParam, lParam, lParamRef);
588 count++;
589 return OK;
590 }
591
592 /********************* point-and-click stuff from here ***********************/
593
594 static HWND hDlgCopy = 0;
595 static HKEY hKeyFiles = 0, hKeyRename = 0, hKeyConflict = 0;
596 static char BackupDir[12];
597
598 static INT_PTR CALLBACK VCP_UI_FileCopyDlgProc(HWND hWndDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
599 {
600 INT_PTR retval = FALSE;
601
602 if (iMsg == WM_INITDIALOG)
603 {
604 ShowWindow(hWndDlg, SW_SHOWNORMAL);
605 UpdateWindow(hWndDlg);
606 retval = TRUE;
607 }
608 return retval;
609 }
610
611 static BOOL VCP_UI_GetDialogTemplate(LPCVOID *template32)
612 {
613 HRSRC hResInfo;
614 HGLOBAL hDlgTmpl32;
615
616 if (!(hResInfo = FindResourceA(SETUPAPI_hInstance, MAKEINTRESOURCEA(COPYFILEDLGORD), (LPSTR)RT_DIALOG)))
617 return FALSE;
618 if (!(hDlgTmpl32 = LoadResource(SETUPAPI_hInstance, hResInfo )) ||
619 !(*template32 = LockResource( hDlgTmpl32 )))
620 return FALSE;
621 return TRUE;
622 }
623
624 static LRESULT WINAPI
625 VCP_UI_FileCopyWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
626 {
627 if (uMsg != WM_CREATE)
628 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
629
630 switch (uMsg)
631 {
632 case WM_CREATE:
633 return 0;
634 default:
635 FIXME("%04x: unhandled.\n", uMsg);
636 }
637
638 return 0;
639 }
640
641 static void VCP_UI_RegisterProgressClass(void)
642 {
643 static BOOL registered = FALSE;
644 WNDCLASSA wndClass;
645
646 if (registered)
647 return;
648
649 registered = TRUE;
650 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
651 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
652 wndClass.lpfnWndProc = VCP_UI_FileCopyWndProc;
653 wndClass.cbClsExtra = 0;
654 wndClass.cbWndExtra = 0;
655 wndClass.hCursor = LoadCursorA (0, (LPSTR)IDC_ARROW);
656 wndClass.hbrBackground = NULL;
657 wndClass.lpszClassName = "setupx_progress";
658
659 RegisterClassA (&wndClass);
660 }
661
662 static RETERR16 VCP_UI_NodeCompare(LPVIRTNODE vn1, LPVIRTNODE vn2)
663 {
664 LPCSTR file1, file2;
665 file1 = vsmGetStringRawName16(vn1->vfsSrc.vhstrFileName);
666 file2 = vsmGetStringRawName16(vn2->vfsSrc.vhstrFileName);
667 return (RETERR16)strcmp(file1, file2);
668 }
669
670 static RETERR16 VCP_UI_CopyStart(void)
671 {
672 LPCVOID template32;
673 char buf[256]; /* plenty */
674 BOOL dirty;
675 DWORD len;
676
677 /* FIXME: should be registered at DLL startup instead */
678 VCP_UI_RegisterProgressClass();
679 if (!(VCP_UI_GetDialogTemplate(&template32)))
680 return VCPN_FAIL;
681
682 if (vn_num > 10) /* hack */
683 {
684 hDlgCopy = CreateDialogIndirectParamA(SETUPAPI_hInstance, template32, 0,
685 VCP_UI_FileCopyDlgProc, 0);
686 if (!hDlgCopy)
687 return VCPN_FAIL;
688 SetDlgItemTextA(hDlgCopy, SOURCESTRORD, "Scanning ...");
689 SetDlgItemTextA(hDlgCopy, DESTSTRORD, "NOT_IMPLEMENTED_YET");
690 }
691 strcpy(buf, REG_INSTALLEDFILES);
692 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyFiles))
693 return VCPN_FAIL;
694 strcat(buf, REGPART_RENAME);
695 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyRename))
696 return VCPN_FAIL;
697 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT, &hKeyConflict))
698 return VCPN_FAIL;
699 len = 1;
700 if (!(RegQueryValueExA(hKeyConflict, "Dirty", NULL, 0, (LPBYTE)&dirty, &len)))
701 {
702 /* FIXME: what does SETUPX.DLL do in this case ? */
703 MESSAGE("Warning: another program using SETUPX is already running ! Failed.\n");
704 return VCPN_FAIL;
705 }
706 dirty = TRUE;
707 if (RegSetValueExA(hKeyConflict, "Dirty", 0, REG_BINARY, (LPBYTE)&dirty, 1))
708 return VCPN_FAIL;
709 len = 12;
710 if (!(RegQueryValueExA(hKeyConflict, "BackupDirectory", NULL, 0, (LPBYTE)BackupDir, &len)))
711 strcpy(BackupDir, "VCM");
712
713 /* create C:\WINDOWS\[BackupDir] and set registry key to it */
714 GetWindowsDirectoryA(buf, 256);
715 strcat(buf, "\\");
716 strcat(buf, BackupDir);
717 if (!(CreateDirectoryA(buf, NULL)))
718 return VCPN_FAIL;
719 if (RegSetValueExA(hKeyConflict, "BackupDirectory", 0, REG_SZ, (LPBYTE)buf, strlen(buf)+1))
720 return VCPN_FAIL;
721 RegCloseKey(hKeyConflict);
722
723 return VCPN_OK;
724 }
725
726 /***********************************************************************
727 * vcpUICallbackProc (SETUPX.213)
728 */
729 RETERR16 WINAPI vcpUICallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
730 LPARAM lParam, LPARAM lParamRef)
731 {
732 static int count = 0;
733 RETERR16 res = VCPN_OK, cbres;
734
735 if (count < 5)
736 FIXME("(%p, %04x, %04x, %08lx, %08lx) - semi-stub\n",
737 lpvObj, uMsg, wParam, lParam, lParamRef);
738 count++;
739 switch (uMsg)
740 {
741 /* unused messages, it seems */
742 case VCPM_DISKPREPINFO:
743
744 case VCPM_FILENEEDED:
745
746 case VCPM_NODECREATE:
747 case VCPM_NODEACCEPT:
748
749 case VCPM_VSTATCLOSESTART:
750 case VCPM_VSTATPATHCHECKSTART:
751 case VCPM_VSTATPATHCHECKEND:
752
753 case VCPM_CHECKPATH:
754 break;
755
756 /* the real stuff */
757 case VCPM_NODECOMPARE:
758 res = VCP_UI_NodeCompare((LPVIRTNODE)lpvObj, (LPVIRTNODE)lParam);
759 break;
760 case VCPM_VSTATREAD:
761 break;
762 case VCPM_VSTATWRITE:
763 cbres = VCP_Callback(&vcp_status, VCPM_DISKPREPINFO, 0, 0, VCP_MsgRef);
764 break;
765 case VCPM_VSTATCLOSEEND:
766 RegCloseKey(hKeyFiles);
767 RegCloseKey(hKeyRename);
768 RegDeleteKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT);
769 break;
770 case VCPM_VSTATCOPYSTART:
771 res = VCP_UI_CopyStart();
772 break;
773 case VCPM_VSTATCOPYEND:
774 if (hDlgCopy) DestroyWindow(hDlgCopy);
775 break;
776 default:
777 FIXME("unhandled msg 0x%04x\n", uMsg);
778 }
779 return res;
780 }