winspool.drv: Replace WINSPOOL_SHDeleteKeyW with RegDeleteTreeW.
[wine] / dlls / 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 <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"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
38
39 static FARPROC16 VCP_Proc = NULL;
40 static LPARAM VCP_MsgRef = 0;
41
42 static BOOL VCP_opened = FALSE;
43
44 static VCPSTATUS vcp_status;
45
46 static HINSTANCE SETUPAPI_hInstance;
47
48 static WORD VCP_Callback( LPVOID obj, UINT16 msg, WPARAM16 wParam, LPARAM lParam, LPARAM lParamRef )
49 {
50     WORD args[8];
51     DWORD ret = OK;
52     if (VCP_Proc)
53     {
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 );
63     }
64     return (WORD)ret;
65 }
66
67 /****************************** VHSTR management ******************************/
68
69 /*
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 ! :-)
74  */
75 typedef struct {
76     DWORD refcount;
77     LPCSTR pStr;
78 } VHSTR_STRUCT;
79
80 static VHSTR_STRUCT **vhstrlist = NULL;
81 static VHSTR vhstr_alloc = 0;
82
83 #define VALID_VHSTR(x)          ((x < vhstr_alloc) && (vhstrlist[x]) && (vhstrlist[x]->refcount))
84
85 /***********************************************************************
86  *              vsmStringAdd (SETUPX.207)
87  */
88 VHSTR WINAPI vsmStringAdd16(LPCSTR lpszName)
89 {
90     VHSTR n;
91     VHSTR index = 0xffff;
92     HANDLE heap;
93     LPSTR str;
94
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++)
99     {
100         if ((vhstrlist[n]) && (vhstrlist[n]->refcount))
101         {
102                 TRACE("checking item: %d\n", n);
103             if (!strcmp(vhstrlist[n]->pStr, lpszName))
104             {
105                 TRACE("found\n");
106                 vhstrlist[n]->refcount++;
107                 return n;
108             }
109         }
110     }
111
112     /* hmm, not found yet, let's insert it */
113     TRACE("inserting item\n");
114     for (n = 0; n < vhstr_alloc; n++)
115     {
116         if ((!(vhstrlist[n])) || (!(vhstrlist[n]->refcount)))
117         {
118             index = n;
119             break;
120         }
121     }
122     heap = GetProcessHeap();
123     if (n == vhstr_alloc) /* hmm, no free index found yet */
124     {
125         index = vhstr_alloc;
126         vhstr_alloc += 20;
127
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);
134     }
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;
144 }
145
146 /***********************************************************************
147  *              vsmStringDelete (SETUPX.206)
148  */
149 INT16 WINAPI vsmStringDelete16(VHSTR vhstr)
150 {
151     if (VALID_VHSTR(vhstr))
152     {
153         vhstrlist[vhstr]->refcount--;
154         if (!vhstrlist[vhstr]->refcount)
155         {
156             HeapFree(GetProcessHeap(), 0, (LPSTR)vhstrlist[vhstr]->pStr);
157             vhstrlist[vhstr]->pStr = NULL;
158         }
159         return VCPN_OK;
160     }
161
162     /* string not found */
163     return VCPN_FAIL;
164 }
165
166 /*
167  * vsmStringFind() - not exported from a standard SETUPX.DLL, it seems
168  */
169 VHSTR WINAPI vsmStringFind16(LPCSTR lpszName)
170 {
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;
176 }
177
178 /***********************************************************************
179  *              vsmGetStringName (SETUPX.205)
180  *
181  * Pretty correct, I guess
182  */
183 INT16 WINAPI vsmGetStringName16(VHSTR vhstr, LPSTR lpszBuffer, int cbBuffer)
184 {
185     if (VALID_VHSTR(vhstr))
186     {
187         int len = strlen(vhstrlist[vhstr]->pStr)+1;
188         if (cbBuffer >= len)
189         {
190             if (lpszBuffer)
191                 strcpy(lpszBuffer, vhstrlist[vhstr]->pStr);
192             return len;
193         }
194     }
195     return VCPN_FAIL;
196 }
197
198 /***********************************************************************
199  *              vsmStringCompare (not exported from a standard SETUPX.DLL, it seems)
200  */
201 INT16 WINAPI vsmStringCompare16(VHSTR vhstrA, VHSTR vhstrB)
202 {
203     if ((!VALID_VHSTR(vhstrA)) || (!VALID_VHSTR(vhstrB)))
204         return VCPN_FAIL; /* correct ? */
205     return strcmp(vhstrlist[vhstrA]->pStr, vhstrlist[vhstrB]->pStr);
206 }
207
208 /***********************************************************************
209  *              vsmGetStringRawName (SETUPX.208)
210  */
211 LPCSTR WINAPI vsmGetStringRawName16(VHSTR vhstr)
212 {
213     return (VALID_VHSTR(vhstr)) ? vhstrlist[vhstr]->pStr : NULL;
214 }
215
216
217 /***************************** VIRTNODE management ****************************/
218 static LPVIRTNODE *pvnlist = NULL;
219 static DWORD vn_num = 0;
220 static DWORD vn_last = 0;
221
222 static RETERR16 VCP_VirtnodeCreate(LPVCPFILESPEC vfsSrc, LPVCPFILESPEC vfsDst, WORD fl, LPARAM lParam, LPEXPANDVTBL lpExpandVtbl)
223 {
224     HANDLE heap;
225     LPVIRTNODE lpvn;
226     RETERR16 cbres;
227
228     while (vn_last < vn_num)
229     {
230         if (pvnlist[vn_last] == NULL)
231             break;
232         vn_last++;
233     }
234     heap = GetProcessHeap();
235     if (vn_last == vn_num)
236     {
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);
244     }
245     pvnlist[vn_last] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VIRTNODE));
246     lpvn = pvnlist[vn_last];
247     vn_last++;
248
249     lpvn->cbSize = sizeof(VIRTNODE);
250
251     if (vfsSrc)
252         memcpy(&lpvn->vfsSrc, vfsSrc, sizeof(VCPFILESPEC));
253
254     if (vfsDst)
255         memcpy(&lpvn->vfsDst, vfsDst, sizeof(VCPFILESPEC));
256
257     lpvn->fl = fl;
258     lpvn->lParam = lParam;
259     lpvn->lpExpandVtbl = lpExpandVtbl;
260
261     lpvn->vhstrDstFinalName = 0xffff; /* FIXME: what is this ? */
262
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);
266
267     return OK;
268 }
269
270 #if 0
271 static BOOL VCP_VirtnodeDelete(LPVIRTNODE lpvnDel)
272 {
273     DWORD n;
274     RETERR16 cbres;
275
276     for (n = 0; n < vn_last; n++)
277     {
278         if (pvnlist[n] == lpvnDel)
279         {
280             cbres = VCP_Callback(lpvnDel, VCPM_NODEDESTROY, 0, 0, VCP_MsgRef);
281             HeapFree(GetProcessHeap(), 0, lpvnDel);
282             pvnlist[n] = NULL;
283             return TRUE;
284         }
285     }
286     return FALSE;
287 }
288 #endif
289
290 /***********************************************************************
291  *              VcpOpen (SETUPX.200)
292  *
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.
300  */
301 RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef)
302 {
303     TRACE("(%p, %08lx)\n", vifproc, lparamMsgRef);
304     if (VCP_opened)
305         return ERR_VCP_BUSY;
306
307     VCP_Proc = (FARPROC16)vifproc;
308     VCP_MsgRef = lparamMsgRef;
309
310     /* load SETUPAPI needed for dialog resources etc. */
311     SETUPAPI_hInstance = GetModuleHandleA("setupapi.dll");
312     if (!SETUPAPI_hInstance)
313     {
314         ERR("Could not load sibling setupapi.dll\n");
315         return ERR_VCP_NOMEM;
316     }
317     VCP_opened = TRUE;
318     return OK;
319 }
320
321 /***********************************************************************
322  *              VcpQueueCopy            [SETUPX.13]
323  *
324  * lpExpandVtbl seems to be deprecated.
325  * fl are the CNFL_xxx and VNFL_xxx flags.
326  * lParam are the VNLP_xxx flags.
327  */
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
334 )
335 {
336     VCPFILESPEC vfsSrc, vfsDst;
337
338     if (!VCP_opened)
339         return ERR_VCP_NOTOPEN;
340
341     TRACE("srcdir: %s, srcfile: %s, dstdir: %s, dstfile: %s\n",
342       lpszSrcDir, lpszSrcFileName, lpszDstDir, lpszDstFileName);
343
344     TRACE("ldidSrc == %d, ldidDst == %d\n", ldidSrc, ldidDst);
345
346     vfsSrc.ldid = ldidSrc;
347     vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
348     vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
349
350     vfsDst.ldid = ldidDst;
351     vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
352     vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
353
354     return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, fl, lParam,
355                     lpExpandVtbl);
356 }
357
358 /***********************************************************************
359  *              VcpQueueDelete          [SETUPX.17]
360  *
361  * Is lParamRef the same as lParam in VcpQueueCopy ?
362  * Damn docu !! Err... which docu ?
363  */
364 RETERR16 WINAPI VcpQueueDelete16(
365         LPCSTR lpszDstFileName,
366         LPCSTR lpszDstDir,
367         LOGDISKID16 ldidDst,
368         LPARAM lParamRef
369 )
370 {
371     VCPFILESPEC vfsDst;
372
373     if (!VCP_opened)
374         return ERR_VCP_NOTOPEN;
375
376     vfsDst.ldid = ldidDst;
377     vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
378     vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
379
380     return VCP_VirtnodeCreate(NULL, &vfsDst, VNFL_DELETE, lParamRef, 0);
381 }
382
383 /***********************************************************************
384  *              VcpQueueRename          [SETUPX.204]
385  *
386  */
387 RETERR16 WINAPI VcpQueueRename16(
388         LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
389         LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
390         LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
391         LPARAM lParam
392 )
393 {
394     VCPFILESPEC vfsSrc, vfsDst;
395
396     if (!VCP_opened)
397         return ERR_VCP_NOTOPEN;
398
399     vfsSrc.ldid = ldidSrc;
400     vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
401     vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
402
403     vfsDst.ldid = ldidDst;
404     vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
405     vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
406
407     return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, VNFL_RENAME, lParam,
408                     0);
409 }
410
411 /***********************************************************************
412  *              VcpEnumFiles (SETUPX.@)
413  */
414 INT16 WINAPI VcpEnumFiles(VCPENUMPROC vep, LPARAM lParamRef)
415 {
416     WORD n;
417
418     for (n = 0; n < vn_last; n++)
419         vep(pvnlist[n], lParamRef);
420
421     return 0; /* FIXME: return value ? */
422 }
423
424 /***********************************************************************
425  *              VcpExplain (SETUPX.411)
426  */
427 LPCSTR WINAPI VcpExplain16(LPVIRTNODE lpVn, DWORD dwWhat)
428 {
429     static char buffer[MAX_PATH]; /* FIXME: is this how it's done ? */
430     buffer[0] = '\0';
431     switch (dwWhat)
432     {
433         case VCPEX_SRC_FULL:
434         case VCPEX_DST_FULL:
435             {
436                 LPVCPFILESPEC lpvfs =
437                     (dwWhat == VCPEX_SRC_FULL) ?  &lpVn->vfsSrc : &lpVn->vfsDst;
438
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));
445
446                 strcat(buffer, "\\");
447                 strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrFileName));
448             }
449             break;
450         default:
451             FIXME("%d unimplemented !\n", dwWhat);
452             strcpy(buffer, "Unknown error");
453             break;
454     }
455     return buffer;
456 }
457
458 static RETERR16 VCP_CheckPaths(void)
459 {
460     DWORD n;
461     LPVIRTNODE lpvn;
462     RETERR16 cbres;
463
464     cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKSTART, 0, 0, VCP_MsgRef);
465     for (n = 0; n < vn_num; n++)
466     {
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);
471     }
472     cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKEND, 0, 0, VCP_MsgRef);
473     return OK;
474 }
475
476 static RETERR16 VCP_CopyFiles(void)
477 {
478     char fn_src[MAX_PATH], fn_dst[MAX_PATH];
479     RETERR16 res = OK, cbres;
480     DWORD n;
481     LPVIRTNODE lpvn;
482
483     cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYSTART, 0, 0, VCP_MsgRef);
484     for (n = 0; n < vn_num; n++)
485     {
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);
494
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 )))
500         {
501             ERR("error copying, src: %s -> dst: %s\n", fn_src, fn_dst);
502             res = ERR_VCP_IOFAIL;
503         }
504
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);
509     }
510
511     cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYEND, 0, 0, VCP_MsgRef);
512     return res;
513 }
514
515 /***********************************************************************
516  *              VcpFlush - internal (not exported), but documented
517  *
518  * VNFL_NOW is used for VcpFlush.
519  */
520 RETERR16 VcpFlush16(WORD fl, LPCSTR lpszBackupDest)
521 {
522     return OK;
523 }
524
525 /***********************************************************************
526  *              VcpClose (SETUPX.201)
527  *
528  * Does callbacks (-> vifproc) with VCPM_VSTATCLOSESTART,
529  * VCPM_VSTATCLOSEEND.
530  *
531  * fl gets VCPFL_xxx flags to indicate what to do with the
532  * VIRTNODEs (files to mess with) created by e.g. GenInstall()
533  */
534 RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest)
535 {
536     RETERR16 res = OK;
537     WORD cbres = VCPN_PROCEED;
538
539     TRACE("(%04x, '%s')\n", fl, lpszBackupDest);
540
541     /* FIXME: needs to sort virtnodes in case VCPFL_INSPECIFIEDORDER
542      * is not set. This is done by VCP_Callback(VCPM_NODECOMPARE) */
543
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");
550
551     res = VCP_CheckPaths();
552     TRACE("#4\n");
553     if (res != OK)
554         return res; /* is this ok ? */
555     VCP_CopyFiles();
556
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;
563 }
564
565 #if 0
566 static RETERR16 VCP_RenameFiles(void)
567 {
568     char fn_src[MAX_PATH], fn_dst[MAX_PATH];
569     RETERR16 res = OK, cbres;
570     DWORD n;
571     LPVIRTNODE lpvn;
572
573     cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMESTART, 0, 0, VCP_MsgRef);
574     for (n = 0; n < vn_num; n++)
575     {
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);
585     }
586     cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMEEND, 0, 0, VCP_MsgRef);
587     return res;
588 }
589 #endif
590
591 /***********************************************************************
592  *              vcpDefCallbackProc (SETUPX.202)
593  */
594 RETERR16 WINAPI vcpDefCallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
595                                         LPARAM lParam, LPARAM lParamRef)
596 {
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;
603 }
604
605 /********************* point-and-click stuff from here ***********************/
606
607 static HWND hDlgCopy = 0;
608 static HKEY hKeyFiles = 0, hKeyRename = 0, hKeyConflict = 0;
609 static char BackupDir[12];
610
611 static INT_PTR CALLBACK VCP_UI_FileCopyDlgProc(HWND hWndDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
612 {
613     INT_PTR retval = FALSE;
614
615     if (iMsg == WM_INITDIALOG)
616     {
617         ShowWindow(hWndDlg, SW_SHOWNORMAL);
618         UpdateWindow(hWndDlg);
619         retval = TRUE;
620     }
621     return retval;
622 }
623
624 static BOOL VCP_UI_GetDialogTemplate(LPCVOID *template32)
625 {
626     HRSRC hResInfo;
627     HGLOBAL hDlgTmpl32;
628
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;
635 }
636
637 static LRESULT WINAPI
638 VCP_UI_FileCopyWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
639 {
640     if (uMsg != WM_CREATE)
641         return DefWindowProcA (hwnd, uMsg, wParam, lParam);
642
643     switch (uMsg)
644     {
645         case WM_CREATE:
646             return 0;
647         default:
648             FIXME("%04x: unhandled.\n", uMsg);
649     }
650
651     return 0;
652 }
653
654 static void VCP_UI_RegisterProgressClass(void)
655 {
656     static BOOL registered = FALSE;
657     WNDCLASSA wndClass;
658
659     if (registered)
660         return;
661
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";
671
672     RegisterClassA (&wndClass);
673 }
674
675 static RETERR16 VCP_UI_NodeCompare(LPVIRTNODE vn1, LPVIRTNODE vn2)
676 {
677     LPCSTR file1, file2;
678     file1 = vsmGetStringRawName16(vn1->vfsSrc.vhstrFileName);
679     file2 = vsmGetStringRawName16(vn2->vfsSrc.vhstrFileName);
680     return (RETERR16)strcmp(file1, file2);
681 }
682
683 static RETERR16 VCP_UI_CopyStart(void)
684 {
685     LPCVOID template32;
686     char buf[256]; /* plenty */
687     BOOL dirty;
688     DWORD len;
689
690     /* FIXME: should be registered at DLL startup instead */
691     VCP_UI_RegisterProgressClass();
692     if (!(VCP_UI_GetDialogTemplate(&template32)))
693         return VCPN_FAIL;
694
695     if (vn_num > 10)  /* hack */
696     {
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");
703     }
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)))
714     {
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;
718     }
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");
725
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);
735
736     return VCPN_OK;
737 }
738
739 /***********************************************************************
740  *              vcpUICallbackProc (SETUPX.213)
741  */
742 RETERR16 WINAPI vcpUICallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
743                                         LPARAM lParam, LPARAM lParamRef)
744 {
745     static int count = 0;
746     RETERR16 res = VCPN_OK, cbres;
747
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)
753     {
754         /* unused messages, it seems */
755         case VCPM_DISKPREPINFO:
756
757         case VCPM_FILENEEDED:
758
759         case VCPM_NODECREATE:
760         case VCPM_NODEACCEPT:
761
762         case VCPM_VSTATCLOSESTART:
763         case VCPM_VSTATPATHCHECKSTART:
764         case VCPM_VSTATPATHCHECKEND:
765
766         case VCPM_CHECKPATH:
767             break;
768
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);
791     }
792     return res;
793 }