Index: trunk/src/setupapi/LICENSE.TXT
===================================================================
--- trunk/src/setupapi/LICENSE.TXT	(revision 4989)
+++ trunk/src/setupapi/LICENSE.TXT	(revision 4989)
@@ -0,0 +1,28 @@
+$Id: LICENSE.TXT,v 1.1 2001-01-20 18:06:11 sandervl Exp $
+@c This is an additional Odin license agreement.
+@c It supercedes the main Odin license, but is only valid in 
+@c the source directory in which it is present.
+
+@c This file is processed by GNU's TeXinfo
+@c If you modify it or move it to another location, make sure that
+@c TeXinfo works (type `make' in directory documentation).
+
+Copyright (c) 1993-2000 the Wine project authors (see the file AUTHORS
+for a complete list)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Index: trunk/src/setupapi/devinst.c
===================================================================
--- trunk/src/setupapi/devinst.c	(revision 4989)
+++ trunk/src/setupapi/devinst.c	(revision 4989)
@@ -0,0 +1,29 @@
+/*
+ * SetupAPI device installer
+ *
+ */
+
+#include "debugtools.h"
+#include "windef.h"
+#include "setupx16.h"
+#include "heap.h"
+
+DEFAULT_DEBUG_CHANNEL(setupapi);
+
+/***********************************************************************
+ *		DiGetClassDevs (SETUPX.304)
+ * 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;
+}
Index: trunk/src/setupapi/infparse.c
===================================================================
--- trunk/src/setupapi/infparse.c	(revision 4989)
+++ trunk/src/setupapi/infparse.c	(revision 4989)
@@ -0,0 +1,123 @@
+/*
+ * SetupX .inf file parsing functions
+ *
+ * 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"
+#include "windef.h"
+#include "winbase.h"
+#include "heap.h"
+#include "wine/winbase16.h"
+#include "setupx16.h"
+#include "setupx_private.h"
+
+DEFAULT_DEBUG_CHANNEL(setupx);
+
+WORD InfNumEntries = 0;
+INF_FILE *InfList = NULL;
+HINF16 IP_curr_handle = 0;
+
+RETERR16 IP_OpenInf(LPCSTR lpInfFileName, HINF16 *lphInf)
+{
+    HFILE hFile = _lopen(lpInfFileName, OF_READ);
+
+    if (!lphInf)
+	return IP_ERROR;
+
+    /* this could be improved by checking for already freed handles */
+    if (IP_curr_handle == 0xffff) 
+	return ERR_IP_OUT_OF_HANDLES; 
+
+    if (hFile != HFILE_ERROR)
+    {
+	InfList = HeapReAlloc(GetProcessHeap(), 0, InfList, InfNumEntries+1);
+	InfList[InfNumEntries].hInf = IP_curr_handle++;
+	InfList[InfNumEntries].hInfFile = hFile;
+	InfList[InfNumEntries].lpInfFileName = HeapAlloc( GetProcessHeap(), 0,
+                                                          strlen(lpInfFileName)+1);
+        strcpy( InfList[InfNumEntries].lpInfFileName, lpInfFileName );
+        *lphInf = InfList[InfNumEntries].hInf;
+	InfNumEntries++;
+	TRACE("ret handle %d.\n", *lphInf);
+	return OK;
+    }
+    *lphInf = 0xffff;
+    return ERR_IP_INVALID_INFFILE;
+}
+
+BOOL IP_FindInf(HINF16 hInf, WORD *ret)
+{
+    WORD n;
+
+    for (n=0; n < InfNumEntries; n++)
+	if (InfList[n].hInf == hInf)
+	{
+	    *ret = n;
+	    return TRUE;
+	}
+    return FALSE;
+}
+	
+
+LPCSTR IP_GetFileName(HINF16 hInf)
+{
+    WORD n;
+    if (IP_FindInf(hInf, &n))
+    {
+	return InfList[n].lpInfFileName;
+    }
+    return NULL;
+}
+
+RETERR16 IP_CloseInf(HINF16 hInf)
+{
+    int i;
+    WORD n;
+    RETERR16 res = ERR_IP_INVALID_HINF;
+
+    if (IP_FindInf(hInf, &n))
+    {
+	_lclose(InfList[n].hInfFile);
+	HeapFree(GetProcessHeap(), 0, InfList[n].lpInfFileName);
+	for (i=n; i < InfNumEntries-1; i++)
+	    InfList[i] = InfList[i+1];
+	InfNumEntries--;
+	InfList = HeapReAlloc(GetProcessHeap(), 0, InfList, InfNumEntries);
+	res = OK;
+    }
+    return res;
+}
+
+/***********************************************************************
+ *		IpOpen16
+ *
+ */
+RETERR16 WINAPI IpOpen16(LPCSTR lpInfFileName, HINF16 *lphInf)
+{
+    TRACE("('%s', %p)\n", lpInfFileName, lphInf);
+    return IP_OpenInf(lpInfFileName, lphInf);
+}
+
+/***********************************************************************
+ *		IpClose16
+ */
+RETERR16 WINAPI IpClose16(HINF16 hInf)
+{
+    return IP_CloseInf(hInf);
+}
+
+/***********************************************************************
+ *		IpGetProfileString16
+ */
+RETERR16 WINAPI IpGetProfileString16(HINF16 hInf, LPCSTR section, LPCSTR entry, LPSTR buffer, WORD buflen) 
+{
+    TRACE("'%s': section '%s' entry '%s'\n", IP_GetFileName(hInf), section, entry);
+    GetPrivateProfileStringA(section, entry, "", buffer, buflen, IP_GetFileName(hInf));
+    return 0;
+}
Index: trunk/src/setupapi/makefile
===================================================================
--- trunk/src/setupapi/makefile	(revision 4989)
+++ trunk/src/setupapi/makefile	(revision 4989)
@@ -0,0 +1,46 @@
+# $Id: makefile,v 1.1 2001-01-20 18:06:12 sandervl Exp $
+
+#
+# Odin32 API
+#
+#       setupapi.dll makefile
+#
+
+
+#
+# Compiler, tools, and interference rules.
+#
+!include ../../makefile.inc
+
+
+#
+# Object files. Prefix with OBJDIR and one space before the '\'.
+#
+OBJS = \
+$(OBJDIR)\stubs.obj \
+$(OBJDIR)\setupapirsrc.obj \
+$(DLLENTRY)
+
+
+#
+# Libraries. One space before the '\'.
+#
+LIBS = \
+$(ODIN32_LIB)/kernel32.lib \
+$(ODIN32_LIB)/ole32.lib \
+$(ODIN32_LIB)/$(ODINCRT).lib \
+OS2386.LIB \
+$(RTLLIB_O)
+
+
+#
+# Target name - name of the dll without extention and path.
+#
+TARGET = setupapi
+
+
+#
+# Includes the common rules.
+#
+!include $(ODIN32_POST_INC)
+
Index: trunk/src/setupapi/setupapi.def
===================================================================
--- trunk/src/setupapi/setupapi.def	(revision 4989)
+++ trunk/src/setupapi/setupapi.def	(revision 4989)
@@ -0,0 +1,230 @@
+LIBRARY SETUPAPI INITINSTANCE TERMINSTANCE
+DESCRIPTION 'Odin SETUPAPI.DLL'
+DATA MULTIPLE NONSHARED
+
+EXPORTS
+
+; 45 stdcall SetupAddInstallSectionToDiskSpaceListA()         SetupAddInstallSectionToDiskSpaceListA
+; 46 stdcall SetupAddInstallSectionToDiskSpaceListW()         SetupAddInstallSectionToDiskSpaceListW
+; 47 stdcall SetupAddSectionToDiskSpaceListA()                SetupAddSectionToDiskSpaceListA
+; 48 stdcall SetupAddSectionToDiskSpaceListW()                SetupAddSectionToDiskSpaceListW
+; 49 stdcall SetupAddToDiskSpaceListA()                       SetupAddToDiskSpaceListA
+; 50 stdcall SetupAddToDiskSpaceListW()                       SetupAddToDiskSpaceListW
+; 51 stdcall SetupAddToSourceListA()                          SetupAddToSourceListA
+; 52 stdcall SetupAddToSourceListW()                          SetupAddToSourceListW
+; 53 stdcall SetupAdjustDiskSpaceListA()                      SetupAdjustDiskSpaceListA
+; 54 stdcall SetupAdjustDiskSpaceListW()                      SetupAdjustDiskSpaceListW
+; 55 stdcall SetupCancelTemporarySourceList()                 SetupCancelTemporarySourceList
+  SetupCloseFileQueue              = _SetupCloseFileQueue@4         @56
+  SetupCloseInfFile                = _SetupCloseInfFile@4           @57
+; 58 stdcall SetupCommitFileQueue()                           SetupCommitFileQueue
+  SetupCommitFileQueueA            = _SetupCommitFileQueueA@16      @59
+; 60 stdcall SetupCommitFileQueueW()                          SetupCommitFileQueueW
+; 61 stdcall SetupCopyErrorA()                                SetupCopyErrorA
+; 62 stdcall SetupCopyErrorW()                                SetupCopyErrorW
+; 63 stdcall SetupCreateDiskSpaceListA()                      SetupCreateDiskSpaceListA
+; 64 stdcall SetupCreateDiskSpaceListW()                      SetupCreateDiskSpaceListW
+; 65 stdcall SetupDecompressOrCopyFileA()                     SetupDecompressOrCopyFileA
+; 66 stdcall SetupDecompressOrCopyFileW()                     SetupDecompressOrCopyFileW
+; 67 stdcall SetupDefaultQueueCallback()                      SetupDefaultQueueCallback
+  SetupDefaultQueueCallbackA       = _SetupDefaultQueueCallbackA@16 @68
+; 69 stdcall SetupDefaultQueueCallbackW()                     SetupDefaultQueueCallbackW
+; 70 stdcall SetupDeleteErrorA()                              SetupDeleteErrorA
+; 71 stdcall SetupDeleteErrorW()                              SetupDeleteErrorW
+; 72 stdcall SetupDestroyDiskSpaceList()                      SetupDestroyDiskSpaceList
+; 73 stdcall SetupDiAskForOEMDisk()                           SetupDiAskForOEMDisk
+; 74 stdcall SetupDiBuildClassInfoList()                      SetupDiBuildClassInfoList
+; 75 stdcall SetupDiBuildDriverInfoList()                     SetupDiBuildDriverInfoList
+; 76 stdcall SetupDiCallClassInstaller()                      SetupDiCallClassInstaller
+; 77 stdcall SetupDiCancelDriverInfoSearch()                  SetupDiCancelDriverInfoSearch
+; 78 stdcall SetupDiChangeState()                             SetupDiChangeState
+; 79 stdcall SetupDiClassGuidsFromNameA()                     SetupDiClassGuidsFromNameA
+; 80 stdcall SetupDiClassGuidsFromNameW()                     SetupDiClassGuidsFromNameW
+; 81 stdcall SetupDiClassNameFromGuidA()                      SetupDiClassNameFromGuidA
+; 82 stdcall SetupDiClassNameFromGuidW()                      SetupDiClassNameFromGuidW
+; 83 stdcall SetupDiCreateDevRegKeyA()                        SetupDiCreateDevRegKeyA
+; 84 stdcall SetupDiCreateDevRegKeyW()                        SetupDiCreateDevRegKeyW
+; 85 stdcall SetupDiCreateDeviceInfoA()                       SetupDiCreateDeviceInfoA
+; 86 stdcall SetupDiCreateDeviceInfoList()                    SetupDiCreateDeviceInfoList
+; 87 stdcall SetupDiCreateDeviceInfoW()                       SetupDiCreateDeviceInfoW
+; 88 stdcall SetupDiDeleteDevRegKey()                         SetupDiDeleteDevRegKey
+; 89 stdcall SetupDiDeleteDeviceInfo()                        SetupDiDeleteDeviceInfo
+; 90 stdcall SetupDiDestroyClassImageList()                   SetupDiDestroyClassImageList
+; 91 stdcall SetupDiDestroyDeviceInfoList()                   SetupDiDestroyDeviceInfoList
+; 92 stdcall SetupDiDestroyDriverInfoList()                   SetupDiDestroyDriverInfoList
+; 93 stdcall SetupDiDrawMiniIcon()                            SetupDiDrawMiniIcon
+; 94 stdcall SetupDiEnumDeviceInfo()                          SetupDiEnumDeviceInfo
+; 95 stdcall SetupDiEnumDriverInfoA()                         SetupDiEnumDriverInfoA
+; 96 stdcall SetupDiEnumDriverInfoW()                         SetupDiEnumDriverInfoW
+; 97 stdcall SetupDiGetActualSectionToInstallA()              SetupDiGetActualSectionToInstallA
+; 98 stdcall SetupDiGetActualSectionToInstallW()              SetupDiGetActualSectionToInstallW
+; 99 stdcall SetupDiGetClassBitmapIndex()                     SetupDiGetClassBitmapIndex
+;100 stdcall SetupDiGetClassDescriptionA()                    SetupDiGetClassDescriptionA
+;101 stdcall SetupDiGetClassDescriptionW()                    SetupDiGetClassDescriptionW
+;102 stdcall SetupDiGetClassDevPropertySheetsA()              SetupDiGetClassDevPropertySheetsA
+;103 stdcall SetupDiGetClassDevPropertySheetsW()              SetupDiGetClassDevPropertySheetsW
+;104 stdcall SetupDiGetClassDevsA()                           SetupDiGetClassDevsA
+;105 stdcall SetupDiGetClassDevsW()                           SetupDiGetClassDevsW
+;106 stdcall SetupDiGetClassImageIndex()                      SetupDiGetClassImageIndex
+;107 stdcall SetupDiGetClassImageList()                       SetupDiGetClassImageList
+;108 stdcall SetupDiGetClassInstallParamsA()                  SetupDiGetClassInstallParamsA
+;109 stdcall SetupDiGetClassInstallParamsW()                  SetupDiGetClassInstallParamsW
+;110 stdcall SetupDiGetDeviceInfoListClass()                  SetupDiGetDeviceInfoListClass
+;111 stdcall SetupDiGetDeviceInstallParamsA()                 SetupDiGetDeviceInstallParamsA
+;112 stdcall SetupDiGetDeviceInstallParamsW()                 SetupDiGetDeviceInstallParamsW
+;113 stdcall SetupDiGetDeviceInstanceIdA()                    SetupDiGetDeviceInstanceIdA
+;114 stdcall SetupDiGetDeviceInstanceIdW()                    SetupDiGetDeviceInstanceIdW
+;115 stdcall SetupDiGetDeviceRegistryPropertyA()              SetupDiGetDeviceRegistryPropertyA
+;116 stdcall SetupDiGetDeviceRegistryPropertyW()              SetupDiGetDeviceRegistryPropertyW
+;117 stdcall SetupDiGetDriverInfoDetailA()                    SetupDiGetDriverInfoDetailA
+;118 stdcall SetupDiGetDriverInfoDetailW()                    SetupDiGetDriverInfoDetailW
+;119 stdcall SetupDiGetDriverInstallParamsA()                 SetupDiGetDriverInstallParamsA
+;120 stdcall SetupDiGetDriverInstallParamsW()                 SetupDiGetDriverInstallParamsW
+;121 stdcall SetupDiGetHwProfileFriendlyNameA()               SetupDiGetHwProfileFriendlyNameA
+;122 stdcall SetupDiGetHwProfileFriendlyNameW()               SetupDiGetHwProfileFriendlyNameW
+;123 stdcall SetupDiGetHwProfileList()                        SetupDiGetHwProfileList
+;124 stdcall SetupDiGetINFClassA()                            SetupDiGetINFClassA
+;125 stdcall SetupDiGetINFClassW()                            SetupDiGetINFClassW
+;126 stdcall SetupDiGetSelectedDevice()                       SetupDiGetSelectedDevice
+;127 stdcall SetupDiGetSelectedDriverA()                      SetupDiGetSelectedDriverA
+;128 stdcall SetupDiGetSelectedDriverW()                      SetupDiGetSelectedDriverW
+;129 stdcall SetupDiGetWizardPage()                           SetupDiGetWizardPage
+;130 stdcall SetupDiInstallClassA()                           SetupDiInstallClassA
+;131 stdcall SetupDiInstallClassW()                           SetupDiInstallClassW
+;132 stdcall SetupDiInstallDevice()                           SetupDiInstallDevice
+;133 stdcall SetupDiInstallDriverFiles()                      SetupDiInstallDriverFiles
+;134 stdcall SetupDiLoadClassIcon()                           SetupDiLoadClassIcon
+;135 stdcall SetupDiMoveDuplicateDevice()                     SetupDiMoveDuplicateDevice
+;136 stdcall SetupDiOpenClassRegKey()                         SetupDiOpenClassRegKey
+;137 stdcall SetupDiOpenDevRegKey()                           SetupDiOpenDevRegKey
+;138 stdcall SetupDiOpenDeviceInfoA()                         SetupDiOpenDeviceInfoA
+;139 stdcall SetupDiOpenDeviceInfoW()                         SetupDiOpenDeviceInfoW
+;140 stdcall SetupDiRegisterDeviceInfo()                      SetupDiRegisterDeviceInfo
+;141 stdcall SetupDiRemoveDevice()                            SetupDiRemoveDevice
+;142 stdcall SetupDiSelectDevice()                            SetupDiSelectDevice
+;143 stdcall SetupDiSelectOEMDrv()                            SetupDiSelectOEMDrv
+;144 stdcall SetupDiSetClassInstallParamsA()                  SetupDiSetClassInstallParamsA
+;145 stdcall SetupDiSetClassInstallParamsW()                  SetupDiSetClassInstallParamsW
+;146 stdcall SetupDiSetDeviceInstallParamsA()                 SetupDiSetDeviceInstallParamsA
+;147 stdcall SetupDiSetDeviceInstallParamsW()                 SetupDiSetDeviceInstallParamsW
+;148 stdcall SetupDiSetDeviceRegistryPropertyA()              SetupDiSetDeviceRegistryPropertyA
+;149 stdcall SetupDiSetDeviceRegistryPropertyW()              SetupDiSetDeviceRegistryPropertyW
+;150 stdcall SetupDiSetDriverInstallParamsA()                 SetupDiSetDriverInstallParamsA
+;151 stdcall SetupDiSetDriverInstallParamsW()                 SetupDiSetDriverInstallParamsW
+;152 stdcall SetupDiSetSelectedDevice()                       SetupDiSetSelectedDevice
+;153 stdcall SetupDiSetSelectedDriverA()                      SetupDiSetSelectedDriverA
+;154 stdcall SetupDiSetSelectedDriverW()                      SetupDiSetSelectedDriverW
+;155 stdcall SetupDuplicateDiskSpaceListA()                   SetupDuplicateDiskSpaceListA
+;156 stdcall SetupDuplicateDiskSpaceListW()                   SetupDuplicateDiskSpaceListW
+  SetupFindFirstLineA                      = _SetupFindFirstLineA@16       @157
+;158 stdcall SetupFindFirstLineW()                            SetupFindFirstLineW
+  SetupFindNextLine                        = _SetupFindNextLine@8          @159
+;160 stdcall SetupFindNextMatchLineA()                        SetupFindNextMatchLineA
+;161 stdcall SetupFindNextMatchLineW()                        SetupFindNextMatchLineW
+;162 stdcall SetupFreeSourceListA()                           SetupFreeSourceListA
+;163 stdcall SetupFreeSourceListW()                           SetupFreeSourceListW
+;164 stdcall SetupGetBinaryField()                            SetupGetBinaryField
+;165 stdcall SetupGetFieldCount()                             SetupGetFieldCount
+;166 stdcall SetupGetFileCompressionInfoA()                   SetupGetFileCompressionInfoA
+;167 stdcall SetupGetFileCompressionInfoW()                   SetupGetFileCompressionInfoW
+;168 stdcall SetupGetInfFileListA()                           SetupGetInfFileListA
+;169 stdcall SetupGetInfFileListW()                           SetupGetInfFileListW
+;170 stdcall SetupGetInfInformationA()                        SetupGetInfInformationA
+;171 stdcall SetupGetInfInformationW()                        SetupGetInfInformationW
+;172 stdcall SetupGetIntField()                               SetupGetIntField
+  SetupGetLineByIndexA                     = _SetupGetLineByIndexA@16      @173
+;174 stdcall SetupGetLineByIndexW()                           SetupGetLineByIndexW
+;175 stdcall SetupGetLineCountA()                             SetupGetLineCountA
+;176 stdcall SetupGetLineCountW()                             SetupGetLineCountW
+  SetupGetLineTextA                        = _SetupGetLineTextA@28         @177
+;178 stdcall SetupGetLineTextW()                              SetupGetLineTextW
+;179 stdcall SetupGetMultiSzFieldA()                          SetupGetMultiSzFieldA
+;180 stdcall SetupGetMultiSzFieldW()                          SetupGetMultiSzFieldW
+;181 stdcall SetupGetSourceFileLocationA()                    SetupGetSourceFileLocationA
+;182 stdcall SetupGetSourceFileLocationW()                    SetupGetSourceFileLocationW
+;183 stdcall SetupGetSourceFileSizeA()                        SetupGetSourceFileSizeA
+;184 stdcall SetupGetSourceFileSizeW()                        SetupGetSourceFileSizeW
+;185 stdcall SetupGetSourceInfoA()                            SetupGetSourceInfoA
+;186 stdcall SetupGetSourceInfoW()                            SetupGetSourceInfoW
+  SetupGetStringFieldA                     = _SetupGetStringFieldA@20      @187
+;188 stdcall SetupGetStringFieldW()                           SetupGetStringFieldW
+;189 stdcall SetupGetTargetPathA()                            SetupGetTargetPathA
+;190 stdcall SetupGetTargetPathW()                            SetupGetTargetPathW
+  SetupInitDefaultQueueCallback            = _SetupInitDefaultQueueCallback@4 @191
+  SetupInitDefaultQueueCallbackEx          = _SetupInitDefaultQueueCallbackEx@20 @192
+;193 stdcall SetupInitializeFileLogA()                        SetupInitializeFileLogA
+;194 stdcall SetupInitializeFileLogW()                        SetupInitializeFileLogW
+;195 stdcall SetupInstallFileA()                              SetupInstallFileA
+;196 stdcall SetupInstallFileExA()                            SetupInstallFileExA
+;197 stdcall SetupInstallFileExW()                            SetupInstallFileExW
+;198 stdcall SetupInstallFileW()                              SetupInstallFileW
+;199 stdcall SetupInstallFilesFromInfSectionA()               SetupInstallFilesFromInfSectionA
+;200 stdcall SetupInstallFilesFromInfSectionW()               SetupInstallFilesFromInfSectionW
+  SetupInstallFromInfSectionA               = _SetupInstallFromInfSectionA@44 @201
+;202 stdcall SetupInstallFromInfSectionW()                    SetupInstallFromInfSectionW
+;203 stdcall SetupInstallServicesFromInfSectionA()            SetupInstallServicesFromInfSectionA
+;204 stdcall SetupInstallServicesFromInfSectionW()            SetupInstallServicesFromInfSectionW
+  SetupIterateCabinetA                      = _SetupIterateCabinetA@16    @203
+  SetupIterateCabinetW                      = _SetupIterateCabinetW@16    @204
+;207 stdcall SetupLogFileA()                                  SetupLogFileA
+;208 stdcall SetupLogFileW()                                  SetupLogFileW
+  SetupOpenAppendInfFileA                   = _SetupOpenAppendInfFileA@12 @209
+;210 stdcall SetupOpenAppendInfFileW()                        SetupOpenAppendInfFileW
+  SetupOpenFileQueue                        = _SetupOpenFileQueue@0       @211
+  SetupOpenInfFileA                         = _SetupOpenInfFileA@16       @212
+;213 stdcall SetupOpenInfFileW()                              SetupOpenInfFileW
+;214 stdcall SetupOpenMasterInf()                             SetupOpenMasterInf
+;215 stdcall SetupPromptForDiskA()                            SetupPromptForDiskA
+;216 stdcall SetupPromptForDiskW()                            SetupPromptForDiskW
+;217 stdcall SetupPromptReboot()                              SetupPromptReboot
+;218 stdcall SetupQueryDrivesInDiskSpaceListA()               SetupQueryDrivesInDiskSpaceListA
+;219 stdcall SetupQueryDrivesInDiskSpaceListW()               SetupQueryDrivesInDiskSpaceListW
+;220 stdcall SetupQueryFileLogA()                             SetupQueryFileLogA
+;221 stdcall SetupQueryFileLogW()                             SetupQueryFileLogW
+;222 stdcall SetupQueryInfFileInformationA()                  SetupQueryInfFileInformationA
+;223 stdcall SetupQueryInfFileInformationW()                  SetupQueryInfFileInformationW
+;224 stdcall SetupQueryInfVersionInformationA()               SetupQueryInfVersionInformationA
+;225 stdcall SetupQueryInfVersionInformationW()               SetupQueryInfVersionInformationW
+;226 stdcall SetupQuerySourceListA()                          SetupQuerySourceListA
+;227 stdcall SetupQuerySourceListW()                          SetupQuerySourceListW
+;228 stdcall SetupQuerySpaceRequiredOnDriveA()                SetupQuerySpaceRequiredOnDriveA
+;229 stdcall SetupQuerySpaceRequiredOnDriveW()                SetupQuerySpaceRequiredOnDriveW
+  SetupQueueCopyA                            = _SetupQueueCopyA@36        @230
+;231 stdcall SetupQueueCopySectionA()                         SetupQueueCopySectionA
+;232 stdcall SetupQueueCopySectionW()                         SetupQueueCopySectionW
+;233 stdcall SetupQueueCopyW()                                SetupQueueCopyW
+;234 stdcall SetupQueueDefaultCopyA()                         SetupQueueDefaultCopyA
+;235 stdcall SetupQueueDefaultCopyW()                         SetupQueueDefaultCopyW
+;236 stdcall SetupQueueDeleteA()                              SetupQueueDeleteA
+;237 stdcall SetupQueueDeleteSectionA()                       SetupQueueDeleteSectionA
+;238 stdcall SetupQueueDeleteSectionW()                       SetupQueueDeleteSectionW
+;239 stdcall SetupQueueDeleteW()                              SetupQueueDeleteW
+;240 stdcall SetupQueueRenameA()                              SetupQueueRenameA
+;241 stdcall SetupQueueRenameSectionA()                       SetupQueueRenameSectionA
+;242 stdcall SetupQueueRenameSectionW()                       SetupQueueRenameSectionW
+;243 stdcall SetupQueueRenameW()                              SetupQueueRenameW
+;244 stdcall SetupRemoveFileLogEntryA()                       SetupRemoveFileLogEntryA
+;245 stdcall SetupRemoveFileLogEntryW()                       SetupRemoveFileLogEntryW
+;246 stdcall SetupRemoveFromDiskSpaceListA()                  SetupRemoveFromDiskSpaceListA
+;247 stdcall SetupRemoveFromDiskSpaceListW()                  SetupRemoveFromDiskSpaceListW
+;248 stdcall SetupRemoveFromSourceListA()                     SetupRemoveFromSourceListA
+;249 stdcall SetupRemoveFromSourceListW()                     SetupRemoveFromSourceListW
+;250 stdcall SetupRemoveInstallSectionFromDiskSpaceListA()    SetupRemoveInstallSectionFromDiskSpaceListA
+;251 stdcall SetupRemoveInstallSectionFromDiskSpaceListW()    SetupRemoveInstallSectionFromDiskSpaceListW
+;252 stdcall SetupRemoveSectionFromDiskSpaceListA()           SetupRemoveSectionFromDiskSpaceListA
+;253 stdcall SetupRemoveSectionFromDiskSpaceListW()           SetupRemoveSectionFromDiskSpaceListW
+;254 stdcall SetupRenameErrorA()                              SetupRenameErrorA
+;255 stdcall SetupRenameErrorW()                              SetupRenameErrorW
+;256 stdcall SetupScanFileQueue()                             SetupScanFileQueue
+;257 stdcall SetupScanFileQueueA()                            SetupScanFileQueueA
+;258 stdcall SetupScanFileQueueW()                            SetupScanFileQueueW
+  SetupSetDirectoryIdA                       = _SetupSetDirectoryIdA@12   @259
+;260 stdcall SetupSetDirectoryIdExA(long long str long long ptr)  SetupSetDirectoryIdExA
+;261 stdcall SetupSetDirectoryIdExW(long long wstr long long ptr) SetupSetDirectoryIdExW
+;262 stdcall SetupSetDirectoryIdW(long long wstr)             SetupSetDirectoryIdW
+;263 stdcall SetupSetPlatformPathOverrideA(str)               SetupSetPlatformPathOverrideA
+;264 stdcall SetupSetPlatformPathOverrideW(wstr)              SetupSetPlatformPathOverrideW
+;265 stdcall SetupSetSourceListA(long str long)               SetupSetSourceListA
+;266 stdcall SetupSetSourceListW(long wstr long)              SetupSetSourceListW
+  SetupTermDefaultQueueCallback              = _SetupTermDefaultQueueCallback@4 @267
+;268 stdcall SetupTerminateFileLog(ptr)                       SetupTerminateFileLog
Index: trunk/src/setupapi/setupapirsrc.orc
===================================================================
--- trunk/src/setupapi/setupapirsrc.orc	(revision 4989)
+++ trunk/src/setupapi/setupapirsrc.orc	(revision 4989)
@@ -0,0 +1,41 @@
+/* $Id: setupapirsrc.orc,v 1.1 2001-01-20 18:06:12 sandervl Exp $ */
+
+#include "winuser.h"
+#include "odinrsrc.h"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version (based on NT 4 SP6)
+//
+
+1 VERSIONINFO
+ FILEVERSION 0x04, 0x00, 0x0565, 0x0123
+ PRODUCTVERSION 0x04, 0x00, 0x0565, 0x0123
+ FILEFLAGSMASK 0x3fL
+ FILEFLAGS 0xaL
+ FILEOS 0x10001L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904E4"
+        BEGIN
+            VALUE "Comments", "Odin32 System Dll\0"
+            VALUE "CompanyName", "Odin Team\0"
+            VALUE "FileDescription", "SETUPAPI System dll\0"
+            VALUE "FileVersion", "4.00\0"
+            VALUE "InternalName", "SETUPAPI\0"
+            VALUE "LegalCopyright", "Copyright (C) 1999-2001\0"
+            VALUE "LegalTrademarks", "\0"
+            VALUE "OriginalFilename", "SETUPAPI.DLL\0"
+            VALUE "ProductName", "Odin32 - SETUPAPI\0"
+            VALUE "ProductVersion", "4.00\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+	VALUE "Translation", 0x409, 0x04E4
+    END
+END
Index: trunk/src/setupapi/setupx16.h
===================================================================
--- trunk/src/setupapi/setupx16.h	(revision 4989)
+++ trunk/src/setupapi/setupx16.h	(revision 4989)
@@ -0,0 +1,213 @@
+#ifndef __SETUPX16_H
+#define __SETUPX16_H
+
+#include "wine/windef16.h"
+
+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,
+	ERR_IP_ALLOC_ERR,
+	ERR_IP_INVALID_SECT_NAME,
+	ERR_IP_OUT_OF_HANDLES,
+	ERR_IP_INF_NOT_FOUND,
+	ERR_IP_INVALID_INFFILE,
+	ERR_IP_INVALID_HINF,
+	ERR_IP_INVALID_FIELD,
+	ERR_IP_SECT_NOT_FOUND,
+	ERR_IP_END_OF_SECTION,
+	ERR_IP_PROFILE_NOT_FOUND,
+	ERR_IP_LINE_NOT_FOUND,
+	ERR_IP_FILEREAD,
+	ERR_IP_TOOMANYINFFILES,
+	ERR_IP_INVALID_SAVERESTORE,
+	ERR_IP_INVALID_INFTYPE
+};
+
+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 */
+#define LDID_SETUPTEMP		2		/* setup temp dir */
+#define LDID_UNINSTALL		3		/* uninstall dir */
+#define LDID_BACKUP		4		/* backup dir */
+#define LDID_SETUPSCRATCH	5		/* setup scratch dir */
+#define LDID_WIN		10		/* win dir */
+#define LDID_SYS		11		/* win system dir */
+#define LDID_IOS		12		/* win Iosubsys dir */
+#define LDID_CMD		13		/* win command dir */
+#define LDID_CPL		14		/* win control panel dir */
+#define LDID_PRINT		15		/* win printer dir */
+#define LDID_MAIL		16		/* win mail dir */
+#define LDID_INF		17		/* win inf dir */
+#define LDID_HELP		18		/* win help dir */
+#define LDID_WINADMIN		19		/* admin dir */
+#define LDID_FONTS		20		/* win fonts dir */
+#define LDID_VIEWERS		21		/* win viewers dir */
+#define LDID_VMM32		22		/* win VMM32 dir */
+#define LDID_COLOR		23		/* win color mngment dir */
+#define LDID_APPS		24		/* win apps dir */
+#define LDID_SHARED		25		/* win shared dir */
+#define LDID_WINBOOT		26		/* guaranteed win boot drive */
+#define LDID_MACHINE		27		/* machine specific files */
+#define LDID_HOST_WINBOOT	28
+#define LDID_BOOT		30		/* boot drive root dir */
+#define LDID_BOOT_HOST		31		/* boot drive host root dir */
+#define LDID_OLD_WINBOOT	32		/* root subdir */
+#define LDID_OLD_WIN		33		/* old windows dir */
+
+/* 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
+
+#define GEINISTALL_DO_INIREG		14
+#define GENINSTALL_DO_ALL		255
+
+/*
+ * 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 */
Index: trunk/src/setupapi/setupx_main.c
===================================================================
--- trunk/src/setupapi/setupx_main.c	(revision 4989)
+++ trunk/src/setupapi/setupx_main.c	(revision 4989)
@@ -0,0 +1,1230 @@
+/*
+ *      SETUPX library
+ *
+ *      Copyright 1998,2000  Andreas Mohr
+ *
+ * FIXME: Rather non-functional functions for now.
+ *
+ * See:
+ * http://www.geocities.com/SiliconValley/Network/5317/drivers.html
+ * http://willemer.de/informatik/windows/inf_info.htm (German)
+ * http://www.microsoft.com/ddk/ddkdocs/win98ddk/devinst_12uw.htm
+ * 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)
+ * - ie5setup.exe
+ * - Netmeeting
+ *
+ * FIXME:
+ * - 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 <stdlib.h>
+#include <stdio.h>
+#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);
+
+/***********************************************************************
+ *		SURegOpenKey
+ */
+DWORD WINAPI SURegOpenKey( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
+{
+    FIXME("(%x,%s,%p), semi-stub.\n",hkey,debugstr_a(lpszSubKey),retkey);
+    return RegOpenKeyA( hkey, lpszSubKey, retkey );
+}
+
+/***********************************************************************
+ *		SURegQueryValueEx
+ */
+DWORD WINAPI SURegQueryValueEx( HKEY hkey, LPSTR lpszValueName,
+                                LPDWORD lpdwReserved, LPDWORD lpdwType,
+                                LPBYTE lpbData, LPDWORD lpcbData )
+{
+    FIXME("(%x,%s,%p,%p,%p,%ld), semi-stub.\n",hkey,debugstr_a(lpszValueName),
+          lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
+    return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
+                               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
+ *
+ * hwnd = parent window
+ * 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).
+ * The 132 value is made of the HOW_xxx flags and sometimes 128 (-> setupx16.h).
+ * 
+ * nCmdShow = nCmdShow of CreateProcess
+ */
+typedef INT WINAPI (*MSGBOX_PROC)( HWND, LPCSTR, LPCSTR, UINT );
+RETERR16 WINAPI InstallHinfSection16( HWND16 hwnd, HINSTANCE16 hinst, LPCSTR lpszCmdLine, INT16 nCmdShow)
+{
+    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
+{
+    LPCSTR RegValName;
+    LPCSTR StdString; /* fallback string; sub dir of windows directory */
+} LDID_DATA;
+
+static const LDID_DATA LDID_Data[34] =
+{
+    { /* 0 (LDID_NULL) -- not defined */
+	NULL,
+	NULL
+    },
+    { /* 1 (LDID_SRCPATH) = source of installation. hmm, what to do here ? */
+	"SourcePath", /* hmm, does SETUPX have to care about updating it ?? */
+	NULL
+    },
+    { /* 2 (LDID_SETUPTEMP) = setup temp dir */
+	"SetupTempDir",
+	NULL
+    },
+    { /* 3 (LDID_UNINSTALL) = uninstall backup dir */
+	"UninstallDir",
+	NULL
+    },
+    { /* 4 (LDID_BACKUP) = backup dir */
+	"BackupDir",
+	NULL
+    },
+    { /* 5 (LDID_SETUPSCRATCH) = setup scratch dir */
+	"SetupScratchDir",
+	NULL
+    },
+    { /* 6 -- not defined */
+	NULL,
+	NULL
+    },
+    { /* 7 -- not defined */
+	NULL,
+	NULL
+    },
+    { /* 8 -- not defined */
+	NULL,
+	NULL
+    },
+    { /* 9 -- not defined */
+	NULL,
+	NULL
+    },
+    { /* 10 (LDID_WIN) = windows dir */
+	"WinDir",
+        ""
+    },
+    { /* 11 (LDID_SYS) = system dir */
+	"SysDir",
+	NULL /* call GetSystemDirectory() instead */
+    },
+    { /* 12 (LDID_IOS) = IOSubSys dir */
+        NULL, /* FIXME: registry string ? */
+	"SYSTEM\\IOSUBSYS"
+    },
+    { /* 13 (LDID_CMD) = COMMAND dir */
+	NULL, /* FIXME: registry string ? */
+	"COMMAND"
+    },
+    { /* 14 (LDID_CPL) = control panel dir */
+	NULL,
+	""
+    },
+    { /* 15 (LDID_PRINT) = windows printer dir */
+	NULL,
+	"SYSTEM" /* correct ?? */
+    },
+    { /* 16 (LDID_MAIL) = destination mail dir */
+	NULL,
+	""
+    },
+    { /* 17 (LDID_INF) = INF dir */
+	"SetupScratchDir", /* correct ? */
+	"INF"
+    },
+    { /* 18 (LDID_HELP) = HELP dir */
+	NULL, /* ??? */
+	"HELP"
+    },
+    { /* 19 (LDID_WINADMIN) = Admin dir */
+	"WinAdminDir",
+	""
+    },
+    { /* 20 (LDID_FONTS) = Fonts dir */
+	NULL, /* ??? */
+	"FONTS"
+    },
+    { /* 21 (LDID_VIEWERS) = Viewers */
+	NULL, /* ??? */
+	"SYSTEM\\VIEWERS"
+    },
+    { /* 22 (LDID_VMM32) = VMM32 dir */
+	NULL, /* ??? */
+	"SYSTEM\\VMM32"
+    },
+    { /* 23 (LDID_COLOR) = ICM dir */
+	"ICMPath",
+	"SYSTEM\\COLOR"
+    },
+    { /* 24 (LDID_APPS) = root of boot drive ? */
+	"AppsDir",
+	"C:\\"
+    },
+    { /* 25 (LDID_SHARED) = shared dir */
+	"SharedDir",
+	""
+    },
+    { /* 26 (LDID_WINBOOT) = Windows boot dir */
+	"WinBootDir",
+	""
+    },
+    { /* 27 (LDID_MACHINE) = machine specific files */
+	"MachineDir",
+	NULL
+    },
+    { /* 28 (LDID_HOST_WINBOOT) = Host Windows boot dir */
+	"HostWinBootDir",
+	NULL
+    },
+    { /* 29 -- not defined */
+	NULL,
+	NULL
+    },
+    { /* 30 (LDID_BOOT) = Root of boot drive */
+	"BootDir",
+	NULL
+    },
+    { /* 31 (LDID_BOOT_HOST) = Root of boot drive host */
+	"BootHost",
+	NULL
+    },
+    { /* 32 (LDID_OLD_WINBOOT) = subdir of root */
+	"OldWinBootDir",
+	NULL
+    },
+    { /* 33 (LDID_OLD_WIN) = old win dir */
+	"OldWinDir",
+	NULL
+    }
+    /* the rest (34-38) isn't too interesting, so I'll forget about it */
+};
+
+/* 
+ * 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)
+{
+    HKEY hKey = 0;
+    WORD n;
+    DWORD type, len;
+    LOGDISKDESC_S ldd;
+    char buffer[MAX_PATH];
+
+    /* has to be here, otherwise loop */
+    std_LDDs_done = TRUE;
+
+    RegOpenKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup", &hKey);
+
+    for (n=0; n < sizeof(LDID_Data)/sizeof(LDID_DATA); n++)
+    {
+	buffer[0] = '\0';
+
+	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, *pPrev = NULL;
+
+    TRACE("(%d)\n", ldid);
+
+    if (!std_LDDs_done)
+	SETUPX_CreateStandardLDDs();
+
+    if (ldid < LDID_ASSIGN_START)
+	return ERR_VCP_LDDINVALID;
+
+    pCurr = pFirstLDD;
+    /* 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;
+}
+
+/***********************************************************************
+ *		CtlDelLdd (SETUPX.37)
+ */
+RETERR16 WINAPI CtlDelLdd16(LOGDISKID16 ldid)
+{
+    FIXME("(%d); - please report to a.mohr@mailto.de !!!\n", ldid);
+    return SETUPX_DelLdd(ldid);
+}
+
+/***********************************************************************
+ * CtlFindLdd		(SETUPX.35)
+ *
+ * doesn't check pldd ptr validity: crash (W98SE)
+ *
+ * RETURN
+ *   ERR_VCP_LDDINVALID if pldd->cbSize != structsize
+ *   1 in all other cases ??
+ * 
+ */
+RETERR16 WINAPI CtlFindLdd16(LPLOGDISKDESC pldd)
+{
+    LDD_LIST *pCurr, *pPrev = NULL;
+
+    TRACE("(%p)\n", pldd);
+   
+    if (!std_LDDs_done)
+	SETUPX_CreateStandardLDDs();
+
+    if (pldd->cbSize != sizeof(LOGDISKDESC_S))
+        return ERR_VCP_LDDINVALID;
+
+    pCurr = pFirstLDD;
+    /* 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 */
+      || (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 */
+    
+    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, *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();
+    pCurr = pFirstLDD;
+    /* 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
+    {
+        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);
+    }
+
+    memcpy(pCurrLDD, pldd, sizeof(LOGDISKDESC_S));
+
+    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);
+
+    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, *pPrev = NULL;
+
+    if (!std_LDDs_done)
+	SETUPX_CreateStandardLDDs();
+
+    if (pldd->cbSize != sizeof(LOGDISKDESC_S))
+        return ERR_VCP_LDDINVALID;
+
+    pCurr = pFirstLDD;
+    /* 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);
+}
+
+/*
+ * Find the value of a custom LDID in a .inf file
+ * e.g. for 49301:
+ * 49300,49301=ProgramFilesDir,5
+ * -- profile section lookup -->
+ * [ProgramFilesDir]
+ * HKLM,"Software\Microsoft\Windows\CurrentVersion","ProgramFilesDir",,"%24%"
+ * -- GenFormStrWithoutPlaceHolders16 -->
+ * HKLM,"Software\Microsoft\Windows\CurrentVersion","ProgramFilesDir",,"C:\"
+ * -- registry lookup -->
+ * C:\Program Files (or C:\ if not found in registry)
+ * 
+ * FIXME:
+ * - 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_AddCustomLDID(int ldid, INT16 hInf)
+{
+    char ldidstr[6];
+    LPSTR sectionbuf = NULL, entrybuf = NULL, regsectionbuf = NULL;
+    LPCSTR filename;
+    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 (!(sectionbuf = SETUPX_GetSections(filename)))
+    {
+	ERR("couldn't get sections !\n");
+	return FALSE;
+    }
+    for (pSec=sectionbuf; *pSec; pSec += strlen(pSec)+1)
+    {
+	if (!(entrybuf = SETUPX_GetSectionEntries(filename, pSec)))
+	{
+	    ERR("couldn't get section entries !\n");
+	    goto end;
+	}
+	for (pEnt=entrybuf; *pEnt; pEnt += strlen(pEnt)+1)
+	{
+	    if (strstr(pEnt, ldidstr))
+	    {
+		pEqual = strchr(pEnt, '=');
+		if (!pEqual) /* crippled entry ?? */
+		    continue;
+
+		/* make sure we found the LDID on left side of the equation */
+		if (pEnt+strlen(ldidstr) <= pEqual)
+		{ /* found */
+
+		    /* but we don't want entries in the strings section */
+		    if (!strcasecmp(pSec, "Strings"))
+			goto next_section;
+		    p = pEqual+1;
+		    goto found;
+		}
+	    }
+	}
+next_section:
+    }
+    goto end;
+found:
+    TRACE("found entry '%s'\n", p);
+    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 (!(regsectionbuf = SETUPX_GetSectionEntries(filename, *(pSub+1))))
+    {
+	ERR("couldn't get registry section entries !\n");
+	goto end;
+    }
+    /* 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_IP_TranslateLDID(int ldid, LPSTR *p, HINF16 hInf)
+{
+    BOOL handled = FALSE;
+    LOGDISKDESC_S ldd;
+
+    ldd.cbSize = sizeof(LOGDISKDESC_S);
+    ldd.ldid = ldid;
+    if (CtlFindLdd16(&ldd) == ERR_VCP_LDDFIND)
+    {
+	/* 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)
+    {
+        FIXME("What is LDID %d ??\n", ldid);
+	*p = "LDID_FIXME";
+    }
+    else
+	*p = ldd.pszPath;
+
+    return handled;
+}
+
+/***********************************************************************
+ *		GenFormStrWithoutPlaceHolders
+ *
+ * ought to be pretty much implemented, I guess...
+ */
+void WINAPI GenFormStrWithoutPlaceHolders16( LPSTR szDst, LPCSTR szSrc, HINF16 hInf)
+{
+    LPCSTR pSrc = szSrc, pSrcEnd = szSrc + strlen(szSrc);
+    LPSTR pDst = szDst, p, pPHBegin;
+    int count;
+    
+    TRACE("(%p, '%s', %04x);\n", szDst, szSrc, hInf);
+    while (pSrc < pSrcEnd)
+    {
+	p = strchr(pSrc, '%');
+	if (p)
+	{
+	    count = (int)p - (int)pSrc;
+	    strncpy(pDst, pSrc, count);
+	    pSrc += count;
+	    pDst += count;
+	    pPHBegin = p+1;
+	    p = strchr(pPHBegin, '%');
+	    if (p)
+	    {
+		char placeholder[80]; /* that really ought to be enough ;) */
+		int ldid;
+		BOOL done = TRUE;
+		count = (int)p - (int)pPHBegin;
+		strncpy(placeholder, pPHBegin, count);
+		placeholder[count] = '\0';
+		ldid = atoi(placeholder);
+		if (ldid)
+		{
+		    LPSTR p;
+		    done = SETUPX_IP_TranslateLDID(ldid, &p, hInf);
+		    strcpy(pDst, p);
+		    if (done)
+			pDst += strlen(pDst);
+		}
+		else
+		{ /* hmm, string placeholder. Need to look up
+		     in the [strings] section of the hInf */
+		    DWORD ret;
+		    char buf[256]; /* long enough ? */
+		    
+		    ret = GetPrivateProfileStringA("strings", placeholder, "",
+		    			buf, 256, IP_GetFileName(hInf));
+		    if (ret)
+		    {
+			strcpy(pDst, buf);
+			pDst += strlen(buf);
+		    }
+		    else
+		    {
+		        ERR("placeholder string '%s' not found !\n", placeholder);
+			done = FALSE;
+		    }
+		}
+		if (!done)
+		{ /* copy raw placeholder string over */
+		    count = (int)p - (int)pPHBegin + 2;
+		    strncpy(pDst, pPHBegin-1, count);
+		    pDst += count;
+		    
+		}
+		pSrc = p+1;
+		continue;
+	    }
+	}
+
+	/* copy the remaining source string over */
+	strncpy(pDst, pSrc, (int)pSrcEnd - (int)pSrc + 1);
+	break;
+    }
+    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
+ *
+ * - 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)
+{
+    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;
+}
Index: trunk/src/setupapi/setupx_private.h
===================================================================
--- trunk/src/setupapi/setupx_private.h	(revision 4989)
+++ trunk/src/setupapi/setupx_private.h	(revision 4989)
@@ -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 */
Index: trunk/src/setupapi/stubs.c
===================================================================
--- trunk/src/setupapi/stubs.c	(revision 4989)
+++ trunk/src/setupapi/stubs.c	(revision 4989)
@@ -0,0 +1,225 @@
+/* -*- tab-width: 8; c-basic-offset: 8 -*- */
+/*
+ * SetupAPI stubs
+ *
+ */
+
+#include "debugtools.h"
+#include "windef.h"
+#ifdef __WIN32OS2__
+#include "ole2.h"
+#endif
+#include "setupapi.h"
+
+DEFAULT_DEBUG_CHANNEL(setupapi);
+
+
+/***********************************************************************
+ *		SetupCloseFileQueue
+ */
+VOID WINAPI SetupCloseFileQueue(HSPFILEQ QueueHandle)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+}
+
+/***********************************************************************
+ *		SetupCommitFileQueueA
+ */
+BOOL WINAPI SetupCommitFileQueueA(HWND Owner, HSPFILEQ QueueHandle,
+				  PSP_FILE_CALLBACK_A MsgHandler,
+				  PVOID Context)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return FALSE;
+}
+
+/***********************************************************************
+ *		SetupIterateCabinetA
+ */
+BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved,
+                                 PSP_FILE_CALLBACK_A MsgHandler, PVOID Context)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return 0;
+}
+
+/***********************************************************************
+ *		SetupIterateCabinetW
+ */
+BOOL WINAPI SetupIterateCabinetW(PWSTR CabinetFile, DWORD Reserved,
+                                 PSP_FILE_CALLBACK_W MsgHandler, PVOID Context) 
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return 0;
+}
+
+
+/***********************************************************************
+ *		SetupGetLineTextA
+ */
+BOOL WINAPI SetupGetLineTextA (PINFCONTEXT Context, HINF InfHandle,
+                        PCSTR Section, PCSTR Key, LPSTR ReturnBuffer,
+                        DWORD ReturnBufferSize, PDWORD RequiredSize)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return 0;
+}
+
+/***********************************************************************
+ *		SetupGetStringFieldA
+ */
+BOOL WINAPI SetupGetStringFieldA(PINFCONTEXT Context, DWORD FieldIndex, 
+                                 LPSTR ReturnBuffer, DWORD ReturnBufferSize,
+                                 PDWORD RequiredSize)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return 0;
+}
+
+
+/***********************************************************************
+ *		SetupFindNextLine
+ */
+BOOL WINAPI SetupFindNextLine (PINFCONTEXT ContextIn, PINFCONTEXT ContextOut)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return 0;
+}
+
+
+/***********************************************************************
+ *		SetupInitDefaultQueueCallback
+ */
+PVOID WINAPI SetupInitDefaultQueueCallback(HWND OwnerWindow)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return 0;
+}
+
+/***********************************************************************
+ *		SetupInitDefaultQueueCallbackEx
+ */
+PVOID WINAPI SetupInitDefaultQueueCallbackEx(HWND OwnerWindow,
+					     HWND AlternativeProgressWindow,
+					     UINT ProgressMessage,
+					     DWORD res1,
+					     PVOID res2)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return 0;
+}
+
+/***********************************************************************
+ *		SetupCloseInfFile
+ */
+VOID WINAPI SetupCloseInfFile (HINF InfHandle)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+}
+
+
+/***********************************************************************
+ *		SetupDefaultQueueCallbackA
+ */
+UINT WINAPI SetupDefaultQueueCallbackA (PVOID Context, UINT Notification,
+                                        UINT Param1, UINT Param2)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return 0;
+}
+
+
+/***********************************************************************
+ *		SetupFindFirstLineA
+ */
+BOOL WINAPI SetupFindFirstLineA (HINF InfHandle, PCSTR Section, PCSTR Key,
+                                 PINFCONTEXT Context)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return 0;
+}
+
+/***********************************************************************
+ *		SetupGetLineByIndexA
+ */
+BOOL WINAPI SetupGetLineByIndexA (HINF InfHandle, PCSTR Section, DWORD Index,
+                                 PINFCONTEXT Context)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return FALSE;
+}
+
+
+/***********************************************************************
+ *		SetupInstallFromInfSectionA
+ */
+BOOL WINAPI SetupInstallFromInfSectionA (HWND Owner, HINF InfHandle, PCSTR SectionName,
+                                         UINT Flags, HKEY RelativeKeyRoot, PCSTR SourceRootPath,
+                                         UINT CopyFlags, PSP_FILE_CALLBACK_A MsgHandler,
+                                         PVOID Context, HDEVINFO DeviceInfoSet,
+                                         PSP_DEVINFO_DATA DeviceInfoData)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return 0;
+}
+
+/***********************************************************************
+ *		SetupOpenAppendInfFileA
+ */
+BOOL WINAPI SetupOpenAppendInfFileA (PCSTR FileName, HINF InfHandle,
+				    PUINT ErrorLine)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return FALSE;
+}
+
+/***********************************************************************
+ *		SetupOpenFileQueue
+ */
+HSPFILEQ WINAPI SetupOpenFileQueue (VOID)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return (HSPFILEQ) INVALID_HANDLE_VALUE;
+}
+
+/***********************************************************************
+ *		SetupOpenInfFileA
+ */
+HINF WINAPI SetupOpenInfFileA (PCSTR FileName, PCSTR InfClass, DWORD InfStyle,
+                               PUINT ErrorLine)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return 0;
+}
+
+/***********************************************************************
+ *		SetupQueueCopyA
+ */
+BOOL WINAPI SetupQueueCopyA (HSPFILEQ QueueHandle, PCSTR SourceRootPath, PCSTR SourcePath,
+			     PCSTR SourceFileName, PCSTR SourceDescription, PCSTR SourceTagFile,
+			     PCSTR TargetDirectory, PCSTR TargetFileName, DWORD CopyStyle)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return FALSE;
+}
+
+/***********************************************************************
+ *		SetupSetDirectoryIdA
+ */
+BOOL WINAPI SetupSetDirectoryIdA (HINF InfHandle,
+				  DWORD Id,
+				  PCSTR Directory)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+	return FALSE;
+}
+
+
+/***********************************************************************
+ *		SetupTermDefaultQueueCallback
+ */
+VOID WINAPI SetupTermDefaultQueueCallback (PVOID Callback)
+{
+	FIXME("not implemented (setupapi.dll) \n");
+}
+
