- implement some more virtcopy (VCP) stuff
- add some setupx resources
- implement VHSTR functionality
- large parts of VCP callback handling
- merge setupapi and setupx stuff, especially resource handling
gets rid of setupx debug channel; setupapi is the only one that remains
diff --git a/dlls/setupapi/.cvsignore b/dlls/setupapi/.cvsignore
index c582135..8df8ae4 100644
--- a/dlls/setupapi/.cvsignore
+++ b/dlls/setupapi/.cvsignore
@@ -1,3 +1,5 @@
Makefile
+setupapi.res
setupapi.spec.c
setupx.spec.c
+virtcopy.glue.c
diff --git a/dlls/setupapi/Makefile.in b/dlls/setupapi/Makefile.in
index f2524b8..a77c806 100644
--- a/dlls/setupapi/Makefile.in
+++ b/dlls/setupapi/Makefile.in
@@ -13,7 +13,14 @@
devinst.c \
infparse.c \
setupx_main.c \
- stubs.c
+ stubs.c \
+ virtcopy.c
+
+GLUE = \
+ virtcopy.c
+
+RC_SRCS= \
+ setupapi.rc
@MAKE_DLL_RULES@
diff --git a/dlls/setupapi/infparse.c b/dlls/setupapi/infparse.c
index 26b97b9..2582dff 100644
--- a/dlls/setupapi/infparse.c
+++ b/dlls/setupapi/infparse.c
@@ -16,9 +16,9 @@
#include "heap.h"
#include "wine/winbase16.h"
#include "setupx16.h"
-#include "setupx_private.h"
+#include "setupapi_private.h"
-DEFAULT_DEBUG_CHANNEL(setupx);
+DEFAULT_DEBUG_CHANNEL(setupapi);
WORD InfNumEntries = 0;
INF_FILE *InfList = NULL;
diff --git a/dlls/setupapi/setupapi.rc b/dlls/setupapi/setupapi.rc
new file mode 100644
index 0000000..5bc79e2
--- /dev/null
+++ b/dlls/setupapi/setupapi.rc
@@ -0,0 +1,34 @@
+/*
+ * Top level resource file for SETUPX
+ *
+ */
+
+#include "windef.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "setupapi_private.h"
+
+/*--------------------- FIXME --------------------------
+ *
+ * These must be seperated into the language files
+ * and translated. The language 0,0 is a hack to get it
+ * loaded properly for all languages by pretending that
+ * they are neutral.
+ * The menus are not yet properly implemented.
+ * Don't localize it yet. (js)
+ */
+
+LANGUAGE 0,0
+
+COPYFILEDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE 20, 20, 208, 105
+STYLE DS_MODALFRAME | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION
+CAPTION "Copying Files..."
+FONT 8, "MS Sans Serif"
+BEGIN
+ PUSHBUTTON "Cancel", IDCANCEL, 79, 84, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ LTEXT "Source:", -1, 7, 7, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP
+ LTEXT "", SOURCESTRORD, 7, 18, 194, 11, WS_CHILD | WS_VISIBLE | WS_GROUP
+ LTEXT "Destination:", -1, 7, 30, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP
+ LTEXT "", DESTSTRORD, 7, 41, 194, 22, WS_CHILD | WS_VISIBLE | WS_GROUP
+ CONTROL "", PROGRESSORD, "setupx_progress", 7, 63, 194, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+END
diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec
index 7cc43cd..f030647 100644
--- a/dlls/setupapi/setupapi.spec
+++ b/dlls/setupapi/setupapi.spec
@@ -1,11 +1,13 @@
name setupapi
type win32
+rsrc setupapi.res
+import user32.dll
import advapi32.dll
import kernel32.dll
import ntdll.dll
-debug_channels (setupapi setupx)
+debug_channels (setupapi)
# almost all functions are commented out for now. Ordinals are from setupapi.dll 4.0
diff --git a/dlls/setupapi/setupapi_private.h b/dlls/setupapi/setupapi_private.h
new file mode 100644
index 0000000..e2400ce
--- /dev/null
+++ b/dlls/setupapi/setupapi_private.h
@@ -0,0 +1,39 @@
+#ifndef __SETUPAPI_PRIVATE_H
+#define __SETUPAPI_PRIVATE_H
+
+#include "wine/windef16.h"
+
+#define COPYFILEDLGORD 1000
+#define SOURCESTRORD 500
+#define DESTSTRORD 501
+#define PROGRESSORD 502
+
+
+#define REG_INSTALLEDFILES "System\\CurrentControlSet\\Control\\InstalledFiles"
+#define REGPART_RENAME "\\Rename"
+#define REG_VERSIONCONFLICT "Software\\Microsoft\\VersionConflictManager"
+
+typedef struct tagLDD_LIST {
+ LPLOGDISKDESC pldd;
+ struct tagLDD_LIST *next;
+} LDD_LIST;
+
+#define INIT_LDD(ldd, LDID) \
+ do { \
+ memset(&(ldd), 0, sizeof(LOGDISKDESC_S)); \
+ (ldd).cbSize = sizeof(LOGDISKDESC_S); \
+ ldd.ldid = LDID; \
+ } while(0)
+
+typedef struct {
+ HINF16 hInf;
+ HFILE hInfFile;
+ LPSTR lpInfFileName;
+} INF_FILE;
+
+extern INF_FILE *InfList;
+extern WORD InfNumEntries;
+
+extern LPCSTR IP_GetFileName(HINF16 hInf);
+
+#endif /* __SETUPAPI_PRIVATE_H */
diff --git a/dlls/setupapi/setupx.spec b/dlls/setupapi/setupx.spec
index b43bc44..8a84816 100644
--- a/dlls/setupapi/setupx.spec
+++ b/dlls/setupapi/setupx.spec
@@ -14,11 +14,11 @@
10 stub IpGetIntField #(word ptr word ptr)
11 stub IpFindNextLine #(word ptr)
12 stub IpGetFileName #(word ptr word)
-13 stub VcpQueueCopy #(str str str str word word ptr word long)
+13 pascal16 VcpQueueCopy(str str str str word word ptr word long) VcpQueueCopy16
14 stub NOAUTORUNWNDPROC
15 stub __DEBUGMSG
16 stub __ASSERTMSG
-17 stub VcpQueueDelete #(str str word long)
+17 pascal16 VcpQueueDelete(str str word long) VcpQueueDelete16
18 stub TpOpenFile #(str ptr word)
19 stub TpCloseFile #(word)
20 stub TpOpenSection #(word ptr str word)
@@ -62,6 +62,7 @@
61 stub suErrorToIds #(word word)
62 stub TPWriteProfileString #(str str str)
63 stub SURPLSETUP
+# does SUSTORELDIDPATH set the path of an LDID in the registry ?
64 stub SUSTORELDIDPATH
65 stub WILDCARDSTRCMPI
101 pascal16 GenInstall(word str word) GenInstall16
@@ -122,20 +123,20 @@
160 stub SXUPDATEDS
170 stub SUSETMEM
171 stub WriteDMFBootData #(word ptr word)
-200 pascal VcpOpen(ptr str) VcpOpen16
+200 pascal VcpOpen(segptr ptr) VcpOpen16
201 pascal VcpClose(word str) VcpClose16
-202 stub vcpDefCallbackProc #(ptr word word long long)
+202 pascal16 vcpDefCallbackProc(ptr word word long long) vcpDefCallbackProc16
203 stub vcpEnumFiles #(ptr long)
-204 stub VcpQueueRename #(str str str str word word long)
-205 stub vsmGetStringName #(word ptr word)
-206 stub vsmStringDelete #(word)
-207 stub vsmStringAdd #(str)
-208 stub vsmGetStringRawName #(word)
+204 pascal16 VcpQueueRename(str str str str word word long) VcpQueueRename16
+205 pascal16 vsmGetStringName(word ptr word) vsmGetStringName16
+206 pascal16 vsmStringDelete(word) vsmStringDelete16
+207 pascal16 vsmStringAdd(str) vsmStringAdd16
+208 pascal vsmGetStringRawName(word) vsmGetStringRawName16
209 stub IpSaveRestorePosition #(word word)
210 pascal16 IpGetProfileString(word str str ptr word) IpGetProfileString16
211 stub IpOpenEx #(str ptr word)
212 stub IpOpenAppendEx #(str word word)
-213 stub vcpUICallbackProc #(ptr word word long long)
+213 pascal16 vcpUICallbackProc(ptr word word long long) vcpUICallbackProc16
214 stub VcpAddMRUPath #(str)
300 stub DiBuildCompatDrvList #(ptr)
301 stub DiBuildClassDrvList #(ptr)
diff --git a/dlls/setupapi/setupx16.h b/dlls/setupapi/setupx16.h
index 12292fa..2094050 100644
--- a/dlls/setupapi/setupx16.h
+++ b/dlls/setupapi/setupx16.h
@@ -5,6 +5,7 @@
typedef UINT16 HINF16;
typedef UINT16 LOGDISKID16;
+typedef UINT16 VHSTR;
#define LINE_LEN 256
@@ -18,7 +19,7 @@
#define GEN_ERROR (UINT16)400
#define DI_ERROR (UINT16)500
-enum _IP_ERR {
+enum {
ERR_IP_INVALID_FILENAME = IP_ERROR+1,
ERR_IP_ALLOC_ERR,
ERR_IP_INVALID_SECT_NAME,
@@ -37,7 +38,113 @@
ERR_IP_INVALID_INFTYPE
};
-enum _ERR_VCP {
+/****** virtual copy operations ******/
+
+typedef DWORD LPEXPANDVTBL;
+
+typedef struct {
+ DWORD dwSoFar;
+ DWORD dwTotal;
+} VCPPROGRESS, *LPVCPPROGRESS;
+
+typedef struct {
+ WORD cbSize;
+ LOGDISKID16 ldid;
+ VHSTR vhstrRoot;
+ VHSTR vhstrVolumeLabel;
+ VHSTR vhstrDiskName;
+ WORD wVolumeTime;
+ WORD wVolumeDate;
+ DWORD dwSerialNumber;
+ WORD fl;
+ LPARAM lparamRef;
+
+ VCPPROGRESS prgFileRead;
+ VCPPROGRESS prgByteRead;
+
+ VCPPROGRESS prgFileWrite;
+ VCPPROGRESS prgByteWrite;
+} VCPDISKINFO, *LPVCPDISKINFO;
+
+typedef struct {
+ LOGDISKID16 ldid;
+ VHSTR vhstrDir;
+ VHSTR vhstrFileName;
+} VCPFILESPEC, *LPVCPFILESPEC;
+
+typedef struct {
+ UINT16 uiMDate;
+ UINT16 uiMTime;
+ UINT16 uiADate;
+ UINT16 uiATime;
+ UINT16 uiAttr;
+ DWORD llenIn;
+ DWORD llenOut;
+} VCPFATTR, *LPVCPFATTR;
+
+typedef struct {
+ UINT16 uDate;
+ UINT16 uTime;
+ DWORD dwSize;
+} VCPFILESTAT, *LPVCPFILESTAT;
+
+typedef struct
+{
+ HFILE16 hFileSrc;
+ HFILE16 hFileDst;
+ VCPFATTR fAttr;
+ WORD dosError;
+ VHSTR vhstrFileName;
+ WPARAM vcpm;
+} VIRTNODEEX, *LPVIRTNODEEX;
+
+typedef struct {
+ WORD cbSize;
+ VCPFILESPEC vfsSrc;
+ VCPFILESPEC vfsDst;
+ WORD fl;
+ LPARAM lParam;
+ LPEXPANDVTBL lpExpandVtbl;
+ LPVIRTNODEEX lpvnex;
+ VHSTR vhstrDstFinalName;
+ VCPFILESTAT vFileStat;
+} VIRTNODE, *LPVIRTNODE;
+
+typedef struct {
+ WORD cbSize;
+ VCPPROGRESS prgDiskRead;
+ VCPPROGRESS prgFileRead;
+ VCPPROGRESS prgByteRead;
+
+ VCPPROGRESS prgDiskWrite;
+ VCPPROGRESS prgFileWrite;
+ VCPPROGRESS prgByteWrite;
+
+ LPVCPDISKINFO lpvdiIn;
+ LPVCPDISKINFO lpvdiOut;
+ LPVIRTNODE lpvn;
+} VCPSTATUS, *LPVCPSTATUS;
+
+#define CNFL_BACKUP 0x0001
+#define CNFL_DELETEONFAILURE 0x0002
+#define CNFL_RENAMEONSUCCESS 0x0004
+#define CNFL_CONTINUATION 0x0008
+#define CNFL_SKIPPED 0x0010
+#define CNFL_IGNOREERRORS 0x0020
+#define CNFL_RETRYFILE 0x0040
+#define CNFL_COPIED 0x0080
+#define VNFL_UNIQUE 0x0000
+#define VNFL_MULTIPLEOK 0x0100
+#define VNFL_DESTROYOLD 0x0200
+#define VNFL_COPY 0x0000
+#define VNFL_DELETE 0x0800
+#define VNFL_RENAME 0x1000
+#define VNFL_NODE_TYPE (VNFL_RENAME|VNFL_DELETE|VNFL_COPY)
+#define VNFL_CREATED 0x2000
+#define VNFL_REJECTED 0x4000
+#define VNFL_DEVICEINSTALLER 0x8000
+
+enum {
ERR_VCP_IOFAIL = VCP_ERROR+1,
ERR_VCP_STRINGTOOLONG,
ERR_VCP_NOMEM,
@@ -65,6 +172,205 @@
ERR_VCP_NO_DIGITAL_SIGNATURE_FILE
};
+#define VCPN_OK 0
+#define VCPN_PROCEED 0
+#define VCPN_ABORT -1
+#define VCPN_RETRY -2
+#define VCPN_IGNORE -3
+#define VCPN_SKIP -4
+#define VCPN_FORCE -5
+#define VCPN_DEFER -6
+#define VCPN_FAIL -7
+#define VCPN_RETRYFILE -8
+
+#define VCPFL_ABANDON 0x00
+#define VCPFL_BACKUP 0x01
+#define VCPFL_COPY 0x02
+#define VCPFL_BACKUPANDCOPY (VCPFL_BACKUP|VCPFL_COPY)
+#define VCPFL_INSPECIFIEDORDER 0x04
+#define VCPFL_DELETE 0x08
+#define VCPFL_RENAME 0x10
+#define VCPFL_ALL (VCPFL_COPY|VCPFL_DELETE|VCPFL_RENAME)
+
+#define CFNL_BACKUP 0x0001
+#define CFNL_DELETEONFAILURE 0x0002
+#define CFNL_RENAMEONSUCCESS 0x0004
+#define CFNL_CONTINUATION 0x0008
+#define CFNL_SKIPPED 0x0010
+#define CFNL_IGNOREERRORS 0x0020
+#define CFNL_RETRYFILE 0x0040
+#define CFNL_COPIED 0x0080
+#define VFNL_MULTIPLEOK 0x0100
+#define VFNL_DESTROYOLD 0x0200
+#define VFNL_NOW 0x0400
+#define VFNL_COPY 0x0000
+#define VFNL_DELETE 0x0800
+#define VFNL_RENAME 0x1000
+#define VFNL_CREATED 0x2000
+#define VFNL_REJECTED 0x4000
+#define VCPM_DISKCLASS 0x01
+#define VCPM_DISKFIRST 0x0100
+#define VCPM_DISKLAST 0x01ff
+
+enum {
+ VCPM_DISKCREATEINFO = VCPM_DISKFIRST,
+ VCPM_DISKGETINFO,
+ VCPM_DISKDESTROYINFO,
+ VCPM_DISKPREPINFO,
+ VCPM_DISKENSURE,
+ VCPM_DISKPROMPT,
+ VCPM_DISKFORMATBEGIN,
+ VCPM_DISKFORMATTING,
+ VCPM_DISKFORMATEND
+};
+
+#define VCPM_FILEINCLASS 0x02
+#define VCPM_FILEOUTCLASS 0x03
+#define VCPM_FILEFIRSTIN 0x0200
+#define VCPM_FILEFIRSTOUT 0x0300
+#define VCPM_FILELAST 0x03ff
+
+enum {
+ VCPM_FILEOPENIN = VCPM_FILEFIRSTIN,
+ VCPM_FILEGETFATTR,
+ VCPM_FILECLOSEIN,
+ VCPM_FILECOPY,
+ VCPM_FILENEEDED,
+
+ VCPM_FILEOPENOUT = VCPM_FILEFIRSTOUT,
+ VCPM_FILESETFATTR,
+ VCPM_FILECLOSEOUT,
+ VCPM_FILEFINALIZE,
+ VCPM_FILEDELETE,
+ VCPM_FILERENAME
+};
+
+#define VCPM_NODECLASS 0x04
+#define VCPM_NODEFIRST 0x0400
+#define VCPM_NODELAST 0x04ff
+
+enum {
+ VCPM_NODECREATE = VCPM_NODEFIRST,
+ VCPM_NODEACCEPT,
+ VCPM_NODEREJECT,
+ VCPM_NODEDESTROY,
+ VCPM_NODECHANGEDESTDIR,
+ VCPM_NODECOMPARE
+};
+
+#define VCPM_TALLYCLASS 0x05
+#define VCPM_TALLYFIRST 0x0500
+#define VCPM_TALLYLAST 0x05ff
+
+enum {
+ VCPM_TALLYSTART = VCPM_TALLYFIRST,
+ VCPM_TALLYEND,
+ VCPM_TALLYFILE,
+ VCPM_TALLYDISK
+};
+
+#define VCPM_VERCLASS 0x06
+#define VCPM_VERFIRST 0x0600
+#define VCPM_VERLAST 0x06ff
+
+enum {
+ VCPM_VERCHECK = VCPM_VERFIRST,
+ VCPM_VERCHECKDONE,
+ VCPM_VERRESOLVECONFLICT
+};
+
+#define VCPM_VSTATCLASS 0x07
+#define VCPM_VSTATFIRST 0x0700
+#define VCPM_VSTATLAST 0x07ff
+
+enum {
+ VCPM_VSTATSTART = VCPM_VSTATFIRST,
+ VCPM_VSTATEND,
+ VCPM_VSTATREAD,
+ VCPM_VSTATWRITE,
+ VCPM_VSTATNEWDISK,
+ VCPM_VSTATCLOSESTART,
+ VCPM_VSTATCLOSEEND,
+ VCPM_VSTATBACKUPSTART,
+ VCPM_VSTATBACKUPEND,
+ VCPM_VSTATRENAMESTART,
+ VCPM_VSTATRENAMEEND,
+ VCPM_VSTATCOPYSTART,
+ VCPM_VSTATCOPYEND,
+ VCPM_VSTATDELETESTART,
+ VCPM_VSTATDELETEEND,
+ VCPM_VSTATPATHCHECKSTART,
+ VCPM_VSTATPATHCHECKEND,
+ VCPM_VSTATCERTIFYSTART,
+ VCPM_VSTATCERTIFYEND,
+ VCPM_VSTATUSERABORT,
+ VCPM_VSTATYIELD
+};
+
+#define VCPM_PATHCLASS 0x08
+#define VCPM_PATHFIRST 0x0800
+#define VCPM_PATHLAST 0x08ff
+
+enum {
+ VCPM_BUILDPATH = VCPM_PATHFIRST,
+ VCPM_UNIQUEPATH,
+ VCPM_CHECKPATH
+};
+
+#define VCPM_PATCHCLASS 0x09
+#define VCPM_PATCHFIRST 0x0900
+#define VCPM_PATCHLAST 0x09ff
+
+enum {
+ VCPM_FILEPATCHBEFORECPY = VCPM_PATCHFIRST,
+ VCPM_FILEPATCHAFTERCPY,
+ VCPM_FILEPATCHINFOPEN,
+ VCPM_FILEPATCHINFCLOSE
+};
+
+#define VCPM_CERTCLASS 0x0a
+#define VCPM_CERTFIRST 0x0a00
+#define VCPM_CERTLAST 0x0aff
+
+enum {
+ VCPM_FILECERTIFY = VCPM_CERTFIRST,
+ VCPM_FILECERTIFYWARN
+};
+
+typedef LRESULT CALLBACK (*VIFPROC)(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam, LPARAM lParam, LPARAM lparamRef);
+
+typedef int CALLBACK (*VCPENUMPROC)(LPVIRTNODE lpvn, LPARAM lparamRef);
+
+RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef);
+RETERR16 WINAPI VcpQueueCopy16(
+ LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
+ LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
+ LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
+ LPEXPANDVTBL lpExpandVtbl,
+ WORD fl, LPARAM lParam
+);
+RETERR16 VcpFlush16(WORD fl, LPCSTR lpszBackupDest);
+RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest);
+
+/* VcpExplain flags */
+enum {
+ VCPEX_SRC_DISK,
+ VCPEX_SRC_CABINET,
+ VCPEX_SRC_LOCN,
+ VCPEX_DST_LOCN,
+ VCPEX_SRC_FILE,
+ VCPEX_DST_FILE,
+ VCPEX_DST_FILE_FINAL,
+ VCPEX_DOS_ERROR,
+ VCPEX_MESSAGE,
+ VCPEX_DOS_SOLUTION,
+ VCPEX_SRC_FULL,
+ VCPEX_DST_FULL,
+ VCPEX_DST_FULL_FINAL
+};
+
+LPCSTR WINAPI VcpExplain16(LPVIRTNODE lpVn, DWORD dwWhat);
+
/****** logical disk management ******/
typedef struct _LOGDISKDESC_S { /* ldd */
@@ -198,8 +504,6 @@
} DEVICE_INFO16, *LPDEVICE_INFO16, **LPLPDEVICE_INFO16;
-typedef LRESULT CALLBACK (*VIFPROC)(LPVOID lpvObj, UINT uMsg, WPARAM wParam, LPARAM lParam, LPARAM lparamRef);
-
extern void WINAPI GenFormStrWithoutPlaceHolders16(LPSTR,LPCSTR,HINF16);
extern RETERR16 WINAPI IpOpen16(LPCSTR,HINF16 *);
extern RETERR16 WINAPI IpClose16(HINF16);
@@ -208,6 +512,7 @@
extern RETERR16 WINAPI CtlFindLdd16(LPLOGDISKDESC);
extern RETERR16 WINAPI CtlAddLdd16(LPLOGDISKDESC);
extern RETERR16 WINAPI CtlDelLdd16(LOGDISKID16);
+extern RETERR16 WINAPI CtlGetLddPath16(LOGDISKID16 ldid, LPSTR szPath);
extern RETERR16 WINAPI GenInstall16(HINF16,LPCSTR,WORD);
#endif /* __SETUPX16_H */
diff --git a/dlls/setupapi/setupx_main.c b/dlls/setupapi/setupx_main.c
index e0ef93a..dde4101 100644
--- a/dlls/setupapi/setupx_main.c
+++ b/dlls/setupapi/setupx_main.c
@@ -47,12 +47,12 @@
#include "winreg.h"
#include "wine/winuser16.h"
#include "setupx16.h"
-#include "setupx_private.h"
+#include "setupapi_private.h"
#include "winerror.h"
#include "heap.h"
#include "debugtools.h"
-DEFAULT_DEBUG_CHANNEL(setupx);
+DEFAULT_DEBUG_CHANNEL(setupapi);
/***********************************************************************
* SURegOpenKey
@@ -292,7 +292,7 @@
LPSTR *pSub;
DWORD count;
HINF16 hInf = 0;
- RETERR16 res = OK;
+ RETERR16 res = OK, tmp;
WORD wFlags;
BOOL reboot = FALSE;
HMODULE hMod;
@@ -310,6 +310,8 @@
res = ERROR_FILE_NOT_FOUND; /* yes, correct */
goto end;
}
+ if (VcpOpen16(NULL, 0))
+ goto end;
if (GenInstall16(hInf, *(pSub+count-2), GENINSTALL_DO_ALL) != OK)
goto end;
wFlags = atoi(*(pSub+count-1)) & ~128;
@@ -338,7 +340,12 @@
res = OK;
end:
- IpClose16(hInf);
+ tmp = VcpClose16(VCPFL_ALL, NULL);
+ if (tmp != OK)
+ res = tmp;
+ tmp = IpClose16(hInf);
+ if (tmp != OK)
+ res = tmp;
SETUPX_FreeSubStrings(pSub);
if (reboot)
{
@@ -502,7 +509,7 @@
* LDID == Logical Device ID
*
* The whole LDD/LDID business might go into a separate file named
- * ldd.c or logdevice.c.
+ * ldd.c.
* At the moment I don't know what the hell these functions are really doing.
* That's why I added reporting stubs.
* The only thing I do know is that I need them for the LDD/LDID infrastructure.
@@ -1048,28 +1055,6 @@
TRACE("ret '%s'\n", szDst);
}
-/***********************************************************************
- * VcpOpen
- *
- * No idea what to do here.
- */
-RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef)
-{
- FIXME("(%p, %08lx), stub.\n", vifproc, lparamMsgRef);
- return OK;
-}
-
-/***********************************************************************
- * VcpClose
- *
- * Is fl related to VCPDISKINFO.fl ?
- */
-RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest)
-{
- FIXME("(%04x, '%s'), stub.\n", fl, lpszBackupDest);
- return OK;
-}
-
/*
* Copy all items in a CopyFiles entry over to the destination
*
@@ -1077,26 +1062,29 @@
*/
static BOOL SETUPX_CopyFiles(LPSTR *pSub, HINF16 hInf)
{
- BOOL res = FALSE;
+ BOOL bSingle = FALSE;
unsigned int n;
LPCSTR filename = IP_GetFileName(hInf);
LPSTR pCopyEntry;
- char pDestStr[MAX_PATH];
+ char pDstStr[MAX_PATH];
LPSTR pSrcDir, pDstDir;
LPSTR pFileEntries, p;
WORD ldid;
LOGDISKDESC_S ldd;
LPSTR *pSubFile;
LPSTR pSrcFile, pDstFile;
+ WORD flag;
for (n=0; n < *(DWORD *)pSub; n++)
{
pCopyEntry = *(pSub+1+n);
if (*pCopyEntry == '@')
{
- ERR("single file not handled yet !\n");
- continue;
+ pCopyEntry++;
+ bSingle = TRUE;
}
+ else
+ bSingle = FALSE;
/* get source directory for that entry */
INIT_LDD(ldd, LDID_SRCPATH);
@@ -1105,20 +1093,35 @@
/* get destination directory for that entry */
if (!(GetPrivateProfileStringA("DestinationDirs", pCopyEntry, "",
- pDestStr, sizeof(pDestStr), filename)))
- continue;
+ pDstStr, sizeof(pDstStr), filename)))
+ {
+ /* hmm, not found; try the default entry */
+ if (!(GetPrivateProfileStringA("DestinationDirs", "DefaultDestDir", "", pDstStr, sizeof(pDstStr), filename)))
+ {
+ WARN("DefaultDestDir not found.\n");
+ continue;
+ }
+ }
/* translate destination dir if given as LDID */
- ldid = atoi(pDestStr);
+ ldid = atoi(pDstStr);
if (ldid)
{
if (!(SETUPX_IP_TranslateLDID(ldid, &pDstDir, hInf)))
continue;
}
else
- pDstDir = pDestStr;
+ pDstDir = pDstStr;
- /* now that we have the destination dir, iterate over files to copy */
+ /* now that we have the destination dir, register file copying */
+
+ if (bSingle)
+ {
+ VcpQueueCopy16(pCopyEntry, pCopyEntry, pSrcDir, pDstDir, LDID_SRCPATH, ldid ? ldid : 0xffff, 0, VFNL_COPY, 0);
+ return TRUE;
+ }
+
+ /* entry wasn't a single file, so let's iterate over section */
pFileEntries = SETUPX_GetSectionEntries(filename, pCopyEntry);
for (p=pFileEntries; *p; p +=strlen(p)+1)
{
@@ -1126,30 +1129,34 @@
pSrcFile = *(pSubFile+1);
pDstFile = (*(DWORD *)pSubFile > 1) ? *(pSubFile+2) : pSrcFile;
TRACE("copying file '%s\\%s' to '%s\\%s'\n", pSrcDir, pSrcFile, pDstDir, pDstFile);
+ flag = 0;
if (*(DWORD *)pSubFile > 2)
{
- WORD flag;
if ((flag = atoi(*(pSubFile+3)))) /* ah, flag */
{
if (flag & 0x2c)
FIXME("VNLP_xxx flag %d not handled yet.\n", flag);
}
else
- FIXME("temp file name '%s' given. Need to register in wininit.ini !\n", *(pSubFile+3)); /* strong guess that this is VcpQueueCopy() */
+ {
+ FIXME("temp file name '%s' given. Need to register in wininit.ini !\n", *(pSubFile+3));
+ /* we probably need to set VIRTNODE.vhstrDstFinalName to
+ * the final destination name, and the temp name is merely
+ * the copy destination */
+ }
}
+ VcpQueueCopy16(pSrcFile, pDstFile, pSrcDir, pDstDir, LDID_SRCPATH, ldid ? ldid : 0xffff, 0, VFNL_COPY|flag, 0);
SETUPX_FreeSubStrings(pSubFile);
- /* we don't copy ANYTHING yet ! (I'm too lazy and want to verify
- * this first before destroying whole partitions ;-) */
}
}
- return res;
+ return TRUE;
}
/***********************************************************************
* GenInstall
*
- * general install function for .INF file sections
+ * generic installer function for .INF file sections
*
* This is not perfect - patch whenever you can !
*
diff --git a/dlls/setupapi/setupx_private.h b/dlls/setupapi/setupx_private.h
deleted file mode 100644
index dc73255..0000000
--- a/dlls/setupapi/setupx_private.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __SETUPX_PRIVATE_H
-#define __SETUPX_PRIVATE_H
-
-#include "wine/windef16.h"
-
-typedef struct tagLDD_LIST {
- LPLOGDISKDESC pldd;
- struct tagLDD_LIST *next;
-} LDD_LIST;
-
-#define INIT_LDD(ldd, LDID) \
- do { \
- memset(&(ldd), 0, sizeof(LOGDISKDESC_S)); \
- (ldd).cbSize = sizeof(LOGDISKDESC_S); \
- ldd.ldid = LDID; \
- } while(0)
-
-typedef struct {
- HINF16 hInf;
- HFILE hInfFile;
- LPSTR lpInfFileName;
-} INF_FILE;
-
-extern INF_FILE *InfList;
-extern WORD InfNumEntries;
-
-extern LPCSTR IP_GetFileName(HINF16 hInf);
-
-#endif /* __SETUPX_PRIVATE_H */
diff --git a/dlls/setupapi/virtcopy.c b/dlls/setupapi/virtcopy.c
new file mode 100644
index 0000000..3cd7459
--- /dev/null
+++ b/dlls/setupapi/virtcopy.c
@@ -0,0 +1,709 @@
+/*
+ * SetupAPI virtual copy operations
+ *
+ * FIXME: we now rely on builtin setupapi.dll for dialog resources.
+ * This is bad ! We ought to have 16bit resource handling working.
+ */
+
+#include <string.h>
+#include "debugtools.h"
+#include "windef.h"
+#include "setupx16.h"
+#include "heap.h"
+#include "callback.h"
+#include "stackframe.h"
+#include "winreg.h"
+#include "setupapi_private.h"
+
+DEFAULT_DEBUG_CHANNEL(setupapi);
+
+/* ### start build ### */
+extern WORD CALLBACK VCP_CallTo16_word_lwwll(FARPROC16,LPVOID,UINT16,WPARAM,LPARAM,LPARAM);
+/* ### stop build ### */
+
+static FARPROC16 VCP_Proc = NULL;
+static LPARAM VCP_MsgRef = 0;
+
+#define VCP_CALLBACK(obj,msg,wParam,lParam,lParamRef) \
+ (VCP_Proc) ? \
+ VCP_CallTo16_word_lwwll(VCP_Proc, obj,msg,wParam,lParam,lParamRef) : OK;
+
+static BOOL VCP_opened = FALSE;
+
+static VCPSTATUS vcp_status;
+
+static HINSTANCE SETUPAPI_hInstance;
+
+/****************************** VHSTR management ******************************/
+
+/*
+ * This is a totally braindead implementation for now;
+ * I don't care about speed at all ! Size and implementation time
+ * is much more important IMHO. I could have created some sophisticated
+ * tree structure, but... what the hell ! :-)
+ */
+typedef struct {
+ DWORD refcount;
+ LPCSTR pStr;
+} VHSTR_STRUCT;
+
+static VHSTR_STRUCT **vhstrlist = NULL;
+static VHSTR vhstr_alloc = 0;
+
+#define VALID_VHSTR(x) ((x < vhstr_alloc) && (vhstrlist[x]) && (vhstrlist[x]->refcount))
+
+VHSTR WINAPI vsmStringAdd16(LPCSTR lpszName)
+{
+ VHSTR n;
+ VHSTR index = 0xffff;
+ HANDLE heap;
+
+ TRACE("add string '%s'\n", lpszName);
+ /* search whether string already inserted */
+ for (n = 0; n < vhstr_alloc; n++)
+ {
+ if ((vhstrlist[n]) && (vhstrlist[n]->refcount))
+ {
+ TRACE("comp %d\n", n);
+ if (!strcmp(vhstrlist[n]->pStr, lpszName))
+ {
+ vhstrlist[n]->refcount++;
+ return n;
+ }
+ }
+ }
+
+ /* hmm, not found yet, let's insert it */
+ for (n = 0; n < vhstr_alloc; n++)
+ {
+ if ((!(vhstrlist[n])) || (!(vhstrlist[n]->refcount)))
+ {
+ index = n;
+ break;
+ }
+ }
+ heap = GetProcessHeap();
+ if (n == vhstr_alloc) /* hmm, no free index found yet */
+ {
+ index = vhstr_alloc;
+ vhstr_alloc += 20;
+ vhstrlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, vhstrlist,
+ sizeof(VHSTR_STRUCT *) * vhstr_alloc);
+ }
+ if (index == 0xffff)
+ return 0xffff; /* failure */
+ if (!vhstrlist[index])
+ vhstrlist[index] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VHSTR_STRUCT));
+ vhstrlist[index]->refcount = 1;
+ vhstrlist[index]->pStr = HeapAlloc(heap, 0, strlen(lpszName)+1);
+ strcpy((LPSTR)vhstrlist[index]->pStr, lpszName);
+ return index;
+}
+
+INT16 WINAPI vsmStringDelete16(VHSTR vhstr)
+{
+ if (VALID_VHSTR(vhstr))
+ {
+ vhstrlist[vhstr]->refcount--;
+ if (!vhstrlist[vhstr]->refcount)
+ {
+ HeapFree(GetProcessHeap(), 0, (LPSTR)vhstrlist[vhstr]->pStr);
+ vhstrlist[vhstr]->pStr = NULL;
+ }
+ return VCPN_OK;
+ }
+
+ /* string not found */
+ return VCPN_FAIL;
+}
+
+/*
+ * vsmStringFind() - not exported from a standard SETUPX.DLL, it seems
+ */
+VHSTR WINAPI vsmStringFind16(LPCSTR lpszName)
+{
+ WORD n;
+ for (n = 0; n < vhstr_alloc; n++)
+ if ((vhstrlist[n]) && (vhstrlist[n]->refcount) && (!strcmp(vhstrlist[n]->pStr, lpszName)))
+ return n;
+ return 0xffff;
+}
+
+/*
+ * vsmGetStringName()
+ *
+ * Pretty correct, I guess
+ */
+INT16 WINAPI vsmGetStringName16(VHSTR vhstr, LPSTR lpszBuffer, int cbBuffer)
+{
+ if (VALID_VHSTR(vhstr))
+ {
+ int len = strlen(vhstrlist[vhstr]->pStr)+1;
+ if (cbBuffer >= len)
+ {
+ if (lpszBuffer)
+ strcpy(lpszBuffer, vhstrlist[vhstr]->pStr);
+ return len;
+ }
+ }
+ return VCPN_FAIL;
+}
+
+/*
+ * vsmStringCompare() - not exported from a standard SETUPX.DLL, it seems
+ */
+INT16 WINAPI vsmStringCompare16(VHSTR vhstrA, VHSTR vhstrB)
+{
+ if ((!VALID_VHSTR(vhstrA)) || (!VALID_VHSTR(vhstrB)))
+ return VCPN_FAIL; /* correct ? */
+ return strcmp(vhstrlist[vhstrA]->pStr, vhstrlist[vhstrB]->pStr);
+}
+
+LPCSTR WINAPI vsmGetStringRawName16(VHSTR vhstr)
+{
+ return (VALID_VHSTR(vhstr)) ? vhstrlist[vhstr]->pStr : NULL;
+}
+
+
+/***************************** VIRTNODE management ****************************/
+static LPVIRTNODE *pvnlist = NULL;
+static DWORD vn_num = 0;
+static DWORD vn_last = 0;
+
+RETERR16 VCP_VirtnodeCreate(LPVCPFILESPEC vfsSrc, LPVCPFILESPEC vfsDst, WORD fl, LPARAM lParam, LPEXPANDVTBL lpExpandVtbl)
+{
+ HANDLE heap;
+ LPVIRTNODE lpvn;
+ RETERR16 cbres;
+
+ while (vn_last < vn_num)
+ {
+ if (pvnlist[vn_last] == NULL)
+ break;
+ vn_last++;
+ }
+ heap = GetProcessHeap();
+ if (vn_last == vn_num)
+ {
+ vn_num += 20;
+ pvnlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, pvnlist,
+ sizeof(LPVIRTNODE *) * vn_num);
+ }
+ pvnlist[vn_last] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VIRTNODE));
+ lpvn = pvnlist[vn_last];
+ vn_last++;
+
+ lpvn->cbSize = sizeof(VIRTNODE);
+
+ if (vfsSrc)
+ memcpy(&lpvn->vfsSrc, vfsSrc, sizeof(VCPFILESPEC));
+
+ if (vfsDst)
+ memcpy(&lpvn->vfsDst, vfsDst, sizeof(VCPFILESPEC));
+
+ lpvn->fl = fl;
+ lpvn->lParam = lParam;
+ lpvn->lpExpandVtbl = lpExpandVtbl;
+
+ lpvn->vhstrDstFinalName = 0xffff; /* FIXME: what is this ? */
+
+ cbres = VCP_CALLBACK(lpvn, VCPM_NODECREATE, 0, 0, VCP_MsgRef);
+ lpvn->fl |= VFNL_CREATED;
+ cbres = VCP_CALLBACK(lpvn, VCPM_NODEACCEPT, 0, 0, VCP_MsgRef);
+
+ return OK;
+}
+
+BOOL VCP_VirtnodeDelete(LPVIRTNODE lpvnDel)
+{
+ DWORD n;
+ RETERR16 cbres;
+
+ for (n = 0; n < vn_last; n++)
+ {
+ if (pvnlist[n] == lpvnDel)
+ {
+ cbres = VCP_CALLBACK(lpvnDel, VCPM_NODEDESTROY, 0, 0, VCP_MsgRef);
+ HeapFree(GetProcessHeap(), 0, lpvnDel);
+ pvnlist[n] = NULL;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/***********************************************************************
+ * VcpOpen
+ *
+ * Sets up a virtual copy operation.
+ * This means that functions such as GenInstall()
+ * create a VIRTNODE struct for every file to be touched in a .INF file
+ * instead of actually touching the file.
+ * The actual copy/move/rename gets started when VcpClose or
+ * VcpFlush is called; several different callbacks are made
+ * (copy, rename, open, close, version conflicts, ...) on every file copied.
+ */
+RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef)
+{
+ TRACE("(%p, %08lx)\n", vifproc, lparamMsgRef);
+ if (VCP_opened)
+ return ERR_VCP_BUSY;
+
+ VCP_Proc = (FARPROC16)vifproc;
+ VCP_MsgRef = lparamMsgRef;
+
+ /* load SETUPAPI needed for dialog resources etc. */
+ SETUPAPI_hInstance = LoadLibraryA("setupapi.dll");
+ if (!SETUPAPI_hInstance)
+ {
+ ERR("Could not load sibling setupapi.dll\n");
+ return ERR_VCP_NOMEM;
+ }
+ VCP_opened = TRUE;
+ return OK;
+}
+
+/***********************************************************************
+ * VcpQueueCopy [SETUPX.13]
+ *
+ * lpExpandVtbl seems to be deprecated.
+ * fl are the CNFL_xxx and VNFL_xxx flags.
+ * lParam are the VNLP_xxx flags.
+ */
+RETERR16 WINAPI VcpQueueCopy16(
+ LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
+ LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
+ LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
+ LPEXPANDVTBL lpExpandVtbl,
+ WORD fl, LPARAM lParam
+)
+{
+ VCPFILESPEC vfsSrc, vfsDst;
+
+ if (!VCP_opened)
+ return ERR_VCP_NOTOPEN;
+
+ vfsSrc.ldid = ldidSrc;
+ vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
+ vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
+
+ vfsDst.ldid = ldidDst;
+ vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
+ vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
+
+ return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, fl, lParam,
+ lpExpandVtbl);
+}
+
+/***********************************************************************
+ * VcpQueueDelete [SETUPX.17]
+ *
+ * Is lParamRef the same as lParam in VcpQueueCopy ?
+ * Damn docu !! Err... which docu ?
+ */
+RETERR16 WINAPI VcpQueueDelete16(
+ LPCSTR lpszDstFileName,
+ LPCSTR lpszDstDir,
+ LOGDISKID16 ldidDst,
+ LPEXPANDVTBL lpExpandVtbl,
+ LPARAM lParamRef
+)
+{
+ VCPFILESPEC vfsDst;
+
+ if (!VCP_opened)
+ return ERR_VCP_NOTOPEN;
+
+ vfsDst.ldid = ldidDst;
+ vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
+ vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
+
+ return VCP_VirtnodeCreate(NULL, &vfsDst, VNFL_DELETE, lParamRef,
+ lpExpandVtbl);
+}
+
+/***********************************************************************
+ * VcpQueueRename [SETUPX.204]
+ *
+ */
+RETERR16 WINAPI VcpQueueRename16(
+ LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
+ LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
+ LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
+ LPARAM lParam
+)
+{
+ VCPFILESPEC vfsSrc, vfsDst;
+
+ if (!VCP_opened)
+ return ERR_VCP_NOTOPEN;
+
+ vfsSrc.ldid = ldidSrc;
+ vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
+ vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
+
+ vfsDst.ldid = ldidDst;
+ vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
+ vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
+
+ return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, VNFL_RENAME, lParam,
+ 0);
+}
+
+INT16 WINAPI VcpEnumFiles(VCPENUMPROC vep, LPARAM lParamRef)
+{
+ WORD n;
+
+ for (n = 0; n < vn_last; n++)
+ vep(pvnlist[n], lParamRef);
+
+ return 0; /* FIXME: return value ? */
+}
+
+LPCSTR WINAPI VcpExplain16(LPVIRTNODE lpVn, DWORD dwWhat)
+{
+ static char buffer[MAX_PATH]; /* FIXME: is this how it's done ? */
+ buffer[0] = '\0';
+ switch (dwWhat)
+ {
+ case VCPEX_SRC_FULL:
+ case VCPEX_DST_FULL:
+ {
+ LPVCPFILESPEC lpvfs =
+ (dwWhat == VCPEX_SRC_FULL) ? &lpVn->vfsSrc : &lpVn->vfsDst;
+
+ if (lpvfs->ldid != 0xffff)
+ CtlGetLddPath16(lpvfs->ldid, buffer);
+ strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrDir));
+ strcat(buffer, "\\");
+ strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrFileName));
+ }
+ break;
+ default:
+ FIXME("%ld unimplemented !\n", dwWhat);
+ strcpy(buffer, "Unknown error");
+ break;
+ }
+ return buffer;
+}
+
+RETERR16 VCP_CheckPaths(void)
+{
+ DWORD n;
+ LPVIRTNODE lpvn;
+ RETERR16 cbres;
+
+ cbres = VCP_CALLBACK(&vcp_status, VCPM_VSTATPATHCHECKSTART, 0, 0, VCP_MsgRef);
+ for (n = 0; n < vn_num; n++)
+ {
+ lpvn = pvnlist[n];
+ if (!lpvn) continue;
+ /* FIXME: check paths of all VIRTNODEs here ! */
+ cbres = VCP_CALLBACK(&lpvn->vfsDst, VCPM_CHECKPATH, 0, (DWORD)lpvn, VCP_MsgRef);
+ }
+ cbres = VCP_CALLBACK(&vcp_status, VCPM_VSTATPATHCHECKEND, 0, 0, VCP_MsgRef);
+ return OK;
+}
+
+RETERR16 VCP_CopyFiles(void)
+{
+ char fn_src[MAX_PATH], fn_dst[MAX_PATH];
+ RETERR16 res = OK, cbres;
+ DWORD n;
+ LPVIRTNODE lpvn;
+
+ cbres = VCP_CALLBACK(&vcp_status, VCPM_VSTATCOPYSTART, 0, 0, VCP_MsgRef);
+ for (n = 0; n < vn_num; n++)
+ {
+ lpvn = pvnlist[n];
+ if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_COPY)) continue;
+ /* FIXME: need to send VCPM_VSTATNEWDISK notification sometimes */
+ strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
+ strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
+ /* FIXME: what is this VCPM_VSTATWRITE here for ?
+ * I guess it's to signal successful destination file creation */
+ cbres = VCP_CALLBACK(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
+ /* FIXME: need to do the file copy in small chunks for notifications */
+ TRACE("copying '%s' to '%s'\n", fn_src, fn_dst);
+#if DO_A_REAL_COPY
+ if (!(CopyFileA(fn_src, fn_dst, TRUE)))
+ res = ERR_VCP_IOFAIL;
+#endif
+ vcp_status.prgFileRead.dwSoFar++;
+ cbres = VCP_CALLBACK(&vcp_status, VCPM_VSTATREAD, 0, 0, VCP_MsgRef);
+ vcp_status.prgFileWrite.dwSoFar++;
+ cbres = VCP_CALLBACK(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
+ }
+
+ cbres = VCP_CALLBACK(&vcp_status, VCPM_VSTATCOPYEND, 0, 0, VCP_MsgRef);
+ return res;
+}
+
+/***********************************************************************
+ * VcpFlush - internal (not exported), but documented
+ *
+ * VNFL_NOW is used for VcpFlush.
+ */
+RETERR16 VcpFlush16(WORD fl, LPCSTR lpszBackupDest)
+{
+ return OK;
+}
+
+/***********************************************************************
+ * VcpClose
+ *
+ * Does callbacks (-> vifproc) with VCPM_VSTATCLOSESTART,
+ * VCPM_VSTATCLOSEEND.
+ *
+ * fl gets VCPFL_xxx flags to indicate what to do with the
+ * VIRTNODEs (files to mess with) created by e.g. GenInstall()
+ */
+RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest)
+{
+ RETERR16 res = OK;
+ WORD cbres = VCPN_PROCEED;
+
+ TRACE("(%04x, '%s')\n", fl, lpszBackupDest);
+
+ /* FIXME: needs to sort virtnodes in case VCPFL_INSPECIFIEDORDER
+ * is not set. This is done by VCP_CALLBACK(VCPM_NODECOMPARE) */
+
+ TRACE("#1\n");
+ memset(&vcp_status, 0, sizeof(VCPSTATUS));
+ /* yes, vcp_status.cbSize is 0 ! */
+ TRACE("#2\n");
+ cbres = VCP_CALLBACK(&vcp_status, VCPM_VSTATCLOSESTART, 0, 0, VCP_MsgRef);
+ TRACE("#3\n");
+
+ res = VCP_CheckPaths();
+ TRACE("#4\n");
+ if (res != OK)
+ return res; /* is this ok ? */
+ VCP_CopyFiles();
+
+ TRACE("#5\n");
+ cbres = VCP_CALLBACK(&vcp_status, VCPM_VSTATCLOSEEND, 0, 0, VCP_MsgRef);
+ TRACE("#6\n");
+ VCP_Proc = NULL;
+ FreeLibrary(SETUPAPI_hInstance);
+ VCP_opened = FALSE;
+ return OK;
+}
+
+RETERR16 VCP_RenameFiles(void)
+{
+ char fn_src[MAX_PATH], fn_dst[MAX_PATH];
+ RETERR16 res = OK, cbres;
+ DWORD n;
+ LPVIRTNODE lpvn;
+
+ cbres = VCP_CALLBACK(&vcp_status, VCPM_VSTATRENAMESTART, 0, 0, VCP_MsgRef);
+ for (n = 0; n < vn_num; n++)
+ {
+ lpvn = pvnlist[n];
+ if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_RENAME)) continue;
+ strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
+ strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
+ cbres = VCP_CALLBACK(&lpvn->vfsDst, VCPM_FILEOPENOUT, 0, (LPARAM)lpvn, VCP_MsgRef);
+ if (!(MoveFileExA(fn_src, fn_dst, MOVEFILE_REPLACE_EXISTING)))
+ res = ERR_VCP_IOFAIL;
+ else
+ VCP_VirtnodeDelete(lpvn);
+ }
+ cbres = VCP_CALLBACK(&vcp_status, VCPM_VSTATRENAMEEND, 0, 0, VCP_MsgRef);
+ return res;
+}
+
+RETERR16 WINAPI vcpDefCallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
+ LPARAM lParam, LPARAM lParamRef)
+{
+ static int count = 0;
+ if (count < 10)
+ FIXME("(%p, %04x, %04x, %08lx, %08lx) - what to do here ?\n",
+ lpvObj, uMsg, wParam, lParam, lParamRef);
+ count++;
+ return OK;
+}
+
+/********************* point-and-click stuff from here ***********************/
+
+static HWND hDlgCopy = 0;
+static HKEY hKeyFiles = 0, hKeyRename = 0, hKeyConflict = 0;
+static char BackupDir[12];
+
+static BOOL CALLBACK VCP_UI_FileCopyDlgProc(HWND hWndDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL retval = FALSE;
+
+ if (iMsg == WM_INITDIALOG)
+ {
+ ShowWindow(hWndDlg, SW_SHOWNORMAL);
+ UpdateWindow(hWndDlg);
+ retval = TRUE;
+ }
+ return retval;
+}
+
+BOOL VCP_UI_GetDialogTemplate(LPCVOID *template32)
+{
+ HANDLE hResInfo, hDlgTmpl32;
+
+ if (!(hResInfo = FindResourceA(SETUPAPI_hInstance, MAKEINTRESOURCEA(COPYFILEDLGORD), RT_DIALOGA)))
+ return FALSE;
+ if (!(hDlgTmpl32 = LoadResource(SETUPAPI_hInstance, hResInfo )) ||
+ !(*template32 = LockResource( hDlgTmpl32 )))
+ return FALSE;
+ return TRUE;
+}
+
+static LRESULT WINAPI
+VCP_UI_FileCopyWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (uMsg != WM_CREATE)
+ return DefWindowProcA (hwnd, uMsg, wParam, lParam);
+
+ switch (uMsg)
+ {
+ case WM_CREATE:
+ return 0;
+ default:
+ FIXME("%04x: unhandled.\n", uMsg);
+ }
+
+ return 0;
+}
+
+void VCP_UI_RegisterProgressClass(void)
+{
+ static BOOL registered = FALSE;
+ WNDCLASSA wndClass;
+
+ if (registered)
+ return;
+
+ registered = TRUE;
+ ZeroMemory (&wndClass, sizeof(WNDCLASSA));
+ wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
+ wndClass.lpfnWndProc = (WNDPROC)VCP_UI_FileCopyWndProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = 0;
+ wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
+ wndClass.hbrBackground = (HBRUSH)NULL;
+ wndClass.lpszClassName = "setupx_progress";
+
+ RegisterClassA (&wndClass);
+}
+
+RETERR16 VCP_UI_NodeCompare(LPVIRTNODE vn1, LPVIRTNODE vn2)
+{
+ LPCSTR file1, file2;
+ file1 = vsmGetStringRawName16(vn1->vfsSrc.vhstrFileName);
+ file2 = vsmGetStringRawName16(vn2->vfsSrc.vhstrFileName);
+ return (RETERR16)strcmp(file1, file2);
+}
+
+RETERR16 VCP_UI_CopyStart(void)
+{
+ LPCVOID template32;
+ char buf[256]; /* plenty */
+ BOOL dirty;
+ DWORD len;
+
+ /* FIXME: should be registered at DLL startup instead */
+ VCP_UI_RegisterProgressClass();
+ if (!(VCP_UI_GetDialogTemplate(&template32)))
+ return VCPN_FAIL;
+
+ hDlgCopy = CreateDialogIndirectParamA(SETUPAPI_hInstance, template32, 0,
+ VCP_UI_FileCopyDlgProc, 0);
+ if (!hDlgCopy)
+ return VCPN_FAIL;
+ SetDlgItemTextA(hDlgCopy, SOURCESTRORD, "Scanning ...");
+ SetDlgItemTextA(hDlgCopy, DESTSTRORD, "NOT_IMPLEMENTED_YET");
+ strcpy(buf, REG_INSTALLEDFILES);
+ if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyFiles))
+ return VCPN_FAIL;
+ strcat(buf, REGPART_RENAME);
+ if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyRename))
+ return VCPN_FAIL;
+ if (RegCreateKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT, &hKeyConflict))
+ return VCPN_FAIL;
+ len = 1;
+ if (!(RegQueryValueExA(hKeyConflict, "Dirty", NULL, 0, (LPBYTE)&dirty, &len)))
+ {
+ /* FIXME: what does SETUPX.DLL do in this case ? */
+ MESSAGE("Warning: another program using SETUPX is already running ! Failed.\n");
+ return VCPN_FAIL;
+ }
+ dirty = TRUE;
+ if (RegSetValueExA(hKeyConflict, "Dirty", 0, REG_BINARY, (LPBYTE)&dirty, 1))
+ return VCPN_FAIL;
+ len = 12;
+ if (!(RegQueryValueExA(hKeyConflict, "BackupDirectory", NULL, 0, BackupDir, &len)))
+ strcpy(BackupDir, "VCM");
+
+ /* create C:\WINDOWS\[BackupDir] and set registry key to it */
+ GetWindowsDirectoryA(buf, 256);
+ strcat(buf, "\\");
+ strcat(buf, BackupDir);
+ if (!(CreateDirectoryA(buf, NULL)))
+ return VCPN_FAIL;
+ if (RegSetValueExA(hKeyConflict, "BackupDirectory", 0, REG_SZ, (LPBYTE)buf, strlen(buf)+1))
+ return VCPN_FAIL;
+ RegCloseKey(hKeyConflict);
+
+ return VCPN_OK;
+}
+
+RETERR16 WINAPI vcpUICallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
+ LPARAM lParam, LPARAM lParamRef)
+{
+ static int count = 0;
+ RETERR16 res = VCPN_OK, cbres;
+
+ if (count < 5)
+ FIXME("(%p, %04x, %04x, %08lx, %08lx) - semi-stub\n",
+ lpvObj, uMsg, wParam, lParam, lParamRef);
+ count++;
+ switch (uMsg)
+ {
+ /* unused messages, it seems */
+ case VCPM_DISKPREPINFO:
+
+ case VCPM_FILENEEDED:
+
+ case VCPM_NODECREATE:
+ case VCPM_NODEACCEPT:
+
+ case VCPM_VSTATCLOSESTART:
+ case VCPM_VSTATPATHCHECKSTART:
+ case VCPM_VSTATPATHCHECKEND:
+
+ case VCPM_CHECKPATH:
+ break;
+
+ /* the real stuff */
+ case VCPM_NODECOMPARE:
+ res = VCP_UI_NodeCompare((LPVIRTNODE)lpvObj, (LPVIRTNODE)lParam);
+ break;
+ case VCPM_VSTATREAD:
+ break;
+ case VCPM_VSTATWRITE:
+ cbres = VCP_CALLBACK(&vcp_status, VCPM_DISKPREPINFO, 0, 0, VCP_MsgRef);
+ break;
+ case VCPM_VSTATCLOSEEND:
+ RegCloseKey(hKeyFiles);
+ RegCloseKey(hKeyRename);
+ RegDeleteKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT);
+ break;
+ case VCPM_VSTATCOPYSTART:
+ res = VCP_UI_CopyStart();
+ break;
+ case VCPM_VSTATCOPYEND:
+ DestroyWindow(hDlgCopy);
+ break;
+ default:
+ FIXME("unhandled msg 0x%04x\n", uMsg);
+ }
+ return res;
+}