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