diff --git a/dlls/setupapi/Makefile.in b/dlls/setupapi/Makefile.in index d9623535136..f2524b8e0c5 100644 --- a/dlls/setupapi/Makefile.in +++ b/dlls/setupapi/Makefile.in @@ -10,6 +10,7 @@ LDDLLFLAGS = @LDDLLFLAGS@ SYMBOLFILE = $(MODULE).tmp.o C_SRCS = \ + devinst.c \ infparse.c \ setupx_main.c \ stubs.c diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c new file mode 100644 index 00000000000..fc96bbcecf8 --- /dev/null +++ b/dlls/setupapi/devinst.c @@ -0,0 +1,28 @@ +/* + * SetupAPI device installer + * + */ + +#include "debugtools.h" +#include "windef.h" +#include "setupx16.h" +#include "heap.h" + +DEFAULT_DEBUG_CHANNEL(setupapi); + +/* + * Return a list of installed system devices. + * Uses HKLM\\ENUM to list devices. + */ +RETERR16 WINAPI DiGetClassDevs16(LPLPDEVICE_INFO16 lplpdi, + LPCSTR lpszClassName, HWND16 hwndParent, INT16 iFlags) +{ + LPDEVICE_INFO16 lpdi; + + FIXME("(%p, '%s', %04x, %04x), semi-stub.\n", + lplpdi, lpszClassName, hwndParent, iFlags); + lpdi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DEVICE_INFO16)); + lpdi->cbSize = sizeof(DEVICE_INFO16); + *lplpdi = lpdi; + return OK; +} diff --git a/dlls/setupapi/infparse.c b/dlls/setupapi/infparse.c index e0958348068..8adfc6f91e0 100644 --- a/dlls/setupapi/infparse.c +++ b/dlls/setupapi/infparse.c @@ -1,7 +1,12 @@ /* * SetupX .inf file parsing functions * - * FIXME: return values ??? + * FIXME: + * - return values ??? + * - this should be reimplemented at some point to have its own + * file parsing instead of using profile functions, + * as some SETUPX exports probably demand that + * (IpSaveRestorePosition, IpFindNextMatchLine, ...). */ #include "debugtools.h" @@ -10,6 +15,7 @@ #include "heap.h" #include "wine/winbase16.h" #include "setupx16.h" +#include "setupx_private.h" DEFAULT_DEBUG_CHANNEL(setupx); diff --git a/dlls/setupapi/setupx.spec b/dlls/setupapi/setupx.spec index 4b2f90ded0a..29bdd4838a7 100644 --- a/dlls/setupapi/setupx.spec +++ b/dlls/setupapi/setupx.spec @@ -4,83 +4,84 @@ owner setupapi 1 stub WEP 2 pascal16 IpOpen(str ptr) IpOpen16 -3 stub IPOPENAPPEND +3 stub IpOpenAppend #(str word) 4 pascal16 IpClose(word) IpClose16 -5 stub IPGETLONGFIELD -6 stub IPGETSTRINGFIELD -7 stub IPFINDFIRSTLINE -8 stub IPGETLINECOUNT -9 stub IPGETFIELDCOUNT -10 stub IPGETINTFIELD -11 stub IPFINDNEXTLINE -12 stub IPGETFILENAME -13 stub VCPQUEUECOPY +5 stub IpGetLongField #(word ptr word ptr) +6 stub IpGetStringField #(word ptr word ptr word ptr) +7 stub IpFindFirstLine #(word str str ptr) +8 stub IpGetLineCount #(word str ptr) +9 stub IpGetFieldCount #(word ptr ptr) +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) 14 stub NOAUTORUNWNDPROC 15 stub __DEBUGMSG 16 stub __ASSERTMSG -17 stub VCPQUEUEDELETE -18 stub TPOPENFILE -19 stub TPCLOSEFILE -20 stub TPOPENSECTION -21 stub TPCLOSESECTION -22 stub TPCOMMITSECTION -23 stub TPGETLINE -24 stub TPGETNEXTLINE -25 stub TPINSERTLINE -26 stub TPREPLACELINE -27 stub TPDELETELINE -28 stub TPMOVELINE -29 stub TPGETLINECONTENTS -30 stub TPGETPRIVATEPROFILESTRING -31 stub TPWRITEPRIVATEPROFILESTRING -32 stub TPGETPROFILESTRING -33 stub CTLSETLDD -34 stub CTLGETLDD -35 stub CTLFINDLDD -36 stub CTLADDLDD -37 stub CTLDELLDD +17 stub VcpQueueDelete #(str str word long) +18 stub TpOpenFile #(str ptr word) +19 stub TpCloseFile #(word) +20 stub TpOpenSection #(word ptr str word) +21 stub TpCloseSection #(word) +22 stub TpCommitSection #(word word str word) +23 stub TpGetLine #(word str str word word ptr) +24 stub TpGetNextLine #(word str str ptr) +25 stub TpInsertLine #(word str str word word word) +26 stub TpReplaceLine #(word str str word word word) +27 stub TpDeleteLine #(word word word word) +28 stub TpMoveLine #(word word word word word word) +29 stub TpGetLineContents #(word ptr word ptr word word word) +30 stub TpGetPrivateProfileString #(str str str ptr word str) +31 stub TpWritePrivateProfileString #(str str str str) +32 stub TpGetProfileString #(str str str ptr word) +33 pascal16 CtlSetLdd(ptr) CtlSetLdd16 +34 pascal16 CtlGetLdd(ptr) CtlGetLdd16 +35 pascal16 CtlFindLdd(ptr) CtlFindLdd16 +36 pascal16 CtlAddLdd(ptr) CtlAddLdd16 +37 pascal16 CtlDelLdd(word) CtlDelLdd16 38 pascal16 CtlGetLddPath(word ptr) CtlGetLddPath16 -39 stub SUREGCLOSEKEY -40 stub SUREGCREATEKEY -41 stub SUREGDELETEKEY -42 stub SUREGDELETEVALUE -43 stub SUREGENUMKEY -44 stub SUREGENUMVALUE -45 stub SUREGFLUSH -46 stub SUREGINIT +39 stub SURegCloseKey #(word) +40 stub SURegCreateKey #(word) +41 stub SURegDeleteKey #(word str) +42 stub SURegDeleteValue #(word str) +43 stub SURegEnumKey #(word long ptr long) +44 stub SURegEnumValue #(word long str ptr ptr ptr ptr ptr) +45 stub SURegFlush #() +46 stub SURegInit #() 47 pascal SURegOpenKey(word str ptr) SURegOpenKey -48 stub SUREGQUERYVALUE -49 stub SUREGQUERYVALUE16 +48 stub SURegQueryValue +49 stub SURegQueryValue16 #(word str ptr ptr) 50 pascal SURegQueryValueEx(long str ptr ptr ptr ptr) SURegQueryValueEx -51 stub SUREGSETVALUE -52 stub SUREGSETVALUE16 -53 stub SUREGSETVALUEEX -54 stub SUREGSAVEKEY -55 stub SUREGLOADKEY -56 stub SUREGUNLOADKEY -60 stub DISKINFOFROMLDID -61 stub SUERRORTOIDS -62 stub TPWRITEPROFILESTRING +51 stub SURegSetValue +52 stub SURegSetValue16 #(word str long ptr long) +53 stub SURegSetValueEx #(word str long long ptr long) +54 stub SURegSaveKey #(word str ptr) +55 stub SURegLoadKey #(word str str) +56 stub SURegUnLoadKey #(word str) +60 stub DiskInfoFromLdid #(word ptr) +61 stub suErrorToIds #(word word) +62 stub TPWriteProfileString #(str str str) 63 stub SURPLSETUP 64 stub SUSTORELDIDPATH 65 stub WILDCARDSTRCMPI 101 pascal16 GenInstall(word str word) GenInstall16 -102 stub GENWININITRENAME +102 stub GenWinInitRename #(str str word) 103 pascal GenFormStrWithoutPlaceHolders(str str word) GenFormStrWithoutPlaceHolders16 104 stub SETUPX -105 stub CFGSETUPMERGE +105 stub CfgSetupMerge #(word) 106 stub INITDEPENDANTLDIDS 107 stub CFGOBJFINDKEYCMD -108 stub GENSUREGSETVALUEEX -110 stub GENINSTALLEX -111 stub GENCOPYLOGCONFIG2REG -112 stub SUGETSETSETUPFLAGS -114 stub CFGPARSELINE +108 stub GenSURegSetValueEx +109 stub GENINSTALLWITHQUEUE +110 stub GenInstallEx #(word str word word ptr long) +111 stub GenCopyLogConfig2Reg #(word word str) +112 stub SUGetSetSetupFlags #(ptr word) +114 stub CFGPARSELINE # returns array 115 stub CFGSETAUTOPROCESS 116 stub CFGOBJTOSTR 117 stub CFGLNTOOBJ 118 stub MATCHCMDEXT -119 stub IPFINDNEXTMATCHLINE +119 stub IpFindNextMatchLine #(word str ptr) 120 stub P_SETDEFAULTOPTION 121 stub CFGCLEANBOOT 122 stub CFGMATCHCMDEXT @@ -90,16 +91,24 @@ owner setupapi 126 stub GENMAPROOTREGSTR2KEY 127 stub P_CDROMOC 128 stub P_MEDIAOC -130 stub _SUFORMATMESSAGE -131 stub SUVFORMATMESSAGE -132 stub _SUFORMATMESSAGEBOX -135 stub SUHELP -140 stub SUVERCONFLICT -141 stub SUVERCONFLICTINIT -142 stub SUVERCONFLICTTERM -143 stub SUCREATEEBD -144 stub SUCOPYTOEBD -145 stub SXISMSDOS7RUNNING +129 stub CFGCLEAN1STBOOT +130 stub suFormatMessage +131 stub suvFormatMessage #(word str str word ptr) +132 stub suFormatMessageBox +#133 stub suHelp # W98SE conflict !! +135 stub suHelp #(word word) +#135 stub P_WEBTVOC # W98SE conflict !! +136 stub P_WBEMOC +137 stub P_THEMESOC +138 stub P_IMAGINGOC +139 stub P_SCHEMESOC +140 stub suVerConflict #(word ptr word ptr) +141 stub suVerConflictInit #(word) +142 stub suVerConflictTerm #(ptr) +# Emergency Boot Disk +143 stub suCreateEBD #(word ptr long) +144 stub suCopyToEBD +145 stub sxIsMSDOS7Running #() 150 stub DS_INIT 151 stub DS_DESTROY 152 stub DS_SSYNCDRIVES @@ -112,60 +121,64 @@ owner setupapi 159 stub DS_SETAVAILABLEPAD 160 stub SXUPDATEDS 170 stub SUSETMEM -171 stub WRITEDMFBOOTDATA -200 pascal vcpOpen(ptr str) vcpOpen16 -201 pascal vcpClose(word word word) vcpClose16 -202 stub VCPDEFCALLBACKPROC -203 stub VCPENUMFILES -204 stub VCPQUEUERENAME -205 stub VSMGETSTRINGNAME -206 stub VSMSTRINGDELETE -207 stub VSMSTRINGADD -208 stub VSMGETSTRINGRAWNAME -209 stub IPSAVERESTOREPOSITION +171 stub WriteDMFBootData #(word ptr word) +200 pascal VcpOpen(ptr str) VcpOpen16 +201 pascal VcpClose(word word word) VcpClose16 +202 stub vcpDefCallbackProc #(ptr word word long long) +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) +209 stub IpSaveRestorePosition #(word word) 210 pascal16 IpGetProfileString(word str str ptr word) IpGetProfileString16 -211 stub IPOPENEX -212 stub IPOPENAPPENDEX -213 stub VCPUICALLBACKPROC -214 stub VCPADDMRUPATH -300 stub DIBUILDCOMPATDRVLIST -301 stub DIBUILDCLASSDRVLIST -302 stub DIDESTROYDRIVERNODELIST -303 stub DICREATEDEVICEINFO -304 stub DIGETCLASSDEVS -305 stub DIDESTROYDEVICEINFOLIST -306 stub DIREMOVEDEVICE -308 stub DICALLCLASSINSTALLER -309 stub DICREATEDRIVERNODE -310 stub DIDRAWMINIICON -311 stub DIGETCLASSBITMAPINDEX -312 stub DISELECTDEVICE -313 stub DIINSTALLDEVICE -314 stub DILOADCLASSICON -315 stub DIASKFOROEMDISK -316 stub DISPLAY_SETMODE -317 stub DISPLAY_CLASSINSTALLER -318 stub DICREATEDEVREGKEY -319 stub DIOPENDEVREGKEY -320 stub DIINSTALLDRVSECTION -321 stub DIINSTALLCLASS -322 stub DIOPENCLASSREGKEY -323 stub DISPLAY_SETFONTSIZE -324 stub DISPLAY_OPENFONTSIZEKEY -325 stub DIBUILDCLASSDRVLISTFROMOLDINF -326 stub DIISTHERENEEDTOCOPY -333 stub DICHANGESTATE -340 stub GETFCTN -341 stub DIBUILDCLASSINFOLIST -342 stub DIDESTROYCLASSINFOLIST -343 stub DIGETDEVICECLASSINFO -344 stub DIDELETEDEVREGKEY -350 stub DISELECTOEMDRV -351 stub DIGETINFCLASS -360 stub GENINFLCTODEVNODE +211 stub IpOpenEx #(str ptr word) +212 stub IpOpenAppendEx #(str word word) +213 stub vcpUICallbackProc #(ptr word word long long) +214 stub VcpAddMRUPath #(str) +300 stub DiBuildCompatDrvList #(ptr) +301 stub DiBuildClassDrvList #(ptr) +302 stub DiDestroyDriverNodeList #(ptr) +303 stub DiCreateDeviceInfo #(ptr str long str str word) +304 pascal16 DiGetClassDevs(ptr str word word) DiGetClassDevs16 +305 stub DiDestroyDeviceInfoList #(ptr) +306 stub DiRemoveDevice #(ptr) +308 stub DiCallClassInstaller #(word ptr) +309 stub DiCreateDriverNode #(ptr word word word str str str str str str long) +310 stub DiDrawMiniIcon +311 stub DiGetClassBitmapIndex #(str ptr) +312 stub DiSelectDevice #(ptr) +313 stub DiInstallDevice #(ptr) +314 stub DiLoadClassIcon #(str ptr ptr) +315 stub DiAskForOEMDisk #(ptr) +316 stub Display_SetMode #(ptr word word word) +317 stub Display_ClassInstaller #(word ptr) +318 stub DiCreateDevRegKey #(ptr ptr word str word) +319 stub DiOpenDevRegKey #(ptr ptr word) +320 stub DiInstallDrvSection #(str str str str long) +321 stub DiInstallClass #(str long) +322 stub DiOpenClassRegKey #(ptr str) +323 stub Display_SetFontSize #(str) +324 stub Display_OpenFontSizeKey #(ptr) +325 stub DiBuildClassDrvListFromOldInf #(ptr str ptr long) +326 stub DiIsThereNeedToCopy #(word long) +333 stub DiChangeState #(ptr long long long) +334 stub WALKSUBTREE +340 stub GetFctn #(word str str ptr ptr) +341 stub DiBuildClassInfoList #(ptr) +342 stub DiDestroyClassInfoList #(ptr) +343 stub DiGetDeviceClassInfo #(ptr ptr) +344 stub DiDeleteDevRegKey #(ptr word) +350 stub DiSelectOEMDrv #(word ptr) +351 stub DiGetINFClass #(str word str long) +353 stub DIPICKBESTDRIVER +355 stub COPYINFFILE +360 stub GenInfLCToDevNode #(word str word word long) 361 stub GETDOSMESSAGE -362 stub MOUSE_CLASSINSTALLER -363 stub SXCOMPAREDOSAPPVER +362 stub Mouse_ClassInstaller #(word ptr) +363 stub sxCompareDosAppVer #(str str) +364 stub MONITOR_CLASSINSTALLER 365 stub FCEGETRESDESOFFSET 366 stub FCEGETALLOCVALUE 367 stub FCEADDRESDES @@ -176,27 +189,30 @@ owner setupapi 372 stub FCEGETOTHERVALUE 373 stub FCEGETVALIDATEVALUE 374 stub FCEWRITETHISFORCEDCONFIGNOW -375 stub SUCREATEPROPERTYSHEETPAGE -376 stub SUDESTROYPROPERTYSHEETPAGE -377 stub SUPROPERTYSHEET -380 stub DIREADREGLOGCONF -381 stub DIREADREGCONF -390 stub DIBUILDPOTENTIALDUPLICATESLIST -395 stub INITSUBSTRDATA -396 stub GETFIRSTSUBSTR -397 stub GETNEXTSUBSTR -400 stub BISFILEINVMM32 -401 stub DIINSTALLDRIVERFILES -405 stub DIBUILDCLASSINFOLISTEX -406 stub DIGETCLASSDEVSEX -407 stub DICOPYREGSUBKEYVALUE -410 stub IPGETVERSIONSTRING -411 stub VCPEXPLAIN -412 stub DIBUILDDRIVERINDEX -413 stub DIADDSINGLEINFTODRVIDX +375 stub SUCreatePropertySheetPage #(ptr) +376 stub SUDestroyPropertySheetPage #(word) +377 stub SUPropertySheet #(ptr) +380 stub DiReadRegLogConf #(ptr str ptr ptr) +381 stub DiReadRegConf #(ptr ptr ptr long) +390 stub DiBuildPotentialDuplicatesList #(ptr ptr long ptr ptr) +395 stub InitSubstrData #(ptr str) +396 stub GetFirstSubstr #(ptr) +397 stub GetNextSubstr #(ptr) +398 stub INITSUBSTRDATAEX +400 stub bIsFileInVMM32 #(str) +401 stub DiInstallDriverFiles #(ptr) +405 stub DiBuildClassInfoListEx #(ptr long) +406 stub DiGetClassDevsEx #(ptr str str word word) +407 stub DiCopyRegSubKeyValue #(word str str str) +408 stub IPGETDRIVERDATE +409 stub IPGETDRIVERVERSION +410 stub IpGetVersionString #(str str ptr word str) +411 stub VcpExplain #(ptr long) +412 stub DiBuildDriverIndex #(word) +413 stub DiAddSingleInfToDrvIdx #(str word word) 414 stub FCEGETFLAGS -450 stub UIMAKEDLGNONBOLD -451 stub UIDELETENONBOLDFONT +450 stub UiMakeDlgNonBold #(word) +451 stub UiDeleteNonBoldFont #(word) 500 stub SUEBDPAGE 501 stub SUOCPAGE 502 stub SXLISTSUBPROC @@ -206,15 +222,51 @@ owner setupapi 507 stub SXOCFIXNEEDS 508 pascal16 CtlSetLddPath(word str) CtlSetLddPath16 509 stub SXCALLOCPROC -520 stub DIBUILDCLASSDRVINFOLIST -521 stub DIBUILDCOMPATDRVINFOLIST -522 stub DIDESTROYDRVINFOLIST -523 stub DICONVERTDRIVERINFOTODRIVERNODE -525 stub FIRSTBOOTMOVETODOSSTART -526 stub DOSOPTENABLECURCFG -527 pascal InstallHinfSection(word word str word) InstallHinfSection16 +510 stub BUILDINFOCS +511 stub BUILDREGOCS +512 stub DELETEOCS +520 stub DiBuildClassDrvInfoList #(ptr) +521 stub DiBuildCompatDrvInfoList #(ptr) +522 stub DiDestroyDrvInfoList #(ptr) +523 stub DiConvertDriverInfoToDriverNode #(ptr ptr) +524 stub DISELECTBESTCOMPATDRV +525 stub FirstBootMoveToDOSSTART #(str word) +526 stub DOSOptEnableCurCfg #(str) +527 pascal16 InstallHinfSection(word word str word) InstallHinfSection16 528 stub SXMAKEUNCPATH 529 stub SXISSBSSERVERFILE 530 stub SXFINDBATCHFILES -600 stub PIDCONSTRUCT -601 stub PIDVALIDATE +531 stub ISPANEUROPEAN +532 stub UPGRADENIGGLINGS +533 stub DISPLAY_ISSECONDDISPLAY +534 stub ISWINDOWSFILE +540 stub VERIFYSELECTEDDRIVER +575 stub SXCALLMIGRATIONDLLS +576 stub SXCALLMIGRATIONDLLS_RUNDLL +600 stub PidConstruct #(str str str word) +601 stub PidValidate #(str str) +602 stub GETJAPANESEKEYBOARDTYPE +610 stub CRC32COMPUTE +621 stub SXSAVEINFO +622 stub SXADDPAGEEX +623 stub OPKREMOVEINSTALLEDNETDEVICE +640 stub DOFIRSTRUNSCREENS +700 stub SXSHOWREBOOTDLG +701 stub SXSHOWREBOOTDLG_RUNDLL +750 stub UIPOSITIONDIALOG +775 stub ASPICLEAN +800 stub EXTRACTCABFILE +825 stub PIDGEN3 +826 stub GETSETUPINFO +827 stub SETSETUPINFO +828 stub GETKEYBOARDOPTIONS +829 stub GETLOCALEOPTIONS +830 stub SETINTLOPTIONS +831 stub GETPRODUCTTYPE +832 stub ISOPKMODE +833 stub AUDITONETIMEINSTALL +834 stub DISKDUP +835 stub OPKPREINSTALL +836 stub ISAUDITMODE +837 stub ISAUDITAUTO +838 stub GETVALIDEULA diff --git a/dlls/setupapi/setupx16.h b/dlls/setupapi/setupx16.h index bb5b9feb463..32d3ccb4993 100644 --- a/dlls/setupapi/setupx16.h +++ b/dlls/setupapi/setupx16.h @@ -6,11 +6,17 @@ typedef UINT16 HINF16; typedef UINT16 LOGDISKID16; +#define LINE_LEN 256 + /* error codes stuff */ typedef UINT16 RETERR16; #define OK 0 #define IP_ERROR (UINT16)100 +#define TP_ERROR (UINT16)200 +#define VCP_ERROR (UINT16)300 +#define GEN_ERROR (UINT16)400 +#define DI_ERROR (UINT16)500 enum _IP_ERR { ERR_IP_INVALID_FILENAME = IP_ERROR+1, @@ -21,7 +27,7 @@ enum _IP_ERR { ERR_IP_INVALID_INFFILE, ERR_IP_INVALID_HINF, ERR_IP_INVALID_FIELD, - ERR_IP_SECTION_NOT_FOUND, + ERR_IP_SECT_NOT_FOUND, ERR_IP_END_OF_SECTION, ERR_IP_PROFILE_NOT_FOUND, ERR_IP_LINE_NOT_FOUND, @@ -31,7 +37,62 @@ enum _IP_ERR { ERR_IP_INVALID_INFTYPE }; -/* logical disk identifiers (LDID) */ +enum _ERR_VCP { + ERR_VCP_IOFAIL = VCP_ERROR+1, + ERR_VCP_STRINGTOOLONG, + ERR_VCP_NOMEM, + ERR_VCP_QUEUEFULL, + ERR_VCP_NOVHSTR, + ERR_VCP_OVERFLOW, + ERR_VCP_BADARG, + ERR_VCP_UNINIT, + ERR_VCP_NOTFOUND, + ERR_VCP_BUSY, + ERR_VCP_INTERRUPTED, + ERR_VCP_BADDEST, + ERR_VCP_SKIPPED, + ERR_VCP_IO, + ERR_VCP_LOCKED, + ERR_VCP_WRONGDISK, + ERR_VCP_CHANGEMODE, + ERR_VCP_LDDINVALID, + ERR_VCP_LDDFIND, + ERR_VCP_LDDUNINIT, + ERR_VCP_LDDPATH_INVALID, + ERR_VCP_NOEXPANSION, + ERR_VCP_NOTOPEN, + ERR_VCP_NO_DIGITAL_SIGNATURE_CATALOG, + ERR_VCP_NO_DIGITAL_SIGNATURE_FILE +}; + +/****** logical disk management ******/ + +typedef struct _LOGDISKDESC_S { /* ldd */ + WORD cbSize; /* struct size */ + LOGDISKID16 ldid; /* logical disk ID */ + LPSTR pszPath; /* path this descriptor points to */ + LPSTR pszVolLabel; /* volume label of the disk related to it */ + LPSTR pszDiskName; /* name of this disk */ + WORD wVolTime; /* modification time of volume label */ + WORD wVolDate; /* modification date */ + DWORD dwSerNum; /* serial number of disk */ + WORD wFlags; +} LOGDISKDESC_S, *LPLOGDISKDESC; + +/** logical disk identifiers (LDID) **/ + +/* predefined LDIDs */ +#define LDID_PREDEF_START 0x0001 +#define LDID_PREDEF_END 0x7fff + +/* registry-assigned LDIDs */ +#define LDID_VAR_START 0x7000 +#define LDID_VAR_END 0x7fff + +/* dynamically assigned LDIDs */ +#define LDID_ASSIGN_START 0x8000 +#define LDID_ASSIGN_END 0xbfff + #define LDID_NULL 0 #define LDID_ABSOLUTE ((UINT)-1) #define LDID_SRCPATH 1 /* setup source path */ @@ -63,16 +124,90 @@ enum _IP_ERR { #define LDID_OLD_WINBOOT 32 /* root subdir */ #define LDID_OLD_WIN 33 /* old windows dir */ -typedef struct { - HINF16 hInf; - HFILE hInfFile; - LPSTR lpInfFileName; -} INF_FILE; +/* flags for GenInstall() */ +#define GENINSTALL_DO_FILES 1 +#define GENINSTALL_DO_INI 2 +#define GENINSTALL_DO_REG 4 +#define GENINSTALL_DO_INI2REG 8 +#define GENINSTALL_DO_CFGAUTO 16 +#define GENINSTALL_DO_LOGCONFIG 32 +#define GENINSTALL_DO_REGSRCPATH 64 +#define GENINSTALL_DO_PERUSER 128 -extern INF_FILE *InfList; -extern WORD InfNumEntries; +#define GEINISTALL_DO_INIREG 14 +#define GENINSTALL_DO_ALL 255 -extern LPCSTR IP_GetFileName(HINF16 hInf); -extern void WINAPI GenFormStrWithoutPlaceHolders16( LPSTR szDst, LPCSTR szSrc, HINF16 hInf); +/* + * flags for InstallHinfSection() + * 128 can be added, too. This means that the .inf file is provided by you + * instead of being a 32 bit file (i.e. Windows .inf file). + * In this case all files you install must be in the same dir + * as your .inf file on the install disk. + */ +#define HOW_NEVER_REBOOT 0 +#define HOW_ALWAYS_SILENT_REBOOT 1 +#define HOW_ALWAYS_PROMPT_REBOOT 2 +#define HOW_SILENT_REBOOT 3 +#define HOW_PROMPT_REBOOT 4 + +/****** device installation stuff ******/ + +#define MAX_CLASS_NAME_LEN 32 +#define MAX_DEVNODE_ID_LEN 256 +#define MAX_GUID_STR 50 + +typedef struct _DEVICE_INFO +{ + UINT16 cbSize; + struct _DEVICE_INFO *lpNextDi; + char szDescription[LINE_LEN]; + DWORD dnDevnode; + HKEY hRegKey; + char szRegSubkey[MAX_DEVNODE_ID_LEN]; + char szClassName[MAX_CLASS_NAME_LEN]; + DWORD Flags; + HWND16 hwndParent; + /*LPDRIVER_NODE*/ LPVOID lpCompatDrvList; + /*LPDRIVER_NODE*/ LPVOID lpClassDrvList; + /*LPDRIVER_NODE*/ LPVOID lpSelectedDriver; + ATOM atDriverPath; + ATOM atTempInfFile; + HINSTANCE16 hinstClassInstaller; + HINSTANCE16 hinstClassPropProvidor; + HINSTANCE16 hinstDevicePropProvidor; + HINSTANCE16 hinstBasicPropProvidor; + FARPROC16 fpClassInstaller; + FARPROC16 fpClassEnumPropPages; + FARPROC16 fpDeviceEnumPropPages; + FARPROC16 fpEnumBasicProperties; + DWORD dwSetupReserved; + DWORD dwClassInstallReserved; + /*GENCALLBACKPROC*/ LPVOID gicpGenInstallCallBack; + + LPARAM gicplParam; + UINT16 InfType; + + HINSTANCE16 hinstPrivateProblemHandler; + FARPROC16 fpPrivateProblemHandler; + LPARAM lpClassInstallParams; + struct _DEVICE_INFO *lpdiChildList; + DWORD dwFlagsEx; + /*LPDRIVER_INFO*/ LPVOID lpCompatDrvInfoList; + /*LPDRIVER_INFO*/ LPVOID lpClassDrvInfoList; + char szClassGUID[MAX_GUID_STR]; +} 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); +extern RETERR16 WINAPI CtlSetLdd16(LPLOGDISKDESC); +extern RETERR16 WINAPI CtlGetLdd16(LPLOGDISKDESC); +extern RETERR16 WINAPI CtlFindLdd16(LPLOGDISKDESC); +extern RETERR16 WINAPI CtlAddLdd16(LPLOGDISKDESC); +extern RETERR16 WINAPI CtlDelLdd16(LOGDISKID16); +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 121bd3d0b3b..edc3df86b47 100644 --- a/dlls/setupapi/setupx_main.c +++ b/dlls/setupapi/setupx_main.c @@ -12,6 +12,7 @@ * DDK: setupx.h * http://mmatrix.tripod.com/customsystemfolder/infsysntaxfull.html * http://www.rdrop.com/~cary/html/inf_faq.html + * http://support.microsoft.com/support/kb/articles/q194/6/40.asp * * Stuff tested with: * - rs405deu.exe (German Acroread 4.05 setup) @@ -19,7 +20,25 @@ * - Netmeeting * * FIXME: - * - check buflen + * - string handling is... weird ;) (buflen etc.) + * - memory leaks ? + * - separate that mess (but probably only when it's done completely) + * + * SETUPX consists of several parts with the following acronyms/prefixes: + * Di device installer (devinst.c ?) + * Gen generic installer (geninst.c ?) + * Ip .INF parsing (infparse.c) + * LDD logical device descriptor (ldd.c ?) + * LDID logical device ID + * SU setup (setup.c ?) + * Tp text processing (textproc.c ?) + * Vcp virtual copy module (vcp.c ?) + * ... + * + * The SETUPX DLL is NOT thread-safe. That's why many installers urge you to + * "close all open applications". + * All in all the design of it seems to be a bit weak. + * Not sure whether my implementation of it is better, though ;-) */ #include @@ -27,7 +46,9 @@ #include "winreg.h" #include "wine/winuser16.h" #include "setupx16.h" +#include "setupx_private.h" #include "winerror.h" +#include "heap.h" #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(setupx); @@ -54,6 +75,205 @@ DWORD WINAPI SURegQueryValueEx( HKEY hkey, LPSTR lpszValueName, lpbData, lpcbData ); } +/* + * Returns pointer to a string list with the first entry being number + * of strings. + * + * Hmm. Should this be InitSubstrData(), GetFirstSubstr() and GetNextSubstr() + * instead? + */ +static LPSTR *SETUPX_GetSubStrings(LPSTR start, char delimiter) +{ + LPSTR p, q; + LPSTR *res = NULL; + DWORD count = 0; + int len; + + p = start; + + while (1) + { + /* find beginning of real substring */ + while ( (*p == ' ') || (*p == '\t') || (*p == '"') ) p++; + + /* find end of real substring */ + q = p; + while ( (*q) + && (*q != ' ') && (*q != '\t') && (*q != '"') + && (*q != ';') && (*q != delimiter) ) q++; + if (q == p) + break; + len = (int)q - (int)p; + + /* alloc entry for new substring in steps of 32 units and copy over */ + if (count % 32 == 0) + { /* 1 for count field + current count + 32 */ + res = HeapReAlloc(GetProcessHeap(), 0, res, (1+count+32)*sizeof(LPSTR)); + } + *(res+1+count) = HeapAlloc(GetProcessHeap(), 0, len+1); + strncpy(*(res+1+count), p, len); + (*(res+1+count))[len] = '\0'; + count++; + + /* we are still within last substring (before delimiter), + * so get out of it */ + while ((*q) && (*q != ';') && (*q != delimiter)) q++; + if ((!*q) || (*q == ';')) + break; + p = q+1; + } + + /* put number of entries at beginning of list */ + *(DWORD *)res = count; + return res; +} + +static void SETUPX_FreeSubStrings(LPSTR *substr) +{ + DWORD count = *(DWORD *)substr; + LPSTR *pStrings = substr+1; + DWORD n; + + for (n=0; n < count; n++) + HeapFree(GetProcessHeap(), 0, *pStrings++); + + HeapFree(GetProcessHeap(), 0, substr); +} + +static void SETUPX_IsolateSubString(LPSTR *begin, LPSTR *end) +{ + LPSTR p, q; + + p = *begin; + q = *end; + + while ((p < q) && ((*p == ' ') || (*p == '\t'))) p++; + while ((p < q) && (*p == '"')) p++; + + while ((q-1 >= p) && ((*(q-1) == ' ') || (*(q-1) == '\t'))) q--; + while ((q-1 >= p) && (*(q-1) == '"')) q--; + + *begin = p; + *end = q; +} + +/* + * Example: HKLM,"Software\Microsoft\Windows\CurrentVersion","ProgramFilesDir",,"C:\" + * FIXME: use SETUPX_GetSubStrings() instead. + * Hmm, but on the other hand SETUPX_GetSubStrings() will probably + * soon be replaced by InitSubstrData() etc. anyway. + * + */ +static BOOL SETUPX_LookupRegistryString(LPSTR regstr, LPSTR buffer, DWORD buflen) +{ + HANDLE heap = GetProcessHeap(); + LPSTR items[5]; + LPSTR p, q, next; + int len, n; + HKEY hkey, hsubkey; + DWORD dwType; + + TRACE("retrieving '%s'\n", regstr); + + p = regstr; + + /* isolate root key, subkey, value, flag, defval */ + for (n=0; n < 5; n++) + { + q = strchr(p, ','); + if (!q) + { + if (n == 4) + q = p+strlen(p); + else + return FALSE; + } + next = q+1; + if (q < regstr) + return FALSE; + SETUPX_IsolateSubString(&p, &q); + len = (int)q - (int)p; + items[n] = HeapAlloc(heap, 0, len+1); + strncpy(items[n], p, len); + items[n][len] = '\0'; + p = next; + } + TRACE("got '%s','%s','%s','%s','%s'\n", + items[0], items[1], items[2], items[3], items[4]); + + /* check root key */ + if (!strcasecmp(items[0], "HKCR")) + hkey = HKEY_CLASSES_ROOT; + else + if (!strcasecmp(items[0], "HKCU")) + hkey = HKEY_CURRENT_USER; + else + if (!strcasecmp(items[0], "HKLM")) + hkey = HKEY_LOCAL_MACHINE; + else + if (!strcasecmp(items[0], "HKU")) + hkey = HKEY_USERS; + else + { /* HKR ? -> relative to key passed to GenInstallEx */ + FIXME("unsupported regkey '%s'\n", items[0]); + goto regfailed; + } + + if (RegOpenKeyA(hkey, items[1], &hsubkey) != ERROR_SUCCESS) + goto regfailed; + + if (RegQueryValueExA(hsubkey, items[2], NULL, &dwType, buffer, &buflen) + != ERROR_SUCCESS) + goto regfailed; + goto done; + +regfailed: + if (buffer) strcpy(buffer, items[4]); /* I don't care about buflen */ +done: + for (n=0; n < 5; n++) + HeapFree(heap, 0, items[n]); + if (buffer) + TRACE("return '%s'\n", buffer); + return TRUE; +} + +static LPSTR SETUPX_GetSections(LPCSTR filename) +{ + LPSTR buf = NULL; + DWORD len = 1024, res; + + do { + buf = HeapReAlloc(GetProcessHeap(), 0, buf, len); + res = GetPrivateProfileStringA(NULL, NULL, NULL, buf, len, filename); + len *= 2; + } while ((!res) && (len < 1048576)); + if (!res) + { + HeapFree(GetProcessHeap(), 0, buf); + return NULL; + } + return buf; +} + +static LPSTR SETUPX_GetSectionEntries(LPCSTR filename, LPCSTR section) +{ + LPSTR buf = NULL; + DWORD len = 1024, res; + + do { + buf = HeapReAlloc(GetProcessHeap(), 0, buf, len); + res = GetPrivateProfileSectionA(section, buf, len, filename); + len *= 2; + } while ((!res) && (len < 1048576)); + if (!res) + { + HeapFree(GetProcessHeap(), 0, buf); + return NULL; + } + return buf; +} + + /*********************************************************************** * InstallHinfSection * @@ -61,16 +281,72 @@ DWORD WINAPI SURegQueryValueEx( HKEY hkey, LPSTR lpszValueName, * hinst = instance of SETUPX.DLL * lpszCmdLine = e.g. "DefaultInstall 132 C:\MYINSTALL\MYDEV.INF" * Here "DefaultInstall" is the .inf file section to be installed (optional). - * 132 is the standard parameter, it seems. - * 133 means don't prompt user for reboot. + * The 132 value is made of the HOW_xxx flags and sometimes 128 (-> setupx16.h). * * nCmdShow = nCmdShow of CreateProcess - * FIXME: is the return type correct ? */ -DWORD WINAPI InstallHinfSection16( HWND16 hwnd, HINSTANCE16 hinst, LPCSTR lpszCmdLine, INT16 nCmdShow) +typedef INT WINAPI (*MSGBOX_PROC)( HWND, LPCSTR, LPCSTR, UINT ); +RETERR16 WINAPI InstallHinfSection16( HWND16 hwnd, HINSTANCE16 hinst, LPCSTR lpszCmdLine, INT16 nCmdShow) { - FIXME("(%04x, %04x, %s, %d), stub.\n", hwnd, hinst, lpszCmdLine, nCmdShow); - return 0; + LPSTR *pSub; + DWORD count; + HINF16 hInf = 0; + RETERR16 res = OK; + WORD wFlags; + BOOL reboot = FALSE; + HMODULE hMod; + MSGBOX_PROC pMessageBoxA; + + TRACE("(%04x, %04x, %s, %d);\n", hwnd, hinst, lpszCmdLine, nCmdShow); + + pSub = SETUPX_GetSubStrings((LPSTR)lpszCmdLine, ' '); + + count = *(DWORD *)pSub; + if (count < 2) /* invalid number of arguments ? */ + goto end; + if (IpOpen16(*(pSub+count), &hInf) != OK) + { + res = ERROR_FILE_NOT_FOUND; /* yes, correct */ + goto end; + } + if (GenInstall16(hInf, *(pSub+count-2), GENINSTALL_DO_ALL) != OK) + goto end; + wFlags = atoi(*(pSub+count-1)) & ~128; + switch (wFlags) + { + case HOW_ALWAYS_SILENT_REBOOT: + case HOW_SILENT_REBOOT: + reboot = TRUE; + break; + case HOW_ALWAYS_PROMPT_REBOOT: + case HOW_PROMPT_REBOOT: + if ((hMod = GetModuleHandleA("user32.dll"))) + { + if ((pMessageBoxA = (MSGBOX_PROC)GetProcAddress( hMod, "MessageBoxA" ))) + { + + if (pMessageBoxA(hwnd, "You must restart Wine before the new settings will take effect.\n\nDo you want to exit Wine now ?", "Systems Settings Change", MB_YESNO|MB_ICONQUESTION) == IDYES) + reboot = TRUE; + } + } + break; + default: + ERR("invalid flags %d !\n", wFlags); + goto end; + } + + res = OK; +end: + IpClose16(hInf); + SETUPX_FreeSubStrings(pSub); + if (reboot) + { + /* FIXME: we should have a means of terminating all wine + wineserver */ + MESSAGE("Program or user told me to restart. Exiting Wine...\n"); + ExitProcess(1); + } + + return res; } typedef struct @@ -220,96 +496,334 @@ static const LDID_DATA LDID_Data[34] = /* the rest (34-38) isn't too interesting, so I'll forget about it */ }; -static void SETUPX_IsolateSubString(LPSTR *begin, LPSTR *end) +/* + * LDD == Logical Device Descriptor + * LDID == Logical Device ID + * + * The whole LDD/LDID business might go into a separate file named + * ldd.c or logdevice.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. + * That's why I implemented them in a way that's suitable for my purpose. + */ +static LDD_LIST *pFirstLDD = NULL; + +static BOOL std_LDDs_done = FALSE; + +void SETUPX_CreateStandardLDDs(void) { - LPSTR p, q; + HKEY hKey = 0; + WORD n; + DWORD type, len; + LOGDISKDESC_S ldd; + char buffer[MAX_PATH]; - p = *begin; - q = *end; + /* has to be here, otherwise loop */ + std_LDDs_done = TRUE; - while ((p < q) && ((*p == ' ') || (*p == '\t'))) p++; - while ((p < q) && (*p == '"')) p++; + RegOpenKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup", &hKey); - while ((q-1 >= p) && ((*(q-1) == ' ') || (*(q-1) == '\t'))) q--; - while ((q-1 >= p) && (*(q-1) == '"')) q--; + for (n=0; n < sizeof(LDID_Data)/sizeof(LDID_DATA); n++) + { + buffer[0] = '\0'; - *begin = p; - *end = q; + len = MAX_PATH; + if ( (hKey) && (LDID_Data[n].RegValName) + && (RegQueryValueExA(hKey, LDID_Data[n].RegValName, + NULL, &type, buffer, &len) == ERROR_SUCCESS) + && (type == REG_SZ) ) + { + TRACE("found value '%s' for LDID %d\n", buffer, n); + } + else + switch(n) + { + case LDID_SRCPATH: + FIXME("LDID_SRCPATH: what exactly do we have to do here ?\n"); + strcpy(buffer, "X:\\FIXME"); + break; + case LDID_SYS: + GetSystemDirectoryA(buffer, MAX_PATH); + break; + case LDID_APPS: + case LDID_MACHINE: + case LDID_HOST_WINBOOT: + case LDID_BOOT: + case LDID_BOOT_HOST: + strcpy(buffer, "C:\\"); + break; + default: + if (LDID_Data[n].StdString) + { + DWORD len = GetWindowsDirectoryA(buffer, MAX_PATH); + LPSTR p; + p = buffer + len; + *p++ = '\\'; + strcpy(p, LDID_Data[n].StdString); + } + break; + } + if (buffer[0]) + { + INIT_LDD(ldd, n); + ldd.pszPath = buffer; + TRACE("LDID %d -> '%s'\n", ldd.ldid, ldd.pszPath); + CtlSetLdd16(&ldd); + } + } + if (hKey) RegCloseKey(hKey); +} + +/* + * CtlDelLdd (SETUPX.37) + * + * RETURN + * ERR_VCP_LDDINVALID if ldid < LDID_ASSIGN_START. + */ +RETERR16 SETUPX_DelLdd(LOGDISKID16 ldid) +{ + LDD_LIST *pCurr = pFirstLDD, *pPrev = NULL; + + TRACE("(%d)\n", ldid); + + if (!std_LDDs_done) + SETUPX_CreateStandardLDDs(); + + if (ldid < LDID_ASSIGN_START) + return ERR_VCP_LDDINVALID; + + /* search until we find the appropriate LDD or hit the end */ + while ((pCurr != NULL) && (ldid > pCurr->pldd->ldid)) + { + pPrev = pCurr; + pCurr = pCurr->next; + } + if ( (pCurr == NULL) /* hit end of list */ + || (ldid != pCurr->pldd->ldid) ) + return ERR_VCP_LDDFIND; /* correct ? */ + + /* ok, found our victim: eliminate it */ + + if (pPrev) + pPrev->next = pCurr->next; + + if (pCurr == pFirstLDD) + pFirstLDD = NULL; + HeapFree(GetProcessHeap(), 0, pCurr); + + return OK; +} + +RETERR16 WINAPI CtlDelLdd16(LOGDISKID16 ldid) +{ + FIXME("(%d); - please report to a.mohr@mailto.de !!!\n", ldid); + return SETUPX_DelLdd(ldid); } /* - * Example: HKLM,"Software\Microsoft\Windows\CurrentVersion","ProgramFilesDir",,"C:\" + * CtlFindLdd (SETUPX.35) + * + * doesn't check pldd ptr validity: crash (W98SE) + * + * RETURN + * ERR_VCP_LDDINVALID if pldd->cbSize != structsize + * 1 in all other cases ?? + * */ -static BOOL SETUPX_LookupRegistryString(LPSTR regstr, LPSTR buffer, DWORD buflen) +RETERR16 WINAPI CtlFindLdd16(LPLOGDISKDESC pldd) { - HANDLE heap = GetProcessHeap(); - LPSTR items[5]; - LPSTR p, q, next; - int len, n; - HKEY hkey, hsubkey; - DWORD dwType; + LDD_LIST *pCurr = pFirstLDD, *pPrev = NULL; - TRACE("retrieving '%s'\n", regstr); + TRACE("(%p)\n", pldd); + + if (!std_LDDs_done) + SETUPX_CreateStandardLDDs(); - p = regstr; + if (pldd->cbSize != sizeof(LOGDISKDESC_S)) + return ERR_VCP_LDDINVALID; - /* isolate root key, subkey, value, flag, defval */ - for (n=0; n < 5; n++) + /* search until we find the appropriate LDD or hit the end */ + while ((pCurr != NULL) && (pldd->ldid > pCurr->pldd->ldid)) { - q = strchr(p, ','); - if (!q) - { - if (n == 4) - q = p+strlen(p); - else - return FALSE; - } - next = q+1; - if (q < regstr) - return FALSE; - SETUPX_IsolateSubString(&p, &q); - len = (int)q - (int)p; - items[n] = HeapAlloc(heap, 0, len+1); - strncpy(items[n], p, len); - items[n][len] = '\0'; - p = next; + pPrev = pCurr; + pCurr = pCurr->next; } - TRACE("got '%s','%s','%s','%s','%s'\n", - items[0], items[1], items[2], items[3], items[4]); + if ( (pCurr == NULL) /* hit end of list */ + || (pldd->ldid != pCurr->pldd->ldid) ) + return ERR_VCP_LDDFIND; /* correct ? */ + + memcpy(pldd, pCurr->pldd, pldd->cbSize); + /* hmm, we probably ought to strcpy() the string ptrs here */ - /* check root key */ - if (!strcasecmp(items[0], "HKCR")) - hkey = HKEY_CLASSES_ROOT; + return 1; /* what is this ?? */ +} + +/* + * CtlSetLdd (SETUPX.33) + * + * Set an LDD entry. + * + * RETURN + * ERR_VCP_LDDINVALID if pldd.cbSize != sizeof(LOGDISKDESC_S) + * + */ +RETERR16 WINAPI CtlSetLdd16(LPLOGDISKDESC pldd) +{ + LDD_LIST *pCurr = pFirstLDD, *pPrev = NULL; + LPLOGDISKDESC pCurrLDD; + HANDLE heap; + BOOL is_new = FALSE; + + TRACE("(%p)\n", pldd); + + if (!std_LDDs_done) + SETUPX_CreateStandardLDDs(); + + if (pldd->cbSize != sizeof(LOGDISKDESC_S)) + return ERR_VCP_LDDINVALID; + + heap = GetProcessHeap(); + /* search until we find the appropriate LDD or hit the end */ + while ((pCurr != NULL) && (pldd->ldid > pCurr->pldd->ldid)) + { + pPrev = pCurr; + pCurr = pCurr->next; + } + if (pCurr == NULL) /* hit end of list */ + { + is_new = TRUE; + pCurr = HeapAlloc(heap, 0, sizeof(LDD_LIST)); + pCurr->pldd = HeapAlloc(heap, 0, sizeof(LOGDISKDESC_S)); + pCurr->next = NULL; + pCurrLDD = pCurr->pldd; + } else - if (!strcasecmp(items[0], "HKCU")) - hkey = HKEY_CURRENT_USER; - else - if (!strcasecmp(items[0], "HKLM")) - hkey = HKEY_LOCAL_MACHINE; - else - if (!strcasecmp(items[0], "HKU")) - hkey = HKEY_USERS; - else - { /* HKR ? -> relative to key passed to GenInstallEx */ - FIXME("unsupported regkey '%s'\n", items[0]); - goto regfailed; + { + pCurrLDD = pCurr->pldd; + if (pCurrLDD->pszPath) HeapFree(heap, 0, pCurrLDD->pszPath); + if (pCurrLDD->pszVolLabel) HeapFree(heap, 0, pCurrLDD->pszVolLabel); + if (pCurrLDD->pszDiskName) HeapFree(heap, 0, pCurrLDD->pszDiskName); } - if (RegOpenKeyA(hkey, items[1], &hsubkey) != ERROR_SUCCESS) - goto regfailed; + memcpy(pCurrLDD, pldd, sizeof(LOGDISKDESC_S)); - if (RegQueryValueExA(hsubkey, items[2], 0, &dwType, buffer, &buflen) - != ERROR_SUCCESS) - goto regfailed; - goto done; + if (pldd->pszPath) + pCurrLDD->pszPath = HEAP_strdupA(heap, 0, pldd->pszPath); + if (pldd->pszVolLabel) + pCurrLDD->pszVolLabel = HEAP_strdupA(heap, 0, pldd->pszVolLabel); + if (pldd->pszDiskName) + pCurrLDD->pszDiskName = HEAP_strdupA(heap, 0, pldd->pszDiskName); -regfailed: - strcpy(buffer, items[4]); /* I don't care about buflen */ -done: - for (n=0; n < 5; n++) - HeapFree(heap, 0, items[n]); - TRACE("return '%s'\n", buffer); - return TRUE; + if (is_new) /* link into list */ + { + if (pPrev) + { + pCurr->next = pPrev->next; + pPrev->next = pCurr; + } + if (!pFirstLDD) + pFirstLDD = pCurr; + } + + return OK; +} + + +/* + * CtlAddLdd (SETUPX.36) + * + * doesn't check pldd ptr validity: crash (W98SE) + * + */ +static LOGDISKID16 ldid_to_add = LDID_ASSIGN_START; +RETERR16 WINAPI CtlAddLdd16(LPLOGDISKDESC pldd) +{ + pldd->ldid = ldid_to_add++; + return CtlSetLdd16(pldd); +} + +/* + * CtlGetLdd (SETUPX.34) + * + * doesn't check pldd ptr validity: crash (W98SE) + * What the !@#$%&*( is the difference between CtlFindLdd() and CtlGetLdd() ?? + * + * RETURN + * ERR_VCP_LDDINVALID if pldd->cbSize != structsize + * + */ +static RETERR16 SETUPX_GetLdd(LPLOGDISKDESC pldd) +{ + LDD_LIST *pCurr = pFirstLDD, *pPrev = NULL; + + if (!std_LDDs_done) + SETUPX_CreateStandardLDDs(); + + if (pldd->cbSize != sizeof(LOGDISKDESC_S)) + return ERR_VCP_LDDINVALID; + + /* search until we find the appropriate LDD or hit the end */ + while ((pCurr != NULL) && (pldd->ldid > pCurr->pldd->ldid)) + { + pPrev = pCurr; + pCurr = pCurr->next; + } + if (pCurr == NULL) /* hit end of list */ + return ERR_VCP_LDDFIND; /* correct ? */ + + memcpy(pldd, pCurr->pldd, pldd->cbSize); + /* hmm, we probably ought to strcpy() the string ptrs here */ + + return OK; +} + +RETERR16 WINAPI CtlGetLdd16(LPLOGDISKDESC pldd) +{ + FIXME("(%p); - please report to a.mohr@mailto.de !!!\n", pldd); + return SETUPX_GetLdd(pldd); +} + +/*********************************************************************** + * CtlGetLddPath (SETUPX.38) + * + * Gets the path of an LDD. + * No crash if szPath == NULL. + * szPath has to be at least MAX_PATH_LEN bytes long. + * RETURN + * ERR_VCP_LDDUNINIT if LDD for LDID not found. + */ +RETERR16 WINAPI CtlGetLddPath16(LOGDISKID16 ldid, LPSTR szPath) +{ + TRACE("(%d, %p);\n", ldid, szPath); + + if (szPath) + { + LOGDISKDESC_S ldd; + INIT_LDD(ldd, ldid); + if (CtlFindLdd16(&ldd) == ERR_VCP_LDDFIND) + return ERR_VCP_LDDUNINIT; + SETUPX_GetLdd(&ldd); + strcpy(szPath, ldd.pszPath); + TRACE("ret '%s' for LDID %d\n", szPath, ldid); + } + return OK; +} + +/*********************************************************************** + * CtlSetLddPath (SETUPX.508) + * + * Sets the path of an LDD. + * Creates LDD for LDID if not existing yet. + */ +RETERR16 WINAPI CtlSetLddPath16(LOGDISKID16 ldid, LPSTR szPath) +{ + LOGDISKDESC_S ldd; + TRACE("(%d, '%s');\n", ldid, szPath); + + INIT_LDD(ldd, ldid); + ldd.pszPath = szPath; + return CtlSetLdd16(&ldd); } /* @@ -328,29 +842,32 @@ done: * - maybe we ought to add a caching array for speed ? - I don't care :) * - not sure whether the processing is correct - sometimes there are equal * LDIDs for both install and removal sections. + * - probably the whole function can be removed as installers add that on their + * own */ -static BOOL SETUPX_TranslateCustomLDID(int ldid, LPSTR buffer, WORD buflen, INT16 hInf) +static BOOL SETUPX_AddCustomLDID(int ldid, INT16 hInf) { - char ldidstr[6], sectionbuf[0xffff], entrybuf[0xffff], section[256]; + char ldidstr[6]; + LPSTR sectionbuf = NULL, entrybuf = NULL, regsectionbuf = NULL; LPCSTR filename; - LPSTR pSec, pEnt, pEqual, p, pEnd; + LPSTR pSec, pEnt, pEqual, p, *pSub = NULL; BOOL ret = FALSE; + char buffer[MAX_PATH]; + LOGDISKDESC_S ldd; sprintf(ldidstr, "%d", ldid); filename = IP_GetFileName(hInf); - if (!GetPrivateProfileStringA(NULL, NULL, NULL, - sectionbuf, sizeof(sectionbuf), filename)) + if (!(sectionbuf = SETUPX_GetSections(filename))) { - ERR("section buffer too small ?\n"); + ERR("couldn't get sections !\n"); return FALSE; } for (pSec=sectionbuf; *pSec; pSec += strlen(pSec)+1) { - if (!GetPrivateProfileSectionA(pSec, - entrybuf, sizeof(entrybuf), filename)) + if (!(entrybuf = SETUPX_GetSectionEntries(filename, pSec))) { - ERR("entry buffer too small ?\n"); - return FALSE; + ERR("couldn't get section entries !\n"); + goto end; } for (pEnt=entrybuf; *pEnt; pEnt += strlen(pEnt)+1) { @@ -368,114 +885,85 @@ static BOOL SETUPX_TranslateCustomLDID(int ldid, LPSTR buffer, WORD buflen, INT1 if (!strcasecmp(pSec, "Strings")) goto next_section; p = pEqual+1; - while ((*p == ' ') || (*p == '\t')) p++; goto found; } } } next_section: } - return FALSE; + goto end; found: TRACE("found entry '%s'\n", p); - /* strip off any flags we get - * FIXME: what are these flags used for ?? */ - pEnd = strchr(p, ','); - strncpy(section, p, (int)pEnd - (int)p); - section[(int)pEnd - (int)p] = '\0'; + pSub = SETUPX_GetSubStrings(p, ','); + if (*(DWORD *)pSub > 2) + { + ERR("malformed entry '%s' ?\n", p); + goto end; + } + TRACE("found section '%s'\n", *(pSub+1)); + /* FIXME: what are the optional flags at the end of an entry used for ?? */ /* get the location of the registry key from that section */ - if (!GetPrivateProfileSectionA(section, entrybuf, sizeof(entrybuf), filename)) + if (!(regsectionbuf = SETUPX_GetSectionEntries(filename, *(pSub+1)))) { - ERR("entrybuf too small ?\n"); - return FALSE; + ERR("couldn't get registry section entries !\n"); + goto end; } - GenFormStrWithoutPlaceHolders16(sectionbuf, entrybuf, hInf); - ret = SETUPX_LookupRegistryString(sectionbuf, buffer, buflen); + /* sectionbuf is > 1024 bytes anyway, so use it */ + GenFormStrWithoutPlaceHolders16(sectionbuf, regsectionbuf, hInf); + ret = SETUPX_LookupRegistryString(sectionbuf, buffer, MAX_PATH); TRACE("return '%s'\n", buffer); + INIT_LDD(ldd, ldid); + ldd.pszPath = buffer; + CtlSetLdd16(&ldd); +end: + SETUPX_FreeSubStrings(pSub); + if (sectionbuf) HeapFree(GetProcessHeap(), 0, sectionbuf); + if (entrybuf) HeapFree(GetProcessHeap(), 0, entrybuf); + if (regsectionbuf) HeapFree(GetProcessHeap(), 0, regsectionbuf); return ret; } /* * Translate a logical disk identifier (LDID) into its string representation + * I'm afraid this can be totally replaced by CtlGetLddPath(). */ -static BOOL SETUPX_TranslateLDID(int ldid, LPSTR buffer, WORD buflen, HINF16 hInf) +static BOOL SETUPX_IP_TranslateLDID(int ldid, LPSTR *p, HINF16 hInf) { BOOL handled = FALSE; + LOGDISKDESC_S ldd; - if ((ldid >= LDID_SRCPATH) && (ldid <= LDID_OLD_WIN)) + ldd.cbSize = sizeof(LOGDISKDESC_S); + ldd.ldid = ldid; + if (CtlFindLdd16(&ldd) == ERR_VCP_LDDFIND) { - if (LDID_Data[ldid].RegValName) - { - HKEY hKey; - - if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup", &hKey) == ERROR_SUCCESS) - { - DWORD type, len = buflen; - - if ( (RegQueryValueExA(hKey, LDID_Data[ldid].RegValName, - NULL, &type, buffer, &len) == ERROR_SUCCESS) - && (type == REG_SZ) ) - { - TRACE("found value '%s' for LDID %d\n", buffer, ldid); - handled = TRUE; - } - - RegCloseKey(hKey); - } - } + /* hmm, it seems the installers already do the work for us + * (by calling CtlSetLddPath) that SETUPX_AddCustomLDID + * is supposed to do. Grmbl ;-) + * Well, I'll leave it here anyway, but print error... */ + ERR("hmm, LDID %d not registered yet !?\n", ldid); + handled = SETUPX_AddCustomLDID(ldid, hInf); } + else + handled = TRUE; + + SETUPX_GetLdd(&ldd); + if (!handled) { - switch(ldid) - { - case LDID_SRCPATH: - FIXME("LDID_SRCPATH: what exactly do we have to do here ?\n"); - break; - case LDID_SYS: - GetSystemDirectoryA(buffer, buflen); - handled = TRUE; - break; - case LDID_APPS: - case LDID_MACHINE: - case LDID_HOST_WINBOOT: - case LDID_BOOT: - case LDID_BOOT_HOST: - strncpy(buffer, "C:\\", buflen); - buffer[buflen-1] = '\0'; - handled = TRUE; - break; - default: - if ( (ldid >= LDID_NULL) && (ldid <= LDID_OLD_WIN) - && (LDID_Data[ldid].StdString) ) - { - UINT len = GetWindowsDirectoryA(buffer, buflen); - if (len <= buflen-1) - { - buffer += len; - buflen -= len; - *buffer++ = '\\'; - buflen--; - strncpy(buffer, LDID_Data[ldid].StdString, buflen); - buffer[buflen-1] = '\0'; - } - handled = TRUE; - } - break; - } + FIXME("What is LDID %d ??\n", ldid); + *p = "LDID_FIXME"; } - - if (!handled) - handled = SETUPX_TranslateCustomLDID(ldid, buffer, buflen, hInf); - - if (!handled) - FIXME("unimplemented LDID %d\n", ldid); + else + *p = ldd.pszPath; return handled; } /*********************************************************************** * GenFormStrWithoutPlaceHolders + * + * ought to be pretty much implemented, I guess... */ void WINAPI GenFormStrWithoutPlaceHolders16( LPSTR szDst, LPCSTR szSrc, HINF16 hInf) { @@ -483,7 +971,7 @@ void WINAPI GenFormStrWithoutPlaceHolders16( LPSTR szDst, LPCSTR szSrc, HINF16 h LPSTR pDst = szDst, p, pPHBegin; int count; - FIXME("(%p, '%s', %04x), semi stub.\n", szDst, szSrc, hInf); + TRACE("(%p, '%s', %04x);\n", szDst, szSrc, hInf); while (pSrc < pSrcEnd) { p = strchr(pSrc, '%'); @@ -506,7 +994,9 @@ void WINAPI GenFormStrWithoutPlaceHolders16( LPSTR szDst, LPCSTR szSrc, HINF16 h ldid = atoi(placeholder); if (ldid) { - done = SETUPX_TranslateLDID(ldid, pDst, 256, hInf); + LPSTR p; + done = SETUPX_IP_TranslateLDID(ldid, &p, hInf); + strcpy(pDst, p); if (done) pDst += strlen(pDst); } @@ -549,49 +1039,183 @@ void WINAPI GenFormStrWithoutPlaceHolders16( LPSTR szDst, LPCSTR szSrc, HINF16 h } /*********************************************************************** - * CtlGetLddPath - */ -RETERR16 WINAPI CtlGetLddPath16(LOGDISKID16 ldid, LPSTR szPath) -{ - FIXME("(%04x, %p), stub.\n", ldid, szPath); - strcpy(szPath, "FIXME_BogusLddPath"); - return OK; -} - -/*********************************************************************** - * CtlSetLddPath - */ -RETERR16 WINAPI CtlSetLddPath16(LOGDISKID16 ldid, LPSTR szPath) -{ - FIXME("(%04x, '%s'), stub.\n", ldid, szPath); - return OK; -} - -/*********************************************************************** - * vcpOpen + * VcpOpen * - * p2 is "\001" for Netmeeting. + * No idea what to do here. */ -RETERR16 WINAPI vcpOpen16(LPWORD p1, LPWORD p2) +RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef) { - FIXME("(%p, %p), stub.\n", p1, p2); + FIXME("(%p, %08lx), stub.\n", vifproc, lparamMsgRef); return OK; } /*********************************************************************** * vcpClose + * + * Is fl related to VCPDISKINFO.fl ? */ -RETERR16 WINAPI vcpClose16(WORD w1, WORD w2, WORD w3) +RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest) { - FIXME("(%04x, %04x %04x), stub.\n", w1, w2, w3); + FIXME("(%04x, %s), stub.\n", fl, lpszBackupDest); return OK; } +/* + * Copy all items in a CopyFiles entry over to the destination + * + * - VNLP_xxx is what is given as flags for a .INF CopyFiles section + */ +static BOOL SETUPX_CopyFiles(LPSTR *pSub, HINF16 hInf) +{ + BOOL res = FALSE; + unsigned int n; + LPCSTR filename = IP_GetFileName(hInf); + LPSTR pCopyEntry; + char pDestStr[MAX_PATH]; + LPSTR pSrcDir, pDstDir; + LPSTR pFileEntries, p; + WORD ldid; + LOGDISKDESC_S ldd; + LPSTR *pSubFile; + LPSTR pSrcFile, pDstFile; + + for (n=0; n < *(DWORD *)pSub; n++) + { + pCopyEntry = *(pSub+1+n); + if (*pCopyEntry == '@') + { + ERR("single file not handled yet !\n"); + continue; + } + + /* get source directory for that entry */ + INIT_LDD(ldd, LDID_SRCPATH); + SETUPX_GetLdd(&ldd); + pSrcDir = ldd.pszPath; + + /* get destination directory for that entry */ + if (!(GetPrivateProfileStringA("DestinationDirs", pCopyEntry, "", + pDestStr, sizeof(pDestStr), filename))) + continue; + + /* translate destination dir if given as LDID */ + ldid = atoi(pDestStr); + if (ldid) + { + if (!(SETUPX_IP_TranslateLDID(ldid, &pDstDir, hInf))) + continue; + } + else + pDstDir = pDestStr; + + /* now that we have the destination dir, iterate over files to copy */ + pFileEntries = SETUPX_GetSectionEntries(filename, pCopyEntry); + for (p=pFileEntries; *p; p +=strlen(p)+1) + { + pSubFile = SETUPX_GetSubStrings(p, ','); + pSrcFile = *(pSubFile+1); + pDstFile = (*(DWORD *)pSubFile > 1) ? *(pSubFile+2) : pSrcFile; + TRACE("copying file '%s\\%s' to '%s\\%s'\n", pSrcDir, pSrcFile, pDstDir, pDstFile); + 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() */ + } + 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; +} + /*********************************************************************** * GenInstall + * + * general install function for .INF file sections + * + * This is not perfect - patch whenever you can ! + * + * wFlags == GENINSTALL_DO_xxx + * e.g. NetMeeting: + * first call GENINSTALL_DO_REGSRCPATH | GENINSTALL_DO_FILES, + * second call GENINSTALL_DO_LOGCONFIG | CFGAUTO | INI2REG | REG | INI */ RETERR16 WINAPI GenInstall16(HINF16 hInfFile, LPCSTR szInstallSection, WORD wFlags) { - FIXME("(%04x, '%s', %04x), stub. This doesn't install anything yet ! Use native SETUPX.DLL instead !!\n", hInfFile, szInstallSection, wFlags); + LPCSTR filename = IP_GetFileName(hInfFile); + LPSTR pEntries, p, pEnd; + DWORD len; + LPSTR *pSub; + + FIXME("(%04x, '%s', %04x), semi-stub. Please implement additional operations here !\n", hInfFile, szInstallSection, wFlags); + pEntries = SETUPX_GetSectionEntries(filename, szInstallSection); + if (!pEntries) + { + ERR("couldn't find entries for section '%s' !\n", szInstallSection); + return ERR_IP_SECT_NOT_FOUND; + } + for (p=pEntries; *p; p +=strlen(p)+1) + { + pEnd = strchr(p, '='); + if (!pEnd) continue; + pSub = SETUPX_GetSubStrings(pEnd+1, ','); /* split entries after the '=' */ + SETUPX_IsolateSubString(&p, &pEnd); + len = (int)pEnd - (int)p; + + if (wFlags & GENINSTALL_DO_FILES) + { + if (!strncasecmp(p, "CopyFiles", len)) + { + SETUPX_CopyFiles(pSub, hInfFile); + continue; + } +#if IMPLEMENT_THAT + else + if (!strncasecmp(p, "DelFiles", len)) + { + SETUPX_DelFiles(filename, szInstallSection, pSub); + continue; + } +#endif + } + if (wFlags & GENINSTALL_DO_INI) + { +#if IMPLEMENT_THAT + if (!strncasecmp(p, "UpdateInis", len)) + { + SETUPX_UpdateInis(filename, szInstallSection, pSub); + continue; + } +#endif + } + if (wFlags & GENINSTALL_DO_REG) + { +#if IMPLEMENT_THAT + /* probably use SUReg*() functions here */ + if (!strncasecmp(p, "AddReg", len)) + { + SETUPX_AddReg(filename, szInstallSection, pSub); + continue; + } + else + if (!strncasecmp(p, "DelReg", len)) + { + SETUPX_DelReg(filename, szInstallSection, pSub); + continue; + } +#endif + } + + SETUPX_FreeSubStrings(pSub); + } + HeapFree(GetProcessHeap(), 0, pEntries); return OK; } diff --git a/dlls/setupapi/setupx_private.h b/dlls/setupapi/setupx_private.h new file mode 100644 index 00000000000..dc73255cec9 --- /dev/null +++ b/dlls/setupapi/setupx_private.h @@ -0,0 +1,29 @@ +#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 */