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