Fixed definitions of TTTOOLINFOA/W_V1_SIZE and
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "wingdi.h"
32 #include "winnls.h"
33 #include "setupapi.h"
34 #include "setupx16.h"
35 #include "setupapi_private.h"
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
39
40 static FARPROC16 VCP_Proc = NULL;
41 static LPARAM VCP_MsgRef = 0;
42
43 static BOOL VCP_opened = FALSE;
44
45 static VCPSTATUS vcp_status;
46
47 static HINSTANCE SETUPAPI_hInstance;
48
49 static WORD VCP_Callback( LPVOID obj, UINT16 msg, WPARAM16 wParam, LPARAM lParam, LPARAM lParamRef )
50 {
51     WORD args[8];
52     DWORD ret = OK;
53     if (VCP_Proc)
54     {
55         args[7] = HIWORD(obj);
56         args[6] = LOWORD(obj);
57         args[5] = msg;
58         args[4] = wParam;
59         args[3] = HIWORD(lParam);
60         args[2] = LOWORD(lParam);
61         args[1] = HIWORD(lParamRef);
62         args[0] = LOWORD(lParamRef);
63         WOWCallback16Ex( (DWORD)VCP_Proc, WCB16_PASCAL, sizeof(args), args, &ret );
64     }
65     return (WORD)ret;
66 }
67
68 /****************************** VHSTR management ******************************/
69
70 /*
71  * This is a totally braindead implementation for now;
72  * I don't care about speed at all ! Size and implementation time
73  * is much more important IMHO. I could have created some sophisticated
74  * tree structure, but... what the hell ! :-)
75  */
76 typedef struct {
77     DWORD refcount;
78     LPCSTR pStr;
79 } VHSTR_STRUCT;
80
81 static VHSTR_STRUCT **vhstrlist = NULL;
82 static VHSTR vhstr_alloc = 0;
83
84 #define VALID_VHSTR(x)          ((x < vhstr_alloc) && (vhstrlist[x]) && (vhstrlist[x]->refcount))
85
86 /***********************************************************************
87  *              vsmStringAdd (SETUPX.207)
88  */
89 VHSTR WINAPI vsmStringAdd16(LPCSTR lpszName)
90 {
91     VHSTR n;
92     VHSTR index = 0xffff;
93     HANDLE heap;
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         vhstrlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, vhstrlist,
128                                         sizeof(VHSTR_STRUCT *) * vhstr_alloc);
129     }
130     if (index == 0xffff)
131         return 0xffff; /* failure */
132     if (!vhstrlist[index])
133         vhstrlist[index] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VHSTR_STRUCT));
134     vhstrlist[index]->refcount = 1;
135     vhstrlist[index]->pStr = HeapAlloc(heap, 0, strlen(lpszName)+1);
136     strcpy((LPSTR)vhstrlist[index]->pStr, lpszName);
137     return index;
138 }
139
140 /***********************************************************************
141  *              vsmStringDelete (SETUPX.206)
142  */
143 INT16 WINAPI vsmStringDelete16(VHSTR vhstr)
144 {
145     if (VALID_VHSTR(vhstr))
146     {
147         vhstrlist[vhstr]->refcount--;
148         if (!vhstrlist[vhstr]->refcount)
149         {
150             HeapFree(GetProcessHeap(), 0, (LPSTR)vhstrlist[vhstr]->pStr);
151             vhstrlist[vhstr]->pStr = NULL;
152         }
153         return VCPN_OK;
154     }
155
156     /* string not found */
157     return VCPN_FAIL;
158 }
159
160 /*
161  * vsmStringFind() - not exported from a standard SETUPX.DLL, it seems
162  */
163 VHSTR WINAPI vsmStringFind16(LPCSTR lpszName)
164 {
165     WORD n;
166     for (n = 0; n < vhstr_alloc; n++)
167         if ((vhstrlist[n]) && (vhstrlist[n]->refcount) && (!strcmp(vhstrlist[n]->pStr, lpszName)))
168             return n;
169     return 0xffff;
170 }
171
172 /***********************************************************************
173  *              vsmGetStringName (SETUPX.205)
174  *
175  * Pretty correct, I guess
176  */
177 INT16 WINAPI vsmGetStringName16(VHSTR vhstr, LPSTR lpszBuffer, int cbBuffer)
178 {
179     if (VALID_VHSTR(vhstr))
180     {
181         int len = strlen(vhstrlist[vhstr]->pStr)+1;
182         if (cbBuffer >= len)
183         {
184             if (lpszBuffer)
185                 strcpy(lpszBuffer, vhstrlist[vhstr]->pStr);
186             return len;
187         }
188     }
189     return VCPN_FAIL;
190 }
191
192 /***********************************************************************
193  *              vsmStringCompare (not exported from a standard SETUPX.DLL, it seems)
194  */
195 INT16 WINAPI vsmStringCompare16(VHSTR vhstrA, VHSTR vhstrB)
196 {
197     if ((!VALID_VHSTR(vhstrA)) || (!VALID_VHSTR(vhstrB)))
198         return VCPN_FAIL; /* correct ? */
199     return strcmp(vhstrlist[vhstrA]->pStr, vhstrlist[vhstrB]->pStr);
200 }
201
202 /***********************************************************************
203  *              vsmGetStringRawName (SETUPX.208)
204  */
205 LPCSTR WINAPI vsmGetStringRawName16(VHSTR vhstr)
206 {
207     return (VALID_VHSTR(vhstr)) ? vhstrlist[vhstr]->pStr : NULL;
208 }
209
210
211 /***************************** VIRTNODE management ****************************/
212 static LPVIRTNODE *pvnlist = NULL;
213 static DWORD vn_num = 0;
214 static DWORD vn_last = 0;
215
216 RETERR16 VCP_VirtnodeCreate(LPVCPFILESPEC vfsSrc, LPVCPFILESPEC vfsDst, WORD fl, LPARAM lParam, LPEXPANDVTBL lpExpandVtbl)
217 {
218     HANDLE heap;
219     LPVIRTNODE lpvn;
220     RETERR16 cbres;
221
222     while (vn_last < vn_num)
223     {
224         if (pvnlist[vn_last] == NULL)
225             break;
226         vn_last++;
227     }
228     heap = GetProcessHeap();
229     if (vn_last == vn_num)
230     {
231         vn_num += 20;
232         pvnlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, pvnlist,
233                                 sizeof(LPVIRTNODE *) * vn_num);
234     }
235     pvnlist[vn_last] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VIRTNODE));
236     lpvn = pvnlist[vn_last];
237     vn_last++;
238
239     lpvn->cbSize = sizeof(VIRTNODE);
240
241     if (vfsSrc)
242         memcpy(&lpvn->vfsSrc, vfsSrc, sizeof(VCPFILESPEC));
243
244     if (vfsDst)
245         memcpy(&lpvn->vfsDst, vfsDst, sizeof(VCPFILESPEC));
246
247     lpvn->fl = fl;
248     lpvn->lParam = lParam;
249     lpvn->lpExpandVtbl = lpExpandVtbl;
250
251     lpvn->vhstrDstFinalName = 0xffff; /* FIXME: what is this ? */
252
253     cbres = VCP_Callback(lpvn, VCPM_NODECREATE, 0, 0, VCP_MsgRef);
254     lpvn->fl |= VFNL_CREATED;
255     cbres = VCP_Callback(lpvn, VCPM_NODEACCEPT, 0, 0, VCP_MsgRef);
256
257     return OK;
258 }
259
260 BOOL VCP_VirtnodeDelete(LPVIRTNODE lpvnDel)
261 {
262     DWORD n;
263     RETERR16 cbres;
264
265     for (n = 0; n < vn_last; n++)
266     {
267         if (pvnlist[n] == lpvnDel)
268         {
269             cbres = VCP_Callback(lpvnDel, VCPM_NODEDESTROY, 0, 0, VCP_MsgRef);
270             HeapFree(GetProcessHeap(), 0, lpvnDel);
271             pvnlist[n] = NULL;
272             return TRUE;
273         }
274     }
275     return FALSE;
276 }
277
278 /***********************************************************************
279  *              VcpOpen (SETUPX.200)
280  *
281  * Sets up a virtual copy operation.
282  * This means that functions such as GenInstall()
283  * create a VIRTNODE struct for every file to be touched in a .INF file
284  * instead of actually touching the file.
285  * The actual copy/move/rename gets started when VcpClose or
286  * VcpFlush is called; several different callbacks are made
287  * (copy, rename, open, close, version conflicts, ...) on every file copied.
288  */
289 RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef)
290 {
291     TRACE("(%p, %08lx)\n", vifproc, lparamMsgRef);
292     if (VCP_opened)
293         return ERR_VCP_BUSY;
294
295     VCP_Proc = (FARPROC16)vifproc;
296     VCP_MsgRef = lparamMsgRef;
297
298     /* load SETUPAPI needed for dialog resources etc. */
299     SETUPAPI_hInstance = LoadLibraryA("setupapi.dll");
300     if (!SETUPAPI_hInstance)
301     {
302         ERR("Could not load sibling setupapi.dll\n");
303         return ERR_VCP_NOMEM;
304     }
305     VCP_opened = TRUE;
306     return OK;
307 }
308
309 /***********************************************************************
310  *              VcpQueueCopy            [SETUPX.13]
311  *
312  * lpExpandVtbl seems to be deprecated.
313  * fl are the CNFL_xxx and VNFL_xxx flags.
314  * lParam are the VNLP_xxx flags.
315  */
316 RETERR16 WINAPI VcpQueueCopy16(
317         LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
318         LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
319         LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
320         LPEXPANDVTBL lpExpandVtbl,
321         WORD fl, LPARAM lParam
322 )
323 {
324     VCPFILESPEC vfsSrc, vfsDst;
325
326     if (!VCP_opened)
327         return ERR_VCP_NOTOPEN;
328
329     TRACE("srcdir: %s, srcfile: %s, dstdir: %s, dstfile: %s\n",
330       lpszSrcDir, lpszSrcFileName, lpszDstDir, lpszDstFileName);
331
332     TRACE("ldidSrc == %d, ldidDst == %d\n", ldidSrc, ldidDst);
333
334     vfsSrc.ldid = ldidSrc;
335     vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
336     vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
337
338     vfsDst.ldid = ldidDst;
339     vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
340     vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
341
342     return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, fl, lParam,
343                     lpExpandVtbl);
344 }
345
346 /***********************************************************************
347  *              VcpQueueDelete          [SETUPX.17]
348  *
349  * Is lParamRef the same as lParam in VcpQueueCopy ?
350  * Damn docu !! Err... which docu ?
351  */
352 RETERR16 WINAPI VcpQueueDelete16(
353         LPCSTR lpszDstFileName,
354         LPCSTR lpszDstDir,
355         LOGDISKID16 ldidDst,
356         LPARAM lParamRef
357 )
358 {
359     VCPFILESPEC vfsDst;
360
361     if (!VCP_opened)
362         return ERR_VCP_NOTOPEN;
363
364     vfsDst.ldid = ldidDst;
365     vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
366     vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
367
368     return VCP_VirtnodeCreate(NULL, &vfsDst, VNFL_DELETE, lParamRef, 0);
369 }
370
371 /***********************************************************************
372  *              VcpQueueRename          [SETUPX.204]
373  *
374  */
375 RETERR16 WINAPI VcpQueueRename16(
376         LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
377         LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
378         LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
379         LPARAM lParam
380 )
381 {
382     VCPFILESPEC vfsSrc, vfsDst;
383
384     if (!VCP_opened)
385         return ERR_VCP_NOTOPEN;
386
387     vfsSrc.ldid = ldidSrc;
388     vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
389     vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
390
391     vfsDst.ldid = ldidDst;
392     vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
393     vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
394
395     return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, VNFL_RENAME, lParam,
396                     0);
397 }
398
399 /***********************************************************************
400  *              VcpEnumFiles (SETUPX.@)
401  */
402 INT16 WINAPI VcpEnumFiles(VCPENUMPROC vep, LPARAM lParamRef)
403 {
404     WORD n;
405
406     for (n = 0; n < vn_last; n++)
407         vep(pvnlist[n], lParamRef);
408
409     return 0; /* FIXME: return value ? */
410 }
411
412 /***********************************************************************
413  *              VcpExplain (SETUPX.411)
414  */
415 LPCSTR WINAPI VcpExplain16(LPVIRTNODE lpVn, DWORD dwWhat)
416 {
417     static char buffer[MAX_PATH]; /* FIXME: is this how it's done ? */
418     buffer[0] = '\0';
419     switch (dwWhat)
420     {
421         case VCPEX_SRC_FULL:
422         case VCPEX_DST_FULL:
423             {
424                 LPVCPFILESPEC lpvfs =
425                     (dwWhat == VCPEX_SRC_FULL) ?  &lpVn->vfsSrc : &lpVn->vfsDst;
426
427                 /* if we have an ldid, use it, otherwise use the string */
428                 /* from the vhstrlist array */
429                 if (lpvfs->ldid != 0xffff)
430                   CtlGetLddPath16(lpvfs->ldid, buffer);
431                 else
432                   strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrDir));
433
434                 strcat(buffer, "\\");
435                 strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrFileName));
436             }
437             break;
438         default:
439             FIXME("%ld unimplemented !\n", dwWhat);
440             strcpy(buffer, "Unknown error");
441             break;
442     }
443     return buffer;
444 }
445
446 RETERR16 VCP_CheckPaths(void)
447 {
448     DWORD n;
449     LPVIRTNODE lpvn;
450     RETERR16 cbres;
451
452     cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKSTART, 0, 0, VCP_MsgRef);
453     for (n = 0; n < vn_num; n++)
454     {
455         lpvn = pvnlist[n];
456         if (!lpvn) continue;
457         /* FIXME: check paths of all VIRTNODEs here ! */
458         cbres = VCP_Callback(&lpvn->vfsDst, VCPM_CHECKPATH, 0, (DWORD)lpvn, VCP_MsgRef);
459     }
460     cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKEND, 0, 0, VCP_MsgRef);
461     return OK;
462 }
463
464 RETERR16 VCP_CopyFiles(void)
465 {
466     char fn_src[MAX_PATH], fn_dst[MAX_PATH];
467     RETERR16 res = OK, cbres;
468     DWORD n;
469     LPVIRTNODE lpvn;
470
471     cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYSTART, 0, 0, VCP_MsgRef);
472     for (n = 0; n < vn_num; n++)
473     {
474         lpvn = pvnlist[n];
475         if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_COPY)) continue;
476         /* FIXME: need to send VCPM_VSTATNEWDISK notification sometimes */
477         strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
478         strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
479         /* FIXME: what is this VCPM_VSTATWRITE here for ?
480          * I guess it's to signal successful destination file creation */
481         cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
482
483         /* FIXME: need to do the file copy in small chunks for notifications */
484         TRACE("copying '%s' to '%s'\n", fn_src, fn_dst);
485         /* perform the file copy */
486         if (!(CopyFileA(fn_src, fn_dst,
487                (lpvn->fl & VNLP_COPYIFEXISTS) ? FALSE : TRUE )))
488         {
489             ERR("error copying, src: %s -> dst: %s\n", fn_src, fn_dst);
490             res = ERR_VCP_IOFAIL;
491         }
492
493         vcp_status.prgFileRead.dwSoFar++;
494         cbres = VCP_Callback(&vcp_status, VCPM_VSTATREAD, 0, 0, VCP_MsgRef);
495         vcp_status.prgFileWrite.dwSoFar++;
496         cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
497     }
498
499     cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYEND, 0, 0, VCP_MsgRef);
500     return res;
501 }
502
503 /***********************************************************************
504  *              VcpFlush - internal (not exported), but documented
505  *
506  * VNFL_NOW is used for VcpFlush.
507  */
508 RETERR16 VcpFlush16(WORD fl, LPCSTR lpszBackupDest)
509 {
510     return OK;
511 }
512
513 /***********************************************************************
514  *              VcpClose (SETUPX.201)
515  *
516  * Does callbacks (-> vifproc) with VCPM_VSTATCLOSESTART,
517  * VCPM_VSTATCLOSEEND.
518  *
519  * fl gets VCPFL_xxx flags to indicate what to do with the
520  * VIRTNODEs (files to mess with) created by e.g. GenInstall()
521  */
522 RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest)
523 {
524     RETERR16 res = OK;
525     WORD cbres = VCPN_PROCEED;
526
527     TRACE("(%04x, '%s')\n", fl, lpszBackupDest);
528
529     /* FIXME: needs to sort virtnodes in case VCPFL_INSPECIFIEDORDER
530      * is not set. This is done by VCP_Callback(VCPM_NODECOMPARE) */
531
532     TRACE("#1\n");
533     memset(&vcp_status, 0, sizeof(VCPSTATUS));
534     /* yes, vcp_status.cbSize is 0 ! */
535     TRACE("#2\n");
536     cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSESTART, 0, 0, VCP_MsgRef);
537     TRACE("#3\n");
538
539     res = VCP_CheckPaths();
540     TRACE("#4\n");
541     if (res != OK)
542         return res; /* is this ok ? */
543     VCP_CopyFiles();
544
545     TRACE("#5\n");
546     cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSEEND, 0, 0, VCP_MsgRef);
547     TRACE("#6\n");
548     VCP_Proc = NULL;
549     FreeLibrary(SETUPAPI_hInstance);
550     VCP_opened = FALSE;
551     return OK;
552 }
553
554 RETERR16 VCP_RenameFiles(void)
555 {
556     char fn_src[MAX_PATH], fn_dst[MAX_PATH];
557     RETERR16 res = OK, cbres;
558     DWORD n;
559     LPVIRTNODE lpvn;
560
561     cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMESTART, 0, 0, VCP_MsgRef);
562     for (n = 0; n < vn_num; n++)
563     {
564         lpvn = pvnlist[n];
565         if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_RENAME)) continue;
566         strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
567         strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
568         cbres = VCP_Callback(&lpvn->vfsDst, VCPM_FILEOPENOUT, 0, (LPARAM)lpvn, VCP_MsgRef);
569         if (!(MoveFileExA(fn_src, fn_dst, MOVEFILE_REPLACE_EXISTING)))
570             res = ERR_VCP_IOFAIL;
571         else
572             VCP_VirtnodeDelete(lpvn);
573     }
574     cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMEEND, 0, 0, VCP_MsgRef);
575     return res;
576 }
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 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 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   = (WNDPROC)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 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 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, 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 }