Implemented a large number of the 32-bit setupapi functions.
Fixed a number of setupx functions by making them call the setupapi
equivalents.
diff --git a/dlls/setupapi/Makefile.in b/dlls/setupapi/Makefile.in
index 1473193..262fd42 100644
--- a/dlls/setupapi/Makefile.in
+++ b/dlls/setupapi/Makefile.in
@@ -5,13 +5,18 @@
VPATH = @srcdir@
MODULE = setupapi.dll
ALTNAMES = setupx.dll
+EXTRALIBS = $(LIBUNICODE)
LDDLLFLAGS = @LDDLLFLAGS@
SYMBOLFILE = $(MODULE).tmp.o
C_SRCS = \
devinst.c \
+ dirid.c \
infparse.c \
+ install.c \
+ parser.c \
+ queue.c \
setupx_main.c \
stubs.c \
virtcopy.c
diff --git a/dlls/setupapi/dirid.c b/dlls/setupapi/dirid.c
new file mode 100644
index 0000000..44c98bc
--- /dev/null
+++ b/dlls/setupapi/dirid.c
@@ -0,0 +1,243 @@
+/*
+ * Directory id handling
+ *
+ * Copyright 2002 Alexandre Julliard for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "windef.h"
+#include "winbase.h"
+#include "ntddk.h"
+#include "winerror.h"
+#include "setupapi.h"
+#include "wine/unicode.h"
+#include "setupapi_private.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
+
+#define MAX_SYSTEM_DIRID DIRID_PRINTPROCESSOR
+
+struct user_dirid
+{
+ int id;
+ WCHAR *str;
+};
+
+static int nb_user_dirids; /* number of user dirids in use */
+static int alloc_user_dirids; /* number of allocated user dirids */
+static struct user_dirid *user_dirids;
+static const WCHAR *system_dirids[MAX_SYSTEM_DIRID+1];
+
+/* retrieve the string for unknown dirids */
+static const WCHAR *get_unknown_dirid(void)
+{
+ static WCHAR *unknown_dirid;
+ static const WCHAR unknown_str[] = {'\\','u','n','k','n','o','w','n',0};
+
+ if (!unknown_dirid)
+ {
+ UINT len = GetSystemDirectoryW( NULL, 0 ) + strlenW(unknown_str);
+ if (!(unknown_dirid = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL;
+ GetSystemDirectoryW( unknown_dirid, len );
+ strcatW( unknown_dirid, unknown_str );
+ }
+ return unknown_dirid;
+}
+
+/* create the string for a system dirid */
+static const WCHAR *create_system_dirid( int dirid )
+{
+ static const WCHAR Null[] = {0};
+ static const WCHAR C_Root[] = {'C',':','\\',0};
+ static const WCHAR Drivers[] = {'\\','d','r','i','v','e','r','s',0};
+ static const WCHAR Inf[] = {'\\','i','n','f',0};
+ static const WCHAR Help[] = {'\\','h','e','l','p',0};
+ static const WCHAR Fonts[] = {'\\','f','o','n','t','s',0};
+ static const WCHAR Viewers[] = {'\\','v','i','e','w','e','r','s',0};
+ static const WCHAR System[] = {'\\','s','y','s','t','e','m',0};
+ static const WCHAR Spool[] = {'\\','s','p','o','o','l',0};
+
+ WCHAR buffer[MAX_PATH+16], *str;
+ int len;
+
+ switch(dirid)
+ {
+ case DIRID_NULL:
+ return Null;
+ case DIRID_WINDOWS:
+ GetWindowsDirectoryW( buffer, MAX_PATH );
+ break;
+ case DIRID_SYSTEM:
+ GetSystemDirectoryW( buffer, MAX_PATH );
+ break;
+ case DIRID_DRIVERS:
+ GetSystemDirectoryW( buffer, MAX_PATH );
+ strcatW( buffer, Drivers );
+ break;
+ case DIRID_INF:
+ GetWindowsDirectoryW( buffer, MAX_PATH );
+ strcatW( buffer, Inf );
+ break;
+ case DIRID_HELP:
+ GetWindowsDirectoryW( buffer, MAX_PATH );
+ strcatW( buffer, Help );
+ break;
+ case DIRID_FONTS:
+ GetWindowsDirectoryW( buffer, MAX_PATH );
+ strcatW( buffer, Fonts );
+ break;
+ case DIRID_VIEWERS:
+ GetSystemDirectoryW( buffer, MAX_PATH );
+ strcatW( buffer, Viewers );
+ break;
+ case DIRID_APPS:
+ return C_Root; /* FIXME */
+ case DIRID_SHARED:
+ GetWindowsDirectoryW( buffer, MAX_PATH );
+ break;
+ case DIRID_BOOT:
+ return C_Root; /* FIXME */
+ case DIRID_SYSTEM16:
+ GetWindowsDirectoryW( buffer, MAX_PATH );
+ strcatW( buffer, System );
+ break;
+ case DIRID_SPOOL:
+ case DIRID_SPOOLDRIVERS: /* FIXME */
+ GetWindowsDirectoryW( buffer, MAX_PATH );
+ strcatW( buffer, Spool );
+ break;
+ case DIRID_LOADER:
+ return C_Root; /* FIXME */
+ case DIRID_USERPROFILE: /* FIXME */
+ case DIRID_COLOR: /* FIXME */
+ case DIRID_PRINTPROCESSOR: /* FIXME */
+ default:
+ FIXME( "unknwon dirid %d\n", dirid );
+ return get_unknown_dirid();
+ }
+ len = (strlenW(buffer) + 1) * sizeof(WCHAR);
+ if ((str = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( str, buffer, len );
+ return str;
+}
+
+/* retrieve the string corresponding to a dirid, or NULL if none */
+const WCHAR *DIRID_get_string( HINF hinf, int dirid )
+{
+ int i;
+
+ if (dirid == DIRID_ABSOLUTE || dirid == DIRID_ABSOLUTE_16BIT) dirid = DIRID_NULL;
+
+ if (dirid >= DIRID_USER)
+ {
+ for (i = 0; i < nb_user_dirids; i++)
+ if (user_dirids[i].id == dirid) return user_dirids[i].str;
+ ERR("user id %d not found\n", dirid );
+ return NULL;
+ }
+ else
+ {
+ if (dirid > MAX_SYSTEM_DIRID) return get_unknown_dirid();
+ if (dirid == DIRID_SRCPATH) return PARSER_get_src_root( hinf );
+ if (!system_dirids[dirid]) system_dirids[dirid] = create_system_dirid( dirid );
+ return system_dirids[dirid];
+ }
+}
+
+/* store a user dirid string */
+static BOOL store_user_dirid( HINF hinf, int id, WCHAR *str )
+{
+ int i;
+
+ for (i = 0; i < nb_user_dirids; i++) if (user_dirids[i].id == id) break;
+
+ if (i < nb_user_dirids) HeapFree( GetProcessHeap(), 0, user_dirids[i].str );
+ else
+ {
+ if (nb_user_dirids >= alloc_user_dirids)
+ {
+ int new_size = max( 32, alloc_user_dirids * 2 );
+ struct user_dirid *new = HeapReAlloc( GetProcessHeap(), 0, user_dirids,
+ new_size * sizeof(*new) );
+ if (!new) return FALSE;
+ user_dirids = new;
+ alloc_user_dirids = new_size;
+ }
+ nb_user_dirids++;
+ }
+ user_dirids[i].id = id;
+ user_dirids[i].str = str;
+ TRACE("id %d -> %s\n", id, debugstr_w(str) );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupSetDirectoryIdW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupSetDirectoryIdA( HINF hinf, DWORD id, PCSTR dir )
+{
+ UNICODE_STRING dirW;
+ int i;
+
+ if (!id) /* clear everything */
+ {
+ for (i = 0; i < nb_user_dirids; i++) HeapFree( GetProcessHeap(), 0, user_dirids[i].str );
+ nb_user_dirids = 0;
+ return TRUE;
+ }
+ if (id < DIRID_USER)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return FALSE;
+ }
+
+ /* duplicate the string */
+ if (!RtlCreateUnicodeStringFromAsciiz( &dirW, dir ))
+ {
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ return FALSE;
+ }
+ return store_user_dirid( hinf, id, dirW.Buffer );
+}
+
+
+/***********************************************************************
+ * SetupSetDirectoryIdW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupSetDirectoryIdW( HINF hinf, DWORD id, PCWSTR dir )
+{
+ int i, len;
+ WCHAR *str;
+
+ if (!id) /* clear everything */
+ {
+ for (i = 0; i < nb_user_dirids; i++) HeapFree( GetProcessHeap(), 0, user_dirids[i].str );
+ nb_user_dirids = 0;
+ return TRUE;
+ }
+ if (id < DIRID_USER)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return FALSE;
+ }
+
+ /* duplicate the string */
+ len = (strlenW(dir)+1) * sizeof(WCHAR);
+ if (!(str = HeapAlloc( GetProcessHeap(), 0, len ))) return FALSE;
+ memcpy( str, dir, len );
+ return store_user_dirid( hinf, id, str );
+}
diff --git a/dlls/setupapi/infparse.c b/dlls/setupapi/infparse.c
index 79abff4..e203265 100644
--- a/dlls/setupapi/infparse.c
+++ b/dlls/setupapi/infparse.c
@@ -26,46 +26,175 @@
*/
#include <string.h>
-#include "wine/debug.h"
#include "windef.h"
#include "winbase.h"
+#include "ntddk.h"
#include "wine/winbase16.h"
+#include "setupapi.h"
#include "setupx16.h"
#include "setupapi_private.h"
+#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
+#define MAX_HANDLES 16384
+#define FIRST_HANDLE 32
+
+static HINF handles[MAX_HANDLES];
+
+
+static RETERR16 alloc_hinf16( HINF hinf, HINF16 *hinf16 )
+{
+ int i;
+ for (i = 0; i < MAX_HANDLES; i++)
+ {
+ if (!handles[i])
+ {
+ handles[i] = hinf;
+ *hinf16 = i + FIRST_HANDLE;
+ return OK;
+ }
+ }
+ return ERR_IP_OUT_OF_HANDLES;
+}
+
+static HINF get_hinf( HINF16 hinf16 )
+{
+ int idx = hinf16 - FIRST_HANDLE;
+ if (idx < 0 || idx >= MAX_HANDLES) return 0;
+ return handles[idx];
+}
+
+
+static HINF free_hinf16( HINF16 hinf16 )
+{
+ HINF ret;
+ int idx = hinf16 - FIRST_HANDLE;
+
+ if (idx < 0 || idx >= MAX_HANDLES) return 0;
+ ret = handles[idx];
+ handles[idx] = 0;
+ return ret;
+}
+
+/* convert last error code to a RETERR16 value */
+static RETERR16 get_last_error(void)
+{
+ switch(GetLastError())
+ {
+ case ERROR_EXPECTED_SECTION_NAME:
+ case ERROR_BAD_SECTION_NAME_LINE:
+ case ERROR_SECTION_NAME_TOO_LONG: return ERR_IP_INVALID_SECT_NAME;
+ case ERROR_SECTION_NOT_FOUND: return ERR_IP_SECT_NOT_FOUND;
+ case ERROR_LINE_NOT_FOUND: return ERR_IP_LINE_NOT_FOUND;
+ default: return IP_ERROR; /* FIXME */
+ }
+}
+
+
+/***********************************************************************
+ * IpOpen (SETUPX.2)
+ *
+ */
+RETERR16 WINAPI IpOpen16( LPCSTR filename, HINF16 *hinf16 )
+{
+ HINF hinf = SetupOpenInfFileA( filename, NULL, INF_STYLE_WIN4, NULL );
+ if (hinf == (HINF)INVALID_HANDLE_VALUE) return get_last_error();
+ return alloc_hinf16( hinf, hinf16 );
+}
+
+
+/***********************************************************************
+ * IpClose (SETUPX.4)
+ */
+RETERR16 WINAPI IpClose16( HINF16 hinf16 )
+{
+ HINF hinf = free_hinf16( hinf16 );
+ if (!hinf) return ERR_IP_INVALID_HINF;
+ SetupCloseInfFile( hinf );
+ return OK;
+}
+
+
+/***********************************************************************
+ * IpGetProfileString (SETUPX.210)
+ */
+RETERR16 WINAPI IpGetProfileString16( HINF16 hinf16, LPCSTR section, LPCSTR entry,
+ LPSTR buffer, WORD buflen )
+{
+ DWORD required_size;
+ HINF hinf = get_hinf( hinf16 );
+
+ if (!hinf) return ERR_IP_INVALID_HINF;
+ if (!SetupGetLineTextA( NULL, hinf, section, entry, buffer, buflen, &required_size ))
+ return get_last_error();
+ TRACE("%p: section %s entry %s ret %s\n",
+ hinf, debugstr_a(section), debugstr_a(entry), debugstr_a(buffer) );
+ return OK;
+}
+
+
+/***********************************************************************
+ * GenFormStrWithoutPlaceHolders (SETUPX.103)
+ *
+ * ought to be pretty much implemented, I guess...
+ */
+void WINAPI GenFormStrWithoutPlaceHolders16( LPSTR dst, LPCSTR src, HINF16 hinf16 )
+{
+ UNICODE_STRING srcW;
+ HINF hinf = get_hinf( hinf16 );
+
+ if (!hinf) return;
+
+ if (!RtlCreateUnicodeStringFromAsciiz( &srcW, src )) return;
+ PARSER_string_substA( hinf, srcW.Buffer, dst, MAX_INF_STRING_LENGTH );
+ RtlFreeUnicodeString( &srcW );
+ TRACE( "%s -> %s\n", debugstr_a(src), debugstr_a(dst) );
+}
+
+/***********************************************************************
+ * GenInstall (SETUPX.101)
+ *
+ * generic installer 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 hinf16, LPCSTR section, WORD genflags )
+{
+ UINT flags = 0;
+ HINF hinf = get_hinf( hinf16 );
+ RETERR16 ret = OK;
+ void *context;
+
+ if (!hinf) return ERR_IP_INVALID_HINF;
+
+ if (genflags & GENINSTALL_DO_FILES) flags |= SPINST_FILES;
+ if (genflags & GENINSTALL_DO_INI) flags |= SPINST_INIFILES;
+ if (genflags & GENINSTALL_DO_REG) flags |= SPINST_REGISTRY;
+ if (genflags & GENINSTALL_DO_INI2REG) flags |= SPINST_INI2REG;
+ if (genflags & GENINSTALL_DO_LOGCONFIG) flags |= SPINST_LOGCONFIG;
+ if (genflags & (GENINSTALL_DO_REGSRCPATH|GENINSTALL_DO_CFGAUTO|GENINSTALL_DO_PERUSER))
+ FIXME( "unsupported flags %x\n", genflags );
+
+ context = SetupInitDefaultQueueCallback( 0 );
+ if (!SetupInstallFromInfSectionA( 0, hinf, section, flags, 0, NULL, 0,
+ SetupDefaultQueueCallbackA, context, 0, 0 ))
+ ret = get_last_error();
+
+ SetupTermDefaultQueueCallback( context );
+ return ret;
+}
+
+
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)
{
@@ -91,49 +220,4 @@
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;
-}
-
-/***********************************************************************
- * IpOpen (SETUPX.2)
- *
- */
-RETERR16 WINAPI IpOpen16(LPCSTR lpInfFileName, HINF16 *lphInf)
-{
- TRACE("('%s', %p)\n", lpInfFileName, lphInf);
- return IP_OpenInf(lpInfFileName, lphInf);
-}
-
-/***********************************************************************
- * IpClose (SETUPX.4)
- */
-RETERR16 WINAPI IpClose16(HINF16 hInf)
-{
- return IP_CloseInf(hInf);
-}
-
-/***********************************************************************
- * IpGetProfileString (SETUPX.210)
- */
-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;
-}
diff --git a/dlls/setupapi/install.c b/dlls/setupapi/install.c
new file mode 100644
index 0000000..9390d04
--- /dev/null
+++ b/dlls/setupapi/install.c
@@ -0,0 +1,623 @@
+/*
+ * Setupapi install routines
+ *
+ * Copyright 2002 Alexandre Julliard for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "windef.h"
+#include "winbase.h"
+#include "ntddk.h"
+#include "winerror.h"
+#include "setupapi.h"
+#include "wine/unicode.h"
+#include "setupapi_private.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
+
+/* info passed to callback functions dealing with files */
+struct files_callback_info
+{
+ HSPFILEQ queue;
+ PCWSTR src_root;
+ UINT copy_flags;
+ HINF layout;
+};
+
+/* info passed to callback functions dealing with the registry */
+struct registry_callback_info
+{
+ HKEY default_root;
+ BOOL delete;
+};
+
+typedef BOOL (*iterate_fields_func)( HINF hinf, PCWSTR field, void *arg );
+
+/* Unicode constants */
+static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0};
+static const WCHAR DelFiles[] = {'D','e','l','F','i','l','e','s',0};
+static const WCHAR RenFiles[] = {'R','e','n','F','i','l','e','s',0};
+static const WCHAR Ini2Reg[] = {'I','n','i','2','R','e','g',0};
+static const WCHAR LogConf[] = {'L','o','g','C','o','n','f',0};
+static const WCHAR AddReg[] = {'A','d','d','R','e','g',0};
+static const WCHAR DelReg[] = {'D','e','l','R','e','g',0};
+static const WCHAR UpdateInis[] = {'U','p','d','a','t','e','I','n','i','s',0};
+static const WCHAR UpdateIniFields[] = {'U','p','d','a','t','e','I','n','i','F','i','e','l','d','s',0};
+
+
+/***********************************************************************
+ * get_field_string
+ *
+ * Retrieve the contents of a field, dynamically growing the buffer if necessary.
+ */
+static WCHAR *get_field_string( INFCONTEXT *context, DWORD index, WCHAR *buffer,
+ WCHAR *static_buffer, DWORD *size )
+{
+ DWORD required;
+
+ if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer;
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ {
+ /* now grow the buffer */
+ if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
+ if (!(buffer = HeapAlloc( GetProcessHeap(), 0, required*sizeof(WCHAR) ))) return NULL;
+ *size = required;
+ if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer;
+ }
+ if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
+ return NULL;
+}
+
+
+/***********************************************************************
+ * copy_files_callback
+ *
+ * Called once for each CopyFiles entry in a given section.
+ */
+static BOOL copy_files_callback( HINF hinf, PCWSTR field, void *arg )
+{
+ struct files_callback_info *info = arg;
+
+ if (field[0] == '@') /* special case: copy single file */
+ SetupQueueDefaultCopyW( info->queue, info->layout, info->src_root, NULL, field, info->copy_flags );
+ else
+ SetupQueueCopySectionW( info->queue, info->src_root, info->layout, hinf, field, info->copy_flags );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * delete_files_callback
+ *
+ * Called once for each DelFiles entry in a given section.
+ */
+static BOOL delete_files_callback( HINF hinf, PCWSTR field, void *arg )
+{
+ struct files_callback_info *info = arg;
+ SetupQueueDeleteSectionW( info->queue, hinf, 0, field );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * rename_files_callback
+ *
+ * Called once for each RenFiles entry in a given section.
+ */
+static BOOL rename_files_callback( HINF hinf, PCWSTR field, void *arg )
+{
+ struct files_callback_info *info = arg;
+ SetupQueueRenameSectionW( info->queue, hinf, 0, field );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * get_root_key
+ *
+ * Retrieve the registry root key from its name.
+ */
+static HKEY get_root_key( const WCHAR *name, HKEY def_root )
+{
+ static const WCHAR HKCR[] = {'H','K','C','R',0};
+ static const WCHAR HKCU[] = {'H','K','C','U',0};
+ static const WCHAR HKLM[] = {'H','K','L','M',0};
+ static const WCHAR HKU[] = {'H','K','U',0};
+ static const WCHAR HKR[] = {'H','K','R',0};
+
+ if (!strcmpiW( name, HKCR )) return HKEY_CLASSES_ROOT;
+ if (!strcmpiW( name, HKCU )) return HKEY_CURRENT_USER;
+ if (!strcmpiW( name, HKLM )) return HKEY_LOCAL_MACHINE;
+ if (!strcmpiW( name, HKU )) return HKEY_USERS;
+ if (!strcmpiW( name, HKR )) return def_root;
+ return 0;
+}
+
+
+/***********************************************************************
+ * append_multi_sz_value
+ *
+ * Append a multisz string to a multisz registry value.
+ */
+static void append_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *strings,
+ DWORD str_size )
+{
+ DWORD size, type, total;
+ WCHAR *buffer, *p;
+
+ if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
+ if (type != REG_MULTI_SZ) return;
+
+ if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size + str_size) * sizeof(WCHAR) ))) return;
+ if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
+
+ /* compare each string against all the existing ones */
+ total = size;
+ while (*strings)
+ {
+ int len = strlenW(strings) + 1;
+
+ for (p = buffer; *p; p += strlenW(p) + 1)
+ if (!strcmpiW( p, strings )) break;
+
+ if (!*p) /* not found, need to append it */
+ {
+ memcpy( p, strings, len * sizeof(WCHAR) );
+ p[len] = 0;
+ total += len;
+ }
+ strings += len;
+ }
+ if (total != size)
+ {
+ TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) );
+ RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total );
+ }
+ done:
+ HeapFree( GetProcessHeap(), 0, buffer );
+}
+
+
+/***********************************************************************
+ * delete_multi_sz_value
+ *
+ * Remove a string from a multisz registry value.
+ */
+static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string )
+{
+ DWORD size, type;
+ WCHAR *buffer, *src, *dst;
+
+ if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
+ if (type != REG_MULTI_SZ) return;
+ /* allocate double the size, one for value before and one for after */
+ if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return;
+ if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
+ src = buffer;
+ dst = buffer + size;
+ while (*src)
+ {
+ int len = strlenW(src) + 1;
+ if (strcmpiW( src, string ))
+ {
+ memcpy( dst, src, len * sizeof(WCHAR) );
+ dst += len;
+ }
+ src += len;
+ }
+ *dst++ = 0;
+ if (dst != buffer + 2*size) /* did we remove something? */
+ {
+ TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) );
+ RegSetValueExW( hkey, value, 0, REG_MULTI_SZ,
+ (BYTE *)(buffer + size), dst - (buffer + size) );
+ }
+ done:
+ HeapFree( GetProcessHeap(), 0, buffer );
+}
+
+
+/***********************************************************************
+ * do_reg_operation
+ *
+ * Perform an add/delete registry operation depending on the flags.
+ */
+static BOOL do_reg_operation( HKEY hkey, const WCHAR *value, INFCONTEXT *context, INT flags )
+{
+ DWORD type, size;
+
+ if (flags & (FLG_ADDREG_DELREG_BIT | FLG_ADDREG_DELVAL)) /* deletion */
+ {
+ if (*value && !(flags & FLG_DELREG_KEYONLY_COMMON))
+ {
+ if ((flags & FLG_DELREG_MULTI_SZ_DELSTRING) == FLG_DELREG_MULTI_SZ_DELSTRING)
+ {
+ WCHAR *str;
+
+ if (!SetupGetStringFieldW( context, 5, NULL, 0, &size ) || !size) return TRUE;
+ if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
+ SetupGetStringFieldW( context, 5, str, size, NULL );
+ delete_multi_sz_value( hkey, value, str );
+ HeapFree( GetProcessHeap(), 0, str );
+ }
+ else RegDeleteValueW( hkey, value );
+ }
+ else RegDeleteKeyW( hkey, NULL );
+ return TRUE;
+ }
+
+ if (flags & (FLG_ADDREG_KEYONLY|FLG_ADDREG_KEYONLY_COMMON)) return TRUE;
+
+ if (flags & (FLG_ADDREG_NOCLOBBER|FLG_ADDREG_OVERWRITEONLY))
+ {
+ BOOL exists = !RegQueryValueExW( hkey, value, NULL, NULL, NULL, NULL );
+ if (exists && (flags & FLG_ADDREG_NOCLOBBER)) return TRUE;
+ if (!exists & (flags & FLG_ADDREG_OVERWRITEONLY)) return TRUE;
+ }
+
+ switch(flags & FLG_ADDREG_TYPE_MASK)
+ {
+ case FLG_ADDREG_TYPE_SZ: type = REG_SZ; break;
+ case FLG_ADDREG_TYPE_MULTI_SZ: type = REG_MULTI_SZ; break;
+ case FLG_ADDREG_TYPE_EXPAND_SZ: type = REG_EXPAND_SZ; break;
+ case FLG_ADDREG_TYPE_BINARY: type = REG_BINARY; break;
+ case FLG_ADDREG_TYPE_DWORD: type = REG_DWORD; break;
+ case FLG_ADDREG_TYPE_NONE: type = REG_NONE; break;
+ default: type = flags >> 16; break;
+ }
+
+ if (!(flags & FLG_ADDREG_BINVALUETYPE) ||
+ (type == REG_DWORD && SetupGetFieldCount(context) == 5))
+ {
+ static const WCHAR empty;
+ WCHAR *str = NULL;
+
+ if (type == REG_MULTI_SZ)
+ {
+ if (!SetupGetMultiSzFieldW( context, 5, NULL, 0, &size )) size = 0;
+ if (size)
+ {
+ if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
+ SetupGetMultiSzFieldW( context, 5, str, size, NULL );
+ }
+ if (flags & FLG_ADDREG_APPEND)
+ {
+ if (!str) return TRUE;
+ append_multi_sz_value( hkey, value, str, size );
+ HeapFree( GetProcessHeap(), 0, str );
+ return TRUE;
+ }
+ /* else fall through to normal string handling */
+ }
+ else
+ {
+ if (!SetupGetStringFieldW( context, 5, NULL, 0, &size )) size = 0;
+ if (size)
+ {
+ if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
+ SetupGetStringFieldW( context, 5, str, size, NULL );
+ }
+ }
+
+ if (type == REG_DWORD)
+ {
+ DWORD dw = str ? wcstol( str, NULL, 16 ) : 0;
+ TRACE( "setting dword %s to %lx\n", debugstr_w(value), dw );
+ RegSetValueExW( hkey, value, 0, type, (BYTE *)&dw, sizeof(dw) );
+ }
+ else
+ {
+ TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(str) );
+ if (str) RegSetValueExW( hkey, value, 0, type, (BYTE *)str, size * sizeof(WCHAR) );
+ else RegSetValueExW( hkey, value, 0, type, (BYTE *)&empty, sizeof(WCHAR) );
+ }
+ HeapFree( GetProcessHeap(), 0, str );
+ return TRUE;
+ }
+ else /* get the binary data */
+ {
+ BYTE *data = NULL;
+
+ if (!SetupGetBinaryField( context, 5, NULL, 0, &size )) size = 0;
+ if (size)
+ {
+ if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
+ TRACE( "setting binary data %s len %ld\n", debugstr_w(value), size );
+ SetupGetBinaryField( context, 5, data, size, NULL );
+ }
+ RegSetValueExW( hkey, value, 0, type, data, size );
+ HeapFree( GetProcessHeap(), 0, data );
+ return TRUE;
+ }
+}
+
+
+/***********************************************************************
+ * registry_callback
+ *
+ * Called once for each AddReg and DelReg entry in a given section.
+ */
+static BOOL registry_callback( HINF hinf, PCWSTR field, void *arg )
+{
+ struct registry_callback_info *info = arg;
+ INFCONTEXT context;
+ HKEY root_key, hkey;
+
+ BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
+
+ for (; ok; ok = SetupFindNextLine( &context, &context ))
+ {
+ WCHAR buffer[MAX_INF_STRING_LENGTH];
+ INT flags;
+
+ /* get root */
+ if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
+ continue;
+ if (!(root_key = get_root_key( buffer, info->default_root )))
+ continue;
+
+ /* get key */
+ if (!SetupGetStringFieldW( &context, 2, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
+ *buffer = 0;
+
+ /* get flags */
+ if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
+
+ if (!info->delete)
+ {
+ if (flags & FLG_ADDREG_DELREG_BIT) continue; /* ignore this entry */
+ }
+ else
+ {
+ if (!flags) flags = FLG_ADDREG_DELREG_BIT;
+ else if (!(flags & FLG_ADDREG_DELREG_BIT)) continue; /* ignore this entry */
+ }
+
+ if (info->delete || (flags & FLG_ADDREG_OVERWRITEONLY))
+ {
+ if (RegOpenKeyW( root_key, buffer, &hkey )) continue; /* ignore if it doesn't exist */
+ }
+ else if (RegCreateKeyW( root_key, buffer, &hkey ))
+ {
+ ERR( "could not create key %08x %s\n", root_key, debugstr_w(buffer) );
+ continue;
+ }
+ TRACE( "key %08x %s\n", root_key, debugstr_w(buffer) );
+
+ /* get value name */
+ if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
+ *buffer = 0;
+
+ /* and now do it */
+ if (!do_reg_operation( hkey, buffer, &context, flags ))
+ {
+ RegCloseKey( hkey );
+ return FALSE;
+ }
+ RegCloseKey( hkey );
+ }
+ return TRUE;
+}
+
+
+static BOOL update_ini_callback( HINF hinf, PCWSTR field, void *arg )
+{
+ FIXME( "should update ini %s\n", debugstr_w(field) );
+ return TRUE;
+}
+
+static BOOL update_ini_fields_callback( HINF hinf, PCWSTR field, void *arg )
+{
+ FIXME( "should update ini fields %s\n", debugstr_w(field) );
+ return TRUE;
+}
+
+static BOOL ini2reg_callback( HINF hinf, PCWSTR field, void *arg )
+{
+ FIXME( "should do ini2reg %s\n", debugstr_w(field) );
+ return TRUE;
+}
+
+static BOOL logconf_callback( HINF hinf, PCWSTR field, void *arg )
+{
+ FIXME( "should do logconf %s\n", debugstr_w(field) );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * iterate_section_fields
+ *
+ * Iterate over all fields of a certain key of a certain section
+ */
+static BOOL iterate_section_fields( HINF hinf, PCWSTR section, PCWSTR key,
+ iterate_fields_func callback, void *arg )
+{
+ WCHAR static_buffer[200];
+ WCHAR *buffer = static_buffer;
+ DWORD size = sizeof(static_buffer)/sizeof(WCHAR);
+ INFCONTEXT context;
+ BOOL ret = FALSE;
+
+ BOOL ok = SetupFindFirstLineW( hinf, section, key, &context );
+ while (ok)
+ {
+ UINT i, count = SetupGetFieldCount( &context );
+ for (i = 1; i <= count; i++)
+ {
+ if (!(buffer = get_field_string( &context, i, buffer, static_buffer, &size )))
+ goto done;
+ if (!callback( hinf, buffer, arg ))
+ {
+ ERR("callback failed for %s %s\n", debugstr_w(section), debugstr_w(buffer) );
+ goto done;
+ }
+ }
+ ok = SetupFindNextMatchLineW( &context, key, &context );
+ }
+ ret = TRUE;
+ done:
+ if (buffer && buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupInstallFilesFromInfSectionA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupInstallFilesFromInfSectionA( HINF hinf, HINF hlayout, HSPFILEQ queue,
+ PCSTR section, PCSTR src_root, UINT flags )
+{
+ UNICODE_STRING sectionW;
+ BOOL ret = FALSE;
+
+ if (!RtlCreateUnicodeStringFromAsciiz( §ionW, section ))
+ {
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ return FALSE;
+ }
+ if (!src_root)
+ ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
+ NULL, flags );
+ else
+ {
+ UNICODE_STRING srcW;
+ if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
+ {
+ ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
+ srcW.Buffer, flags );
+ RtlFreeUnicodeString( &srcW );
+ }
+ else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ }
+ RtlFreeUnicodeString( §ionW );
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupInstallFilesFromInfSectionW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupInstallFilesFromInfSectionW( HINF hinf, HINF hlayout, HSPFILEQ queue,
+ PCWSTR section, PCWSTR src_root, UINT flags )
+{
+ struct files_callback_info info;
+
+ info.queue = queue;
+ info.src_root = src_root;
+ info.copy_flags = flags;
+ info.layout = hlayout;
+ return iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info );
+}
+
+
+/***********************************************************************
+ * SetupInstallFromInfSectionA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupInstallFromInfSectionA( HWND owner, HINF hinf, PCSTR section, UINT flags,
+ HKEY key_root, PCSTR src_root, UINT copy_flags,
+ PSP_FILE_CALLBACK_A callback, PVOID context,
+ HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
+{
+ UNICODE_STRING sectionW, src_rootW;
+ struct callback_WtoA_context ctx;
+ BOOL ret = FALSE;
+
+ src_rootW.Buffer = NULL;
+ if (src_root && !RtlCreateUnicodeStringFromAsciiz( &src_rootW, src_root ))
+ {
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ return FALSE;
+ }
+
+ if (RtlCreateUnicodeStringFromAsciiz( §ionW, section ))
+ {
+ ctx.orig_context = context;
+ ctx.orig_handler = callback;
+ ret = SetupInstallFromInfSectionW( owner, hinf, sectionW.Buffer, flags, key_root,
+ src_rootW.Buffer, copy_flags, QUEUE_callback_WtoA,
+ &ctx, devinfo, devinfo_data );
+ RtlFreeUnicodeString( §ionW );
+ }
+ else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+
+ RtlFreeUnicodeString( &src_rootW );
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupInstallFromInfSectionW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupInstallFromInfSectionW( HWND owner, HINF hinf, PCWSTR section, UINT flags,
+ HKEY key_root, PCWSTR src_root, UINT copy_flags,
+ PSP_FILE_CALLBACK_W callback, PVOID context,
+ HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
+{
+ if (flags & SPINST_FILES)
+ {
+ struct files_callback_info info;
+ HSPFILEQ queue;
+ BOOL ret;
+
+ if (!(queue = SetupOpenFileQueue())) return FALSE;
+ info.queue = queue;
+ info.src_root = src_root;
+ info.copy_flags = copy_flags;
+ info.layout = hinf;
+ ret = (iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info ) &&
+ iterate_section_fields( hinf, section, DelFiles, delete_files_callback, &info ) &&
+ iterate_section_fields( hinf, section, RenFiles, rename_files_callback, &info ) &&
+ SetupCommitFileQueueW( owner, queue, callback, context ));
+ SetupCloseFileQueue( queue );
+ if (!ret) return FALSE;
+ }
+ if (flags & SPINST_INIFILES)
+ {
+ if (!iterate_section_fields( hinf, section, UpdateInis, update_ini_callback, NULL ) ||
+ !iterate_section_fields( hinf, section, UpdateIniFields,
+ update_ini_fields_callback, NULL ))
+ return FALSE;
+ }
+ if (flags & SPINST_INI2REG)
+ {
+ if (!iterate_section_fields( hinf, section, Ini2Reg, ini2reg_callback, NULL ))
+ return FALSE;
+ }
+
+ if (flags & SPINST_LOGCONFIG)
+ {
+ if (!iterate_section_fields( hinf, section, LogConf, logconf_callback, NULL ))
+ return FALSE;
+ }
+
+ if (flags & SPINST_REGISTRY)
+ {
+ struct registry_callback_info info;
+
+ info.default_root = key_root;
+ info.delete = FALSE;
+ if (!iterate_section_fields( hinf, section, AddReg, registry_callback, &info ))
+ return FALSE;
+ info.delete = TRUE;
+ if (!iterate_section_fields( hinf, section, DelReg, registry_callback, &info ))
+ return FALSE;
+ }
+ if (flags & (SPINST_BITREG|SPINST_REGSVR|SPINST_UNREGSVR|SPINST_PROFILEITEMS|SPINST_COPYINF))
+ FIXME( "unsupported flags %x\n", flags );
+ return TRUE;
+}
diff --git a/dlls/setupapi/parser.c b/dlls/setupapi/parser.c
new file mode 100644
index 0000000..68c10f5
--- /dev/null
+++ b/dlls/setupapi/parser.c
@@ -0,0 +1,1766 @@
+/*
+ * INF file parsing
+ *
+ * Copyright 2002 Alexandre Julliard for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "windef.h"
+#include "ntddk.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/unicode.h"
+#include "setupapi.h"
+#include "setupx16.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
+
+#define CONTROL_Z '\x1a'
+#define MAX_SECTION_NAME_LEN 255
+#define MAX_FIELD_LEN 511 /* larger fields get silently truncated */
+/* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */
+#define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1)
+
+/* inf file structure definitions */
+
+struct field
+{
+ const WCHAR *text; /* field text */
+};
+
+struct line
+{
+ int first_field; /* index of first field in field array */
+ int nb_fields; /* number of fields in line */
+ int key_field; /* index of field for key or -1 if no key */
+};
+
+struct section
+{
+ const WCHAR *name; /* section name */
+ unsigned int nb_lines; /* number of used lines */
+ unsigned int alloc_lines; /* total number of allocated lines in array below */
+ struct line lines[16]; /* lines information (grown dynamically, 16 is initial size) */
+};
+
+struct inf_file
+{
+ struct inf_file *next; /* next appended file */
+ WCHAR *strings; /* buffer for string data (section names and field values) */
+ WCHAR *string_pos; /* position of next available string in buffer */
+ unsigned int nb_sections; /* number of used sections */
+ unsigned int alloc_sections; /* total number of allocated section pointers */
+ struct section **sections; /* section pointers array */
+ unsigned int nb_fields;
+ unsigned int alloc_fields;
+ struct field *fields;
+ int strings_section; /* index of [Strings] section or -1 if none */
+ WCHAR *src_root; /* source root directory */
+};
+
+/* parser definitions */
+
+enum parser_state
+{
+ LINE_START, /* at beginning of a line */
+ SECTION_NAME, /* parsing a section name */
+ KEY_NAME, /* parsing a key name */
+ VALUE_NAME, /* parsing a value name */
+ EOL_BACKSLASH, /* backslash at end of line */
+ QUOTES, /* inside quotes */
+ LEADING_SPACES, /* leading spaces */
+ TRAILING_SPACES, /* trailing spaces */
+ COMMENT, /* inside a comment */
+ NB_PARSER_STATES
+};
+
+struct parser
+{
+ const WCHAR *start; /* start position of item being parsed */
+ const WCHAR *end; /* end of buffer */
+ struct inf_file *file; /* file being built */
+ enum parser_state state; /* current parser state */
+ enum parser_state stack[4]; /* state stack */
+ int stack_pos; /* current pos in stack */
+
+ int cur_section; /* index of section being parsed*/
+ struct line *line; /* current line */
+ unsigned int line_pos; /* current line position in file */
+ unsigned int error; /* error code */
+ unsigned int token_len; /* current token len */
+ WCHAR token[MAX_FIELD_LEN+1]; /* current token */
+};
+
+typedef const WCHAR * (*parser_state_func)( struct parser *parser, const WCHAR *pos );
+
+/* parser state machine functions */
+static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos );
+
+static const parser_state_func parser_funcs[NB_PARSER_STATES] =
+{
+ line_start_state, /* LINE_START */
+ section_name_state, /* SECTION_NAME */
+ key_name_state, /* KEY_NAME */
+ value_name_state, /* VALUE_NAME */
+ eol_backslash_state, /* EOL_BACKSLASH */
+ quotes_state, /* QUOTES */
+ leading_spaces_state, /* LEADING_SPACES */
+ trailing_spaces_state, /* TRAILING_SPACES */
+ comment_state /* COMMENT */
+};
+
+
+/* Unicode string constants */
+static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
+static const WCHAR Signature[] = {'S','i','g','n','a','t','u','r','e',0};
+static const WCHAR Chicago[] = {'$','C','h','i','c','a','g','o','$',0};
+static const WCHAR WindowsNT[] = {'$','W','i','n','d','o','w','s',' ','N','T','$',0};
+static const WCHAR Windows95[] = {'$','W','i','n','d','o','w','s',' ','9','5','$',0};
+static const WCHAR LayoutFile[] = {'L','a','y','o','u','t','F','i','l','e',0};
+
+/* extend an array, allocating more memory if necessary */
+static void *grow_array( void *array, unsigned int *count, size_t elem )
+{
+ void *new_array;
+ unsigned int new_count = *count + *count / 2;
+ if (new_count < 32) new_count = 32;
+ if ((new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, array, new_count * elem )))
+ *count = new_count;
+ else
+ HeapFree( GetProcessHeap(), 0, array );
+ return new_array;
+}
+
+
+/* find a section by name */
+static int find_section( struct inf_file *file, const WCHAR *name )
+{
+ int i;
+
+ for (i = 0; i < file->nb_sections; i++)
+ if (!strcmpiW( name, file->sections[i]->name )) return i;
+ return -1;
+}
+
+
+/* find a line by name */
+static struct line *find_line( struct inf_file *file, int section_index, const WCHAR *name )
+{
+ struct section *section;
+ struct line *line;
+ int i;
+
+ if (section_index < 0 || section_index >= file->nb_sections) return NULL;
+ section = file->sections[section_index];
+ for (i = 0, line = section->lines; i < section->nb_lines; i++, line++)
+ {
+ if (line->key_field == -1) continue;
+ if (!strcmpiW( name, file->fields[line->key_field].text )) return line;
+ }
+ return NULL;
+}
+
+
+/* add a section to the file and return the section index */
+static int add_section( struct inf_file *file, const WCHAR *name )
+{
+ struct section *section;
+
+ if (file->nb_sections >= file->alloc_sections)
+ {
+ if (!(file->sections = grow_array( file->sections, &file->alloc_sections,
+ sizeof(file->sections[0]) ))) return -1;
+ }
+ if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) ))) return -1;
+ section->name = name;
+ section->nb_lines = 0;
+ section->alloc_lines = sizeof(section->lines)/sizeof(section->lines[0]);
+ file->sections[file->nb_sections] = section;
+ return file->nb_sections++;
+}
+
+
+/* add a line to a given section */
+static struct line *add_line( struct inf_file *file, int section_index )
+{
+ struct section *section;
+ struct line *line;
+
+ assert( section_index >= 0 && section_index < file->nb_sections );
+
+ section = file->sections[section_index];
+ if (section->nb_lines == section->alloc_lines) /* need to grow the section */
+ {
+ int size = sizeof(*section) - sizeof(section->lines) + 2*section->alloc_lines*sizeof(*line);
+ if (!(section = HeapReAlloc( GetProcessHeap(), 0, section, size ))) return NULL;
+ section->alloc_lines *= 2;
+ file->sections[section_index] = section;
+ }
+ line = §ion->lines[section->nb_lines++];
+ line->first_field = file->nb_fields;
+ line->nb_fields = 0;
+ line->key_field = -1;
+ return line;
+}
+
+
+/* retrieve a given line from section/line index */
+inline static struct line *get_line( struct inf_file *file, unsigned int section_index,
+ unsigned int line_index )
+{
+ struct section *section;
+
+ if (section_index >= file->nb_sections) return NULL;
+ section = file->sections[section_index];
+ if (line_index >= section->nb_lines) return NULL;
+ return §ion->lines[line_index];
+}
+
+
+/* retrieve a given field from section/line/field index */
+static struct field *get_field( struct inf_file *file, int section_index, int line_index,
+ int field_index )
+{
+ struct line *line = get_line( file, section_index, line_index );
+
+ if (!line) return NULL;
+ if (!field_index) /* get the key */
+ {
+ if (line->key_field == -1) return NULL;
+ return &file->fields[line->key_field];
+ }
+ field_index--;
+ if (field_index >= line->nb_fields) return NULL;
+ return &file->fields[line->first_field + field_index];
+}
+
+
+/* allocate a new field, growing the array if necessary */
+static struct field *add_field( struct inf_file *file, const WCHAR *text )
+{
+ struct field *field;
+
+ if (file->nb_fields >= file->alloc_fields)
+ {
+ if (!(file->fields = grow_array( file->fields, &file->alloc_fields,
+ sizeof(file->fields[0]) ))) return NULL;
+ }
+ field = &file->fields[file->nb_fields++];
+ field->text = text;
+ return field;
+}
+
+
+/* retrieve the string substitution for a directory id */
+static const WCHAR *get_dirid_subst( int dirid, unsigned int *len )
+{
+ extern const WCHAR *DIRID_get_string( HINF hinf, int dirid );
+ const WCHAR *ret = DIRID_get_string( 0, dirid );
+ if (ret) *len = strlenW(ret);
+ return ret;
+}
+
+
+/* retrieve the string substitution for a given string, or NULL if not found */
+/* if found, len is set to the substitution length */
+static const WCHAR *get_string_subst( struct inf_file *file, const WCHAR *str, unsigned int *len )
+{
+ static const WCHAR percent = '%';
+
+ struct section *strings_section;
+ struct line *line;
+ struct field *field;
+ int i, dirid;
+ WCHAR *dirid_str, *end;
+ const WCHAR *ret = NULL;
+
+ if (!*len) /* empty string (%%) is replaced by single percent */
+ {
+ *len = 1;
+ return &percent;
+ }
+ if (file->strings_section == -1) goto not_found;
+ strings_section = file->sections[file->strings_section];
+ for (i = 0, line = strings_section->lines; i < strings_section->nb_lines; i++, line++)
+ {
+ if (line->key_field == -1) continue;
+ if (strncmpiW( str, file->fields[line->key_field].text, *len )) continue;
+ if (!file->fields[line->key_field].text[*len]) break;
+ }
+ if (i == strings_section->nb_lines || !line->nb_fields) goto not_found;
+ field = &file->fields[line->first_field];
+ *len = strlenW( field->text );
+ return field->text;
+
+ not_found: /* check for integer id */
+ if ((dirid_str = HeapAlloc( GetProcessHeap(), 0, (*len+1) * sizeof(WCHAR) )))
+ {
+ memcpy( dirid_str, str, *len * sizeof(WCHAR) );
+ dirid_str[*len] = 0;
+ dirid = wcstol( dirid_str, &end, 10 );
+ if (!*end) ret = get_dirid_subst( dirid, len );
+ HeapFree( GetProcessHeap(), 0, dirid_str );
+ return ret;
+ }
+ return NULL;
+}
+
+
+/* do string substitutions on the specified text */
+/* the buffer is assumed to be large enough */
+/* returns necessary length not including terminating null */
+unsigned int PARSER_string_substW( struct inf_file *file, const WCHAR *text, WCHAR *buffer,
+ unsigned int size )
+{
+ const WCHAR *start, *subst, *p;
+ unsigned int len, total = 0;
+ int inside = 0;
+
+ if (!buffer) size = MAX_STRING_LEN + 1;
+ for (p = start = text; *p; p++)
+ {
+ if (*p != '%') continue;
+ inside = !inside;
+ if (inside) /* start of a %xx% string */
+ {
+ len = p - start;
+ if (len > size - 1) len = size - 1;
+ if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) );
+ total += len;
+ size -= len;
+ start = p;
+ }
+ else /* end of the %xx% string, find substitution */
+ {
+ len = p - start - 1;
+ subst = get_string_subst( file, start + 1, &len );
+ if (!subst)
+ {
+ subst = start;
+ len = p - start + 1;
+ }
+ if (len > size - 1) len = size - 1;
+ if (buffer) memcpy( buffer + total, subst, len * sizeof(WCHAR) );
+ total += len;
+ size -= len;
+ start = p + 1;
+ }
+ }
+
+ if (start != p) /* unfinished string, copy it */
+ {
+ len = p - start;
+ if (len > size - 1) len = size - 1;
+ if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) );
+ total += len;
+ }
+ if (buffer && size) buffer[total] = 0;
+ return total;
+}
+
+
+/* do string substitutions on the specified text */
+/* the buffer is assumed to be large enough */
+/* returns necessary length not including terminating null */
+unsigned int PARSER_string_substA( struct inf_file *file, const WCHAR *text, char *buffer,
+ unsigned int size )
+{
+ WCHAR buffW[MAX_STRING_LEN+1];
+ DWORD ret;
+
+ unsigned int len = PARSER_string_substW( file, text, buffW, sizeof(buffW)/sizeof(WCHAR) );
+ if (!buffer) RtlUnicodeToMultiByteSize( &ret, buffW, len * sizeof(WCHAR) );
+ else
+ {
+ RtlUnicodeToMultiByteN( buffer, size-1, &ret, buffW, len * sizeof(WCHAR) );
+ buffer[ret] = 0;
+ }
+ return ret;
+}
+
+
+/* push some string data into the strings buffer */
+static WCHAR *push_string( struct inf_file *file, const WCHAR *string )
+{
+ WCHAR *ret = file->string_pos;
+ strcpyW( ret, string );
+ file->string_pos += strlenW( ret ) + 1;
+ return ret;
+}
+
+
+/* push the current state on the parser stack */
+inline static void push_state( struct parser *parser, enum parser_state state )
+{
+ assert( parser->stack_pos < sizeof(parser->stack)/sizeof(parser->stack[0]) );
+ parser->stack[parser->stack_pos++] = state;
+}
+
+
+/* pop the current state */
+inline static void pop_state( struct parser *parser )
+{
+ assert( parser->stack_pos );
+ parser->state = parser->stack[--parser->stack_pos];
+}
+
+
+/* set the parser state and return the previous one */
+inline static enum parser_state set_state( struct parser *parser, enum parser_state state )
+{
+ enum parser_state ret = parser->state;
+ parser->state = state;
+ return ret;
+}
+
+
+/* check if the pointer points to an end of file */
+inline static int is_eof( struct parser *parser, const WCHAR *ptr )
+{
+ return (ptr >= parser->end || *ptr == CONTROL_Z);
+}
+
+
+/* check if the pointer points to an end of line */
+inline static int is_eol( struct parser *parser, const WCHAR *ptr )
+{
+ return (ptr >= parser->end || *ptr == CONTROL_Z || *ptr == '\n');
+}
+
+
+/* push data from current token start up to pos into the current token */
+static int push_token( struct parser *parser, const WCHAR *pos )
+{
+ int len = pos - parser->start;
+ const WCHAR *src = parser->start;
+ WCHAR *dst = parser->token + parser->token_len;
+
+ if (len > MAX_FIELD_LEN - parser->token_len) len = MAX_FIELD_LEN - parser->token_len;
+
+ parser->token_len += len;
+ for ( ; len > 0; len--, dst++, src++) *dst = *src ? *src : ' ';
+ *dst = 0;
+ parser->start = pos;
+ return 0;
+}
+
+
+/* add a section with the current token as name */
+static int add_section_from_token( struct parser *parser )
+{
+ int section_index;
+
+ if (parser->token_len > MAX_SECTION_NAME_LEN)
+ {
+ parser->error = ERROR_SECTION_NAME_TOO_LONG;
+ return -1;
+ }
+ if ((section_index = find_section( parser->file, parser->token )) == -1)
+ {
+ /* need to create a new one */
+ const WCHAR *name = push_string( parser->file, parser->token );
+ if ((section_index = add_section( parser->file, name )) == -1)
+ {
+ parser->error = ERROR_NOT_ENOUGH_MEMORY;
+ return -1;
+ }
+ }
+ parser->token_len = 0;
+ parser->cur_section = section_index;
+ return section_index;
+}
+
+
+/* add a field containing the current token to the current line */
+static struct field *add_field_from_token( struct parser *parser, int is_key )
+{
+ struct field *field;
+ WCHAR *text;
+
+ if (!parser->line) /* need to start a new line */
+ {
+ if (parser->cur_section == -1) /* got a line before the first section */
+ {
+ parser->error = ERROR_WRONG_INF_STYLE;
+ return NULL;
+ }
+ if (!(parser->line = add_line( parser->file, parser->cur_section ))) goto error;
+ }
+ else assert(!is_key);
+
+ text = push_string( parser->file, parser->token );
+ if ((field = add_field( parser->file, text )))
+ {
+ if (!is_key) parser->line->nb_fields++;
+ else
+ {
+ /* replace first field by key field */
+ parser->line->key_field = parser->line->first_field;
+ parser->line->first_field++;
+ }
+ parser->token_len = 0;
+ return field;
+ }
+ error:
+ parser->error = ERROR_NOT_ENOUGH_MEMORY;
+ return NULL;
+}
+
+
+/* handler for parser LINE_START state */
+static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos )
+{
+ const WCHAR *p;
+
+ for (p = pos; !is_eof( parser, p ); p++)
+ {
+ switch(*p)
+ {
+ case '\n':
+ parser->line_pos++;
+ parser->line = NULL; /* start a new line */
+ break;
+ case ';':
+ push_state( parser, LINE_START );
+ set_state( parser, COMMENT );
+ return p + 1;
+ case '[':
+ parser->start = p + 1;
+ set_state( parser, SECTION_NAME );
+ return p + 1;
+ default:
+ if (!isspaceW(*p))
+ {
+ parser->start = p;
+ set_state( parser, KEY_NAME );
+ return p;
+ }
+ break;
+ }
+ }
+ return NULL;
+}
+
+
+/* handler for parser SECTION_NAME state */
+static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos )
+{
+ const WCHAR *p;
+
+ for (p = pos; !is_eol( parser, p ); p++)
+ {
+ if (*p == ']')
+ {
+ push_token( parser, p );
+ if (add_section_from_token( parser ) == -1) return NULL;
+ push_state( parser, LINE_START );
+ set_state( parser, COMMENT ); /* ignore everything else on the line */
+ return p + 1;
+ }
+ }
+ parser->error = ERROR_BAD_SECTION_NAME_LINE; /* unfinished section name */
+ return NULL;
+}
+
+
+/* handler for parser KEY_NAME state */
+static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos )
+{
+ const WCHAR *p, *token_end = parser->start;
+
+ for (p = pos; !is_eol( parser, p ); p++)
+ {
+ if (*p == ',') break;
+ switch(*p)
+ {
+
+ case '=':
+ push_token( parser, token_end );
+ if (!add_field_from_token( parser, 1 )) return NULL;
+ parser->start = p + 1;
+ push_state( parser, VALUE_NAME );
+ set_state( parser, LEADING_SPACES );
+ return p + 1;
+ case ';':
+ push_token( parser, token_end );
+ if (!add_field_from_token( parser, 0 )) return NULL;
+ push_state( parser, LINE_START );
+ set_state( parser, COMMENT );
+ return p + 1;
+ case '"':
+ push_token( parser, token_end );
+ parser->start = p + 1;
+ push_state( parser, KEY_NAME );
+ set_state( parser, QUOTES );
+ return p + 1;
+ case '\\':
+ push_token( parser, token_end );
+ parser->start = p;
+ push_state( parser, KEY_NAME );
+ set_state( parser, EOL_BACKSLASH );
+ return p;
+ default:
+ if (!isspaceW(*p)) token_end = p + 1;
+ else
+ {
+ push_token( parser, p );
+ push_state( parser, KEY_NAME );
+ set_state( parser, TRAILING_SPACES );
+ return p;
+ }
+ break;
+ }
+ }
+ push_token( parser, token_end );
+ set_state( parser, VALUE_NAME );
+ return p;
+}
+
+
+/* handler for parser VALUE_NAME state */
+static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos )
+{
+ const WCHAR *p, *token_end = parser->start;
+
+ for (p = pos; !is_eol( parser, p ); p++)
+ {
+ switch(*p)
+ {
+ case ';':
+ push_token( parser, token_end );
+ if (!add_field_from_token( parser, 0 )) return NULL;
+ push_state( parser, LINE_START );
+ set_state( parser, COMMENT );
+ return p + 1;
+ case ',':
+ push_token( parser, token_end );
+ if (!add_field_from_token( parser, 0 )) return NULL;
+ parser->start = p + 1;
+ push_state( parser, VALUE_NAME );
+ set_state( parser, LEADING_SPACES );
+ return p + 1;
+ case '"':
+ push_token( parser, token_end );
+ parser->start = p + 1;
+ push_state( parser, VALUE_NAME );
+ set_state( parser, QUOTES );
+ return p + 1;
+ case '\\':
+ push_token( parser, token_end );
+ parser->start = p;
+ push_state( parser, VALUE_NAME );
+ set_state( parser, EOL_BACKSLASH );
+ return p;
+ default:
+ if (!isspaceW(*p)) token_end = p + 1;
+ else
+ {
+ push_token( parser, p );
+ push_state( parser, VALUE_NAME );
+ set_state( parser, TRAILING_SPACES );
+ return p;
+ }
+ break;
+ }
+ }
+ push_token( parser, token_end );
+ if (!add_field_from_token( parser, 0 )) return NULL;
+ set_state( parser, LINE_START );
+ return p;
+}
+
+
+/* handler for parser EOL_BACKSLASH state */
+static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos )
+{
+ const WCHAR *p;
+
+ for (p = pos; !is_eof( parser, p ); p++)
+ {
+ switch(*p)
+ {
+ case '\n':
+ parser->line_pos++;
+ parser->start = p + 1;
+ set_state( parser, LEADING_SPACES );
+ return p + 1;
+ case '\\':
+ continue;
+ case ';':
+ push_state( parser, EOL_BACKSLASH );
+ set_state( parser, COMMENT );
+ return p + 1;
+ default:
+ if (isspaceW(*p)) continue;
+ push_token( parser, p );
+ pop_state( parser );
+ return p;
+ }
+ }
+ parser->start = p;
+ pop_state( parser );
+ return p;
+}
+
+
+/* handler for parser QUOTES state */
+static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos )
+{
+ const WCHAR *p, *token_end = parser->start;
+
+ for (p = pos; !is_eol( parser, p ); p++)
+ {
+ if (*p == '"')
+ {
+ if (p+1 < parser->end && p[1] == '"') /* double quotes */
+ {
+ push_token( parser, p + 1 );
+ parser->start = token_end = p + 2;
+ p++;
+ }
+ else /* end of quotes */
+ {
+ push_token( parser, p );
+ parser->start = p + 1;
+ pop_state( parser );
+ return p + 1;
+ }
+ }
+ }
+ push_token( parser, p );
+ pop_state( parser );
+ return p;
+}
+
+
+/* handler for parser LEADING_SPACES state */
+static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos )
+{
+ const WCHAR *p;
+
+ for (p = pos; !is_eol( parser, p ); p++)
+ {
+ if (*p == '\\')
+ {
+ parser->start = p;
+ set_state( parser, EOL_BACKSLASH );
+ return p;
+ }
+ if (!isspaceW(*p)) break;
+ }
+ parser->start = p;
+ pop_state( parser );
+ return p;
+}
+
+
+/* handler for parser TRAILING_SPACES state */
+static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos )
+{
+ const WCHAR *p;
+
+ for (p = pos; !is_eol( parser, p ); p++)
+ {
+ if (*p == '\\')
+ {
+ set_state( parser, EOL_BACKSLASH );
+ return p;
+ }
+ if (!isspaceW(*p)) break;
+ }
+ pop_state( parser );
+ return p;
+}
+
+
+/* handler for parser COMMENT state */
+static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos )
+{
+ const WCHAR *p = pos;
+
+ while (!is_eol( parser, p )) p++;
+ pop_state( parser );
+ return p;
+}
+
+
+/* parse a complete buffer */
+static DWORD parse_buffer( struct inf_file *file, const WCHAR *buffer, const WCHAR *end,
+ UINT *error_line )
+{
+ static const WCHAR Strings[] = {'S','t','r','i','n','g','s',0};
+
+ struct parser parser;
+ const WCHAR *pos = buffer;
+
+ parser.start = buffer;
+ parser.end = end;
+ parser.file = file;
+ parser.line = NULL;
+ parser.state = LINE_START;
+ parser.stack_pos = 0;
+ parser.cur_section = -1;
+ parser.line_pos = 1;
+ parser.error = 0;
+ parser.token_len = 0;
+
+ /* parser main loop */
+ while (pos) pos = (parser_funcs[parser.state])( &parser, pos );
+
+ /* trim excess buffer space */
+ if (file->alloc_sections > file->nb_sections)
+ {
+ file->sections = HeapReAlloc( GetProcessHeap(), 0, file->sections,
+ file->nb_sections * sizeof(file->sections[0]) );
+ file->alloc_sections = file->nb_sections;
+ }
+ if (file->alloc_fields > file->nb_fields)
+ {
+ file->fields = HeapReAlloc( GetProcessHeap(), 0, file->fields,
+ file->nb_fields * sizeof(file->fields[0]) );
+ file->alloc_fields = file->nb_fields;
+ }
+ file->strings = HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, file->strings,
+ (file->string_pos - file->strings) * sizeof(WCHAR) );
+
+ if (parser.error)
+ {
+ if (error_line) *error_line = parser.line_pos;
+ return parser.error;
+ }
+
+ /* find the [strings] section */
+ file->strings_section = find_section( file, Strings );
+ return 0;
+}
+
+
+/* append a child INF file to its parent list, in a thread-safe manner */
+static void append_inf_file( struct inf_file *parent, struct inf_file *child )
+{
+ struct inf_file **ppnext = &parent->next;
+ child->next = NULL;
+
+ for (;;)
+ {
+ struct inf_file *next = InterlockedCompareExchangePointer( (void **)ppnext, child, NULL );
+ if (!next) return;
+ ppnext = &next->next;
+ }
+}
+
+
+/***********************************************************************
+ * parse_file
+ *
+ * parse an INF file.
+ */
+static struct inf_file *parse_file( HANDLE handle, const WCHAR *class, UINT *error_line )
+{
+ void *buffer;
+ DWORD err = 0;
+ struct inf_file *file;
+
+ DWORD size = GetFileSize( handle, NULL );
+ HANDLE mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, size, NULL );
+ if (!mapping) return NULL;
+ buffer = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, size );
+ NtClose( mapping );
+ if (!buffer) return NULL;
+
+ if (class) FIXME( "class %s not supported yet\n", debugstr_w(class) );
+
+ if (!(file = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*file) )))
+ {
+ err = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ /* we won't need more strings space than the size of the file,
+ * so we can preallocate it here
+ */
+ if (!(file->strings = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) )))
+ {
+ err = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+ file->string_pos = file->strings;
+ file->strings_section = -1;
+
+ if (!RtlIsTextUnicode( buffer, size, NULL ))
+ {
+ WCHAR *new_buff = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) );
+ if (new_buff)
+ {
+ DWORD len = MultiByteToWideChar( CP_ACP, 0, buffer, size, new_buff,
+ size * sizeof(WCHAR) );
+ err = parse_buffer( file, new_buff, new_buff + len, error_line );
+ HeapFree( GetProcessHeap(), 0, new_buff );
+ }
+ }
+ else err = parse_buffer( file, buffer, (WCHAR *)((char *)buffer + size), error_line );
+
+ if (!err) /* now check signature */
+ {
+ int version_index = find_section( file, Version );
+ if (version_index != -1)
+ {
+ struct line *line = find_line( file, version_index, Signature );
+ if (line && line->nb_fields > 0)
+ {
+ struct field *field = file->fields + line->first_field;
+ if (!strcmpiW( field->text, Chicago )) goto done;
+ if (!strcmpiW( field->text, WindowsNT )) goto done;
+ if (!strcmpiW( field->text, Windows95 )) goto done;
+ }
+ }
+ err = ERROR_WRONG_INF_STYLE;
+ }
+
+ done:
+ UnmapViewOfFile( buffer );
+ if (err)
+ {
+ HeapFree( GetProcessHeap(), 0, file );
+ SetLastError( err );
+ file = NULL;
+ }
+ return file;
+}
+
+
+/***********************************************************************
+ * PARSER_get_src_root
+ *
+ * Retrieve the source directory of an inf file.
+ */
+const WCHAR *PARSER_get_src_root( HINF hinf )
+{
+ struct inf_file *file = hinf;
+ return file->src_root;
+}
+
+
+/***********************************************************************
+ * SetupOpenInfFileA (SETUPAPI.@)
+ */
+HINF WINAPI SetupOpenInfFileA( PCSTR name, PCSTR class, DWORD style, UINT *error )
+{
+ UNICODE_STRING nameW, classW;
+ HINF ret = (HINF)INVALID_HANDLE_VALUE;
+
+ classW.Buffer = NULL;
+ if (class && !RtlCreateUnicodeStringFromAsciiz( &classW, class ))
+ {
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ return ret;
+ }
+ if (RtlCreateUnicodeStringFromAsciiz( &nameW, name ))
+ {
+ ret = SetupOpenInfFileW( nameW.Buffer, classW.Buffer, style, error );
+ RtlFreeUnicodeString( &nameW );
+ }
+ RtlFreeUnicodeString( &classW );
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupOpenInfFileW (SETUPAPI.@)
+ */
+HINF WINAPI SetupOpenInfFileW( PCWSTR name, PCWSTR class, DWORD style, UINT *error )
+{
+ struct inf_file *file = NULL;
+ HANDLE handle;
+ WCHAR *path, *p;
+ UINT len;
+
+ if (strchrW( name, '\\' ) || strchrW( name, '/' ))
+ {
+ if (!(len = GetFullPathNameW( name, 0, NULL, NULL ))) return (HINF)INVALID_HANDLE_VALUE;
+ if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
+ {
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ return (HINF)INVALID_HANDLE_VALUE;
+ }
+ GetFullPathNameW( name, len, path, NULL );
+ handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
+ }
+ else /* try Windows directory */
+ {
+ static const WCHAR Inf[] = {'\\','i','n','f','\\',0};
+ static const WCHAR System32[] = {'\\','s','y','s','t','e','m','3','2','\\',0};
+
+ len = GetWindowsDirectoryW( NULL, 0 ) + strlenW(name) + 12;
+ if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
+ {
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ return (HINF)INVALID_HANDLE_VALUE;
+ }
+ GetWindowsDirectoryW( path, len );
+ p = path + strlenW(path);
+ strcpyW( p, Inf );
+ strcatW( p, name );
+ handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ strcpyW( p, System32 );
+ strcatW( p, name );
+ handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
+ }
+ }
+
+ if (handle != INVALID_HANDLE_VALUE)
+ {
+ file = parse_file( handle, class, error );
+ CloseHandle( handle );
+ }
+ if (!file)
+ {
+ HeapFree( GetProcessHeap(), 0, path );
+ return (HINF)INVALID_HANDLE_VALUE;
+ }
+ TRACE( "%s -> %p\n", debugstr_w(path), file );
+ file->src_root = path;
+ if ((p = strrchrW( path, '\\' ))) p[1] = 0; /* remove file name */
+ SetLastError( 0 );
+ return (HINF)file;
+}
+
+
+/***********************************************************************
+ * SetupOpenAppendInfFileA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupOpenAppendInfFileA( PCSTR name, HINF parent_hinf, UINT *error )
+{
+ HINF child_hinf;
+
+ if (!name) return SetupOpenAppendInfFileW( NULL, parent_hinf, error );
+ child_hinf = SetupOpenInfFileA( name, NULL, INF_STYLE_WIN4, error );
+ if (child_hinf == (HINF)INVALID_HANDLE_VALUE) return FALSE;
+ append_inf_file( parent_hinf, child_hinf );
+ TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_a(name), child_hinf );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupOpenAppendInfFileW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupOpenAppendInfFileW( PCWSTR name, HINF parent_hinf, UINT *error )
+{
+ HINF child_hinf;
+
+ if (!name)
+ {
+ INFCONTEXT context;
+ WCHAR filename[MAX_PATH];
+ int idx = 1;
+
+ if (!SetupFindFirstLineW( parent_hinf, Version, LayoutFile, &context )) return FALSE;
+ while (SetupGetStringFieldW( &context, idx++, filename,
+ sizeof(filename)/sizeof(WCHAR), NULL ))
+ {
+ child_hinf = SetupOpenInfFileW( filename, NULL, INF_STYLE_WIN4, error );
+ if (child_hinf == (HINF)INVALID_HANDLE_VALUE) return FALSE;
+ append_inf_file( parent_hinf, child_hinf );
+ TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_w(filename), child_hinf );
+ }
+ return TRUE;
+ }
+ child_hinf = SetupOpenInfFileW( name, NULL, INF_STYLE_WIN4, error );
+ if (child_hinf == (HINF)INVALID_HANDLE_VALUE) return FALSE;
+ append_inf_file( parent_hinf, child_hinf );
+ TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_w(name), child_hinf );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupCloseInfFile (SETUPAPI.@)
+ */
+void WINAPI SetupCloseInfFile( HINF hinf )
+{
+ struct inf_file *file = hinf;
+ int i;
+
+ for (i = 0; i < file->nb_sections; i++) HeapFree( GetProcessHeap(), 0, file->sections[i] );
+ HeapFree( GetProcessHeap(), 0, file->src_root );
+ HeapFree( GetProcessHeap(), 0, file->sections );
+ HeapFree( GetProcessHeap(), 0, file->fields );
+ HeapFree( GetProcessHeap(), 0, file->strings );
+ HeapFree( GetProcessHeap(), 0, file );
+}
+
+
+/***********************************************************************
+ * SetupGetLineCountA (SETUPAPI.@)
+ */
+LONG WINAPI SetupGetLineCountA( HINF hinf, PCSTR name )
+{
+ UNICODE_STRING sectionW;
+ LONG ret = -1;
+
+ if (!RtlCreateUnicodeStringFromAsciiz( §ionW, name ))
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ else
+ {
+ ret = SetupGetLineCountW( hinf, sectionW.Buffer );
+ RtlFreeUnicodeString( §ionW );
+ }
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupGetLineCountW (SETUPAPI.@)
+ */
+LONG WINAPI SetupGetLineCountW( HINF hinf, PCWSTR section )
+{
+ struct inf_file *file = hinf;
+ int section_index;
+ LONG ret = -1;
+
+ for (file = hinf; file; file = file->next)
+ {
+ if ((section_index = find_section( file, section )) == -1) continue;
+ if (ret == -1) ret = 0;
+ ret += file->sections[section_index]->nb_lines;
+ }
+ TRACE( "(%p,%s) returning %ld\n", hinf, debugstr_w(section), ret );
+ SetLastError( (ret == -1) ? ERROR_SECTION_NOT_FOUND : 0 );
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupGetLineByIndexA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupGetLineByIndexA( HINF hinf, PCSTR section, DWORD index, INFCONTEXT *context )
+{
+ UNICODE_STRING sectionW;
+ BOOL ret = FALSE;
+
+ if (!RtlCreateUnicodeStringFromAsciiz( §ionW, section ))
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ else
+ {
+ ret = SetupGetLineByIndexW( hinf, sectionW.Buffer, index, context );
+ RtlFreeUnicodeString( §ionW );
+ }
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupGetLineByIndexW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupGetLineByIndexW( HINF hinf, PCWSTR section, DWORD index, INFCONTEXT *context )
+{
+ struct inf_file *file = hinf;
+ int section_index;
+
+ SetLastError( ERROR_SECTION_NOT_FOUND );
+ for (file = hinf; file; file = file->next)
+ {
+ if ((section_index = find_section( file, section )) == -1) continue;
+ SetLastError( ERROR_LINE_NOT_FOUND );
+ if (index < file->sections[section_index]->nb_lines)
+ {
+ context->Inf = hinf;
+ context->CurrentInf = file;
+ context->Section = section_index;
+ context->Line = index;
+ SetLastError( 0 );
+ TRACE( "(%p,%s): returning %d/%ld\n",
+ hinf, debugstr_w(section), section_index, index );
+ return TRUE;
+ }
+ index -= file->sections[section_index]->nb_lines;
+ }
+ TRACE( "(%p,%s) not found\n", hinf, debugstr_w(section) );
+ return FALSE;
+}
+
+
+/***********************************************************************
+ * SetupFindFirstLineA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupFindFirstLineA( HINF hinf, PCSTR section, PCSTR key, INFCONTEXT *context )
+{
+ UNICODE_STRING sectionW, keyW;
+ BOOL ret = FALSE;
+
+ if (!RtlCreateUnicodeStringFromAsciiz( §ionW, section ))
+ {
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ return FALSE;
+ }
+
+ if (!key) ret = SetupFindFirstLineW( hinf, sectionW.Buffer, NULL, context );
+ else
+ {
+ if (RtlCreateUnicodeStringFromAsciiz( &keyW, key ))
+ {
+ ret = SetupFindFirstLineW( hinf, sectionW.Buffer, keyW.Buffer, context );
+ RtlFreeUnicodeString( &keyW );
+ }
+ else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ }
+ RtlFreeUnicodeString( §ionW );
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupFindFirstLineW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupFindFirstLineW( HINF hinf, PCWSTR section, PCWSTR key, INFCONTEXT *context )
+{
+ struct inf_file *file;
+ int section_index;
+
+ SetLastError( ERROR_SECTION_NOT_FOUND );
+ for (file = hinf; file; file = file->next)
+ {
+ if ((section_index = find_section( file, section )) == -1) continue;
+ if (key)
+ {
+ INFCONTEXT ctx;
+ ctx.Inf = hinf;
+ ctx.CurrentInf = file;
+ ctx.Section = section_index;
+ ctx.Line = -1;
+ return SetupFindNextMatchLineW( &ctx, key, context );
+ }
+ SetLastError( ERROR_LINE_NOT_FOUND ); /* found at least one section */
+ if (file->sections[section_index]->nb_lines)
+ {
+ context->Inf = hinf;
+ context->CurrentInf = file;
+ context->Section = section_index;
+ context->Line = 0;
+ SetLastError( 0 );
+ TRACE( "(%p,%s,%s): returning %d/0\n",
+ hinf, debugstr_w(section), debugstr_w(key), section_index );
+ return TRUE;
+ }
+ }
+ TRACE( "(%p,%s,%s): not found\n", hinf, debugstr_w(section), debugstr_w(key) );
+ return FALSE;
+}
+
+
+/***********************************************************************
+ * SetupFindNextLine (SETUPAPI.@)
+ */
+BOOL WINAPI SetupFindNextLine( const INFCONTEXT *context_in, INFCONTEXT *context_out )
+{
+ struct inf_file *file = context_in->CurrentInf;
+ struct section *section;
+
+ if (context_in->Section >= file->nb_sections) goto error;
+
+ section = file->sections[context_in->Section];
+ if (context_in->Line+1 < section->nb_lines)
+ {
+ if (context_out != context_in) *context_out = *context_in;
+ context_out->Line++;
+ SetLastError( 0 );
+ return TRUE;
+ }
+
+ /* now search the appended files */
+
+ for (file = file->next; file; file = file->next)
+ {
+ int section_index = find_section( file, section->name );
+ if (section_index == -1) continue;
+ if (file->sections[section_index]->nb_lines)
+ {
+ context_out->Inf = context_in->Inf;
+ context_out->CurrentInf = file;
+ context_out->Section = section_index;
+ context_out->Line = 0;
+ SetLastError( 0 );
+ return TRUE;
+ }
+ }
+ error:
+ SetLastError( ERROR_LINE_NOT_FOUND );
+ return FALSE;
+}
+
+
+/***********************************************************************
+ * SetupFindNextMatchLineA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupFindNextMatchLineA( const INFCONTEXT *context_in, PCSTR key,
+ INFCONTEXT *context_out )
+{
+ UNICODE_STRING keyW;
+ BOOL ret = FALSE;
+
+ if (!key) return SetupFindNextLine( context_in, context_out );
+
+ if (!RtlCreateUnicodeStringFromAsciiz( &keyW, key ))
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ else
+ {
+ ret = SetupFindNextMatchLineW( context_in, keyW.Buffer, context_out );
+ RtlFreeUnicodeString( &keyW );
+ }
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupFindNextMatchLineW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupFindNextMatchLineW( const INFCONTEXT *context_in, PCWSTR key,
+ INFCONTEXT *context_out )
+{
+ struct inf_file *file = context_in->CurrentInf;
+ struct section *section;
+ struct line *line;
+ unsigned int i;
+
+ if (!key) return SetupFindNextLine( context_in, context_out );
+
+ if (context_in->Section >= file->nb_sections) goto error;
+
+ section = file->sections[context_in->Section];
+
+ for (i = context_in->Line+1, line = §ion->lines[i]; i < section->nb_lines; i++, line++)
+ {
+ if (line->key_field == -1) continue;
+ if (!strcmpiW( key, file->fields[line->key_field].text ))
+ {
+ if (context_out != context_in) *context_out = *context_in;
+ context_out->Line = i;
+ SetLastError( 0 );
+ TRACE( "(%p,%s,%s): returning %d\n",
+ file, debugstr_w(section->name), debugstr_w(key), i );
+ return TRUE;
+ }
+ }
+
+ /* now search the appended files */
+
+ for (file = file->next; file; file = file->next)
+ {
+ int section_index = find_section( file, section->name );
+ if (section_index == -1) continue;
+ section = file->sections[section_index];
+ for (i = 0, line = section->lines; i < section->nb_lines; i++, line++)
+ {
+ if (line->key_field == -1) continue;
+ if (!strcmpiW( key, file->fields[line->key_field].text ))
+ {
+ context_out->Inf = context_in->Inf;
+ context_out->CurrentInf = file;
+ context_out->Section = section_index;
+ context_out->Line = i;
+ SetLastError( 0 );
+ TRACE( "(%p,%s,%s): returning %d/%d\n",
+ file, debugstr_w(section->name), debugstr_w(key), section_index, i );
+ return TRUE;
+ }
+ }
+ }
+ TRACE( "(%p,%s,%s): not found\n",
+ context_in->CurrentInf, debugstr_w(section->name), debugstr_w(key) );
+ error:
+ SetLastError( ERROR_LINE_NOT_FOUND );
+ return FALSE;
+}
+
+
+/***********************************************************************
+ * SetupGetLineTextW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupGetLineTextW( const INFCONTEXT *context, HINF hinf, PCWSTR section_name,
+ PCWSTR key_name, PWSTR buffer, DWORD size, DWORD *required )
+{
+ struct inf_file *file;
+ struct line *line;
+ struct field *field;
+ int i;
+ DWORD total = 0;
+
+ if (!context)
+ {
+ INFCONTEXT new_context;
+ if (!SetupFindFirstLineW( hinf, section_name, key_name, &new_context )) return FALSE;
+ file = new_context.CurrentInf;
+ line = get_line( file, new_context.Section, new_context.Line );
+ }
+ else
+ {
+ file = context->CurrentInf;
+ if (!(line = get_line( file, context->Section, context->Line )))
+ {
+ SetLastError( ERROR_LINE_NOT_FOUND );
+ return FALSE;
+ }
+ }
+
+ for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
+ total += PARSER_string_substW( file, field->text, NULL, 0 ) + 1;
+
+ if (required) *required = total;
+ if (buffer)
+ {
+ if (total > size)
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ return FALSE;
+ }
+ for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
+ {
+ unsigned int len = PARSER_string_substW( file, field->text, buffer, size );
+ if (i+1 < line->nb_fields) buffer[len] = ',';
+ buffer += len + 1;
+ }
+ }
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupGetLineTextA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupGetLineTextA( const INFCONTEXT *context, HINF hinf, PCSTR section_name,
+ PCSTR key_name, PSTR buffer, DWORD size, DWORD *required )
+{
+ struct inf_file *file;
+ struct line *line;
+ struct field *field;
+ int i;
+ DWORD total = 0;
+
+ if (!context)
+ {
+ INFCONTEXT new_context;
+ if (!SetupFindFirstLineA( hinf, section_name, key_name, &new_context )) return FALSE;
+ file = new_context.CurrentInf;
+ line = get_line( file, new_context.Section, new_context.Line );
+ }
+ else
+ {
+ file = context->CurrentInf;
+ if (!(line = get_line( file, context->Section, context->Line )))
+ {
+ SetLastError( ERROR_LINE_NOT_FOUND );
+ return FALSE;
+ }
+ }
+
+ for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
+ total += PARSER_string_substA( file, field->text, NULL, 0 ) + 1;
+
+ if (required) *required = total;
+ if (buffer)
+ {
+ if (total > size)
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ return FALSE;
+ }
+ for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
+ {
+ unsigned int len = PARSER_string_substA( file, field->text, buffer, size );
+ if (i+1 < line->nb_fields) buffer[len] = ',';
+ buffer += len + 1;
+ }
+ }
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupGetFieldCount (SETUPAPI.@)
+ */
+DWORD WINAPI SetupGetFieldCount( const INFCONTEXT *context )
+{
+ struct inf_file *file = context->CurrentInf;
+ struct line *line = get_line( file, context->Section, context->Line );
+
+ if (!line) return 0;
+ return line->nb_fields;
+}
+
+
+/***********************************************************************
+ * SetupGetStringFieldA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupGetStringFieldA( const INFCONTEXT *context, DWORD index, PSTR buffer,
+ DWORD size, DWORD *required )
+{
+ struct inf_file *file = context->CurrentInf;
+ struct field *field = get_field( file, context->Section, context->Line, index );
+ unsigned int len;
+
+ SetLastError(0);
+ if (!field) return FALSE;
+ len = PARSER_string_substA( file, field->text, NULL, 0 );
+ if (required) *required = len + 1;
+ if (buffer)
+ {
+ if (size <= len)
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ return FALSE;
+ }
+ PARSER_string_substA( file, field->text, buffer, size );
+
+ TRACE( "context %p/%p/%d/%d index %ld returning %s\n",
+ context->Inf, context->CurrentInf, context->Section, context->Line,
+ index, debugstr_a(buffer) );
+ }
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupGetStringFieldW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupGetStringFieldW( const INFCONTEXT *context, DWORD index, PWSTR buffer,
+ DWORD size, DWORD *required )
+{
+ struct inf_file *file = context->CurrentInf;
+ struct field *field = get_field( file, context->Section, context->Line, index );
+ unsigned int len;
+
+ SetLastError(0);
+ if (!field) return FALSE;
+ len = PARSER_string_substW( file, field->text, NULL, 0 );
+ if (required) *required = len + 1;
+ if (buffer)
+ {
+ if (size <= len)
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ return FALSE;
+ }
+ PARSER_string_substW( file, field->text, buffer, size );
+
+ TRACE( "context %p/%p/%d/%d index %ld returning %s\n",
+ context->Inf, context->CurrentInf, context->Section, context->Line,
+ index, debugstr_w(buffer) );
+ }
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupGetIntField (SETUPAPI.@)
+ */
+BOOL WINAPI SetupGetIntField( const INFCONTEXT *context, DWORD index, INT *result )
+{
+ char localbuff[20];
+ char *end, *buffer = localbuff;
+ DWORD required;
+ INT res;
+ BOOL ret = FALSE;
+
+ if (!SetupGetStringFieldA( context, index, localbuff, sizeof(localbuff), &required ))
+ {
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
+ if (!(buffer = HeapAlloc( GetProcessHeap(), 0, required ))) return FALSE;
+ if (!SetupGetStringFieldA( context, index, buffer, required, NULL )) goto done;
+ }
+ res = strtol( buffer, &end, 0 );
+ if (end != buffer && !*end)
+ {
+ *result = res;
+ ret = TRUE;
+ }
+ else SetLastError( ERROR_INVALID_DATA );
+
+ done:
+ if (buffer != localbuff) HeapFree( GetProcessHeap(), 0, buffer );
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupGetBinaryField (SETUPAPI.@)
+ */
+BOOL WINAPI SetupGetBinaryField( const INFCONTEXT *context, DWORD index, BYTE *buffer,
+ DWORD size, DWORD *required )
+{
+ struct inf_file *file = context->CurrentInf;
+ struct line *line = get_line( file, context->Section, context->Line );
+ struct field *field;
+ int i;
+
+ if (!line)
+ {
+ SetLastError( ERROR_LINE_NOT_FOUND );
+ return FALSE;
+ }
+ if (!index || index >= line->nb_fields)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return FALSE;
+ }
+ index--; /* fields start at 0 */
+ if (required) *required = line->nb_fields - index;
+ if (!buffer) return TRUE;
+ if (size < line->nb_fields - index)
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ return FALSE;
+ }
+ field = &file->fields[line->first_field + index];
+ for (i = index; i < line->nb_fields; i++, field++)
+ {
+ const WCHAR *p;
+ DWORD value = 0;
+ for (p = field->text; *p && isxdigitW(*p); p++)
+ {
+ if ((value <<= 8) > 255)
+ {
+ SetLastError( ERROR_INVALID_DATA );
+ return FALSE;
+ }
+ if (*p <= '9') value |= (*p - '0');
+ else value |= (tolowerW(*p) - 'a' + 10);
+ }
+ buffer[i - index] = value;
+ }
+ if (TRACE_ON(setupapi))
+ {
+ TRACE( "%p/%p/%d/%d index %ld returning",
+ context->Inf, context->CurrentInf, context->Section, context->Line, index );
+ for (i = index; i < line->nb_fields; i++) DPRINTF( " %02x", buffer[i - index] );
+ DPRINTF( "\n" );
+ }
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupGetMultiSzFieldA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupGetMultiSzFieldA( const INFCONTEXT *context, DWORD index, PSTR buffer,
+ DWORD size, DWORD *required )
+{
+ struct inf_file *file = context->CurrentInf;
+ struct line *line = get_line( file, context->Section, context->Line );
+ struct field *field;
+ unsigned int len;
+ int i;
+ DWORD total = 1;
+
+ if (!line)
+ {
+ SetLastError( ERROR_LINE_NOT_FOUND );
+ return FALSE;
+ }
+ if (!index || index >= line->nb_fields)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return FALSE;
+ }
+ index--; /* fields start at 0 */
+ field = &file->fields[line->first_field + index];
+ for (i = index; i < line->nb_fields; i++, field++)
+ {
+ if (!(len = PARSER_string_substA( file, field->text, NULL, 0 ))) break;
+ total += len + 1;
+ }
+
+ if (required) *required = total;
+ if (!buffer) return TRUE;
+ if (total > size)
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ return FALSE;
+ }
+ field = &file->fields[line->first_field + index];
+ for (i = index; i < line->nb_fields; i++, field++)
+ {
+ if (!(len = PARSER_string_substA( file, field->text, buffer, size ))) break;
+ buffer += len + 1;
+ }
+ *buffer = 0; /* add final null */
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupGetMultiSzFieldW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupGetMultiSzFieldW( const INFCONTEXT *context, DWORD index, PWSTR buffer,
+ DWORD size, DWORD *required )
+{
+ struct inf_file *file = context->CurrentInf;
+ struct line *line = get_line( file, context->Section, context->Line );
+ struct field *field;
+ unsigned int len;
+ int i;
+ DWORD total = 1;
+
+ if (!line)
+ {
+ SetLastError( ERROR_LINE_NOT_FOUND );
+ return FALSE;
+ }
+ if (!index || index >= line->nb_fields)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return FALSE;
+ }
+ index--; /* fields start at 0 */
+ field = &file->fields[line->first_field + index];
+ for (i = index; i < line->nb_fields; i++, field++)
+ {
+ if (!(len = PARSER_string_substW( file, field->text, NULL, 0 ))) break;
+ total += len + 1;
+ }
+
+ if (required) *required = total;
+ if (!buffer) return TRUE;
+ if (total > size)
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ return FALSE;
+ }
+ field = &file->fields[line->first_field + index];
+ for (i = index; i < line->nb_fields; i++, field++)
+ {
+ if (!(len = PARSER_string_substW( file, field->text, buffer, size ))) break;
+ buffer += len + 1;
+ }
+ *buffer = 0; /* add final null */
+ return TRUE;
+}
diff --git a/dlls/setupapi/queue.c b/dlls/setupapi/queue.c
new file mode 100644
index 0000000..59e0617
--- /dev/null
+++ b/dlls/setupapi/queue.c
@@ -0,0 +1,1237 @@
+/*
+ * Setupapi file queue routines
+ *
+ * Copyright 2002 Alexandre Julliard for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "windef.h"
+#include "winbase.h"
+#include "ntddk.h"
+#include "winerror.h"
+#include "setupapi.h"
+#include "wine/unicode.h"
+#include "setupapi_private.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
+
+/* context structure for the default queue callback */
+struct default_callback_context
+{
+ HWND owner;
+ HWND progress;
+ UINT message;
+};
+
+struct file_op
+{
+ struct file_op *next;
+ UINT style;
+ WCHAR *src_root;
+ WCHAR *src_path;
+ WCHAR *src_file;
+ WCHAR *src_descr;
+ WCHAR *src_tag;
+ WCHAR *dst_path;
+ WCHAR *dst_file;
+};
+
+struct file_op_queue
+{
+ struct file_op *head;
+ struct file_op *tail;
+ unsigned int count;
+};
+
+struct file_queue
+{
+ struct file_op_queue copy_queue;
+ struct file_op_queue delete_queue;
+ struct file_op_queue rename_queue;
+ DWORD flags;
+};
+
+
+inline static WCHAR *strdupW( const WCHAR *str )
+{
+ WCHAR *ret = NULL;
+ if (str)
+ {
+ int len = (strlenW(str) + 1) * sizeof(WCHAR);
+ if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( ret, str, len );
+ }
+ return ret;
+}
+
+
+inline static WCHAR *strdupAtoW( const char *str )
+{
+ WCHAR *ret = NULL;
+ if (str)
+ {
+ DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
+ if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
+ MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
+ }
+ return ret;
+}
+
+inline static char *strdupWtoA( const WCHAR *str )
+{
+ char *ret = NULL;
+ if (str)
+ {
+ DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
+ if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
+ WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
+ }
+ return ret;
+}
+
+/* append a file operation to a queue */
+inline static void queue_file_op( struct file_op_queue *queue, struct file_op *op )
+{
+ op->next = NULL;
+ if (queue->tail) queue->tail->next = op;
+ else queue->head = op;
+ queue->tail = op;
+ queue->count++;
+}
+
+/* free all the file operations on a given queue */
+static void free_file_op_queue( struct file_op_queue *queue )
+{
+ struct file_op *op;
+
+ for (op = queue->head; op; op = op->next)
+ {
+ HeapFree( GetProcessHeap(), 0, op->src_root );
+ HeapFree( GetProcessHeap(), 0, op->src_path );
+ HeapFree( GetProcessHeap(), 0, op->src_file );
+ HeapFree( GetProcessHeap(), 0, op->src_descr );
+ HeapFree( GetProcessHeap(), 0, op->src_tag );
+ HeapFree( GetProcessHeap(), 0, op->dst_path );
+ if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
+ }
+}
+
+/* concat 3 strings to make a path, handling separators correctly */
+static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
+{
+ *buffer = 0;
+ if (src1 && *src1)
+ {
+ strcpyW( buffer, src1 );
+ buffer += strlenW(buffer );
+ if (buffer[-1] != '\\') *buffer++ = '\\';
+ if (src2) while (*src2 == '\\') src2++;
+ }
+
+ if (src2)
+ {
+ strcpyW( buffer, src2 );
+ buffer += strlenW(buffer );
+ if (buffer[-1] != '\\') *buffer++ = '\\';
+ if (src3) while (*src3 == '\\') src3++;
+ }
+ if (src3)
+ {
+ strcpyW( buffer, src3 );
+ buffer += strlenW(buffer );
+ }
+}
+
+
+/***********************************************************************
+ * build_filepathsW
+ *
+ * Build a FILEPATHS_W structure for a given file operation.
+ */
+static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
+{
+ int src_len = 1, dst_len = 1;
+ WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
+
+ if (op->src_root) src_len += strlenW(op->src_root) + 1;
+ if (op->src_path) src_len += strlenW(op->src_path) + 1;
+ if (op->src_file) src_len += strlenW(op->src_file) + 1;
+ if (op->dst_path) dst_len += strlenW(op->dst_path) + 1;
+ if (op->dst_file) dst_len += strlenW(op->dst_file) + 1;
+ src_len *= sizeof(WCHAR);
+ dst_len *= sizeof(WCHAR);
+
+ if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
+ {
+ HeapFree( GetProcessHeap(), 0, source );
+ paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
+ }
+ if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
+ {
+ HeapFree( GetProcessHeap(), 0, target );
+ paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
+ }
+ if (!source || !target) return FALSE;
+ concat_W( source, op->src_root, op->src_path, op->src_file );
+ concat_W( target, NULL, op->dst_path, op->dst_file );
+ paths->Win32Error = 0;
+ paths->Flags = 0;
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * QUEUE_callback_WtoA
+ *
+ * Map a file callback parameters from W to A and call the A callback.
+ */
+UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
+ UINT_PTR param1, UINT_PTR param2 )
+{
+ struct callback_WtoA_context *callback_ctx = context;
+ char buffer[MAX_PATH];
+ UINT ret;
+ UINT_PTR old_param2 = param2;
+
+ switch(notification)
+ {
+ case SPFILENOTIFY_COPYERROR:
+ param2 = (UINT_PTR)&buffer;
+ /* fall through */
+ case SPFILENOTIFY_STARTDELETE:
+ case SPFILENOTIFY_ENDDELETE:
+ case SPFILENOTIFY_DELETEERROR:
+ case SPFILENOTIFY_STARTRENAME:
+ case SPFILENOTIFY_ENDRENAME:
+ case SPFILENOTIFY_RENAMEERROR:
+ case SPFILENOTIFY_STARTCOPY:
+ case SPFILENOTIFY_ENDCOPY:
+ {
+ FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
+ FILEPATHS_A pathsA;
+
+ pathsA.Source = strdupWtoA( pathsW->Source );
+ pathsA.Target = strdupWtoA( pathsW->Target );
+ pathsA.Win32Error = pathsW->Win32Error;
+ pathsA.Flags = pathsW->Flags;
+ ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
+ (UINT_PTR)&pathsA, param2 );
+ HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
+ HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
+ }
+ if (notification == SPFILENOTIFY_COPYERROR)
+ MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
+ break;
+
+ case SPFILENOTIFY_NEEDMEDIA:
+ case SPFILENOTIFY_QUEUESCAN:
+ FIXME("mapping for %d not implemented\n",notification);
+ case SPFILENOTIFY_STARTQUEUE:
+ case SPFILENOTIFY_ENDQUEUE:
+ case SPFILENOTIFY_STARTSUBQUEUE:
+ case SPFILENOTIFY_ENDSUBQUEUE:
+ default:
+ ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
+ break;
+ }
+ return ret;
+}
+
+
+/***********************************************************************
+ * get_src_file_info
+ *
+ * Retrieve the source file information for a given file.
+ */
+static void get_src_file_info( HINF hinf, struct file_op *op )
+{
+ static const WCHAR SourceDisksNames[] =
+ {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
+ static const WCHAR SourceDisksFiles[] =
+ {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
+
+ INFCONTEXT file_ctx, disk_ctx;
+ INT id, diskid;
+ DWORD len, len2;
+
+ /* find the SourceDisksFiles entry */
+ if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx ))
+ {
+ const WCHAR *dir;
+
+ if ((op->style & (SP_COPY_SOURCE_ABSOLUTE|SP_COPY_SOURCEPATH_ABSOLUTE))) return;
+ /* no specific info, use .inf file source directory */
+ if (!op->src_root && (dir = DIRID_get_string( hinf, DIRID_SRCPATH )))
+ op->src_root = strdupW( dir );
+ return;
+ }
+ if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
+
+ /* now find the diskid in the SourceDisksNames section */
+ if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return;
+ for (;;)
+ {
+ if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
+ if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
+ }
+
+ /* and fill in the missing info */
+
+ if (!op->src_descr)
+ {
+ if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) &&
+ (op->src_descr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
+ SetupGetStringFieldW( &disk_ctx, 1, op->src_descr, len, NULL );
+ }
+ if (!op->src_tag)
+ {
+ if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) &&
+ (op->src_tag = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
+ SetupGetStringFieldW( &disk_ctx, 2, op->src_tag, len, NULL );
+ }
+ if (!op->src_path && !(op->style & SP_COPY_SOURCE_ABSOLUTE))
+ {
+ if (!(op->style & SP_COPY_SOURCEPATH_ABSOLUTE))
+ {
+ /* retrieve relative path for this disk */
+ if (!SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len )) len = 0;
+ }
+ /* retrieve relative path for this file */
+ if (!SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len2 )) len2 = 0;
+
+ if ((len || len2) &&
+ (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) )))
+ {
+ WCHAR *ptr = op->src_path;
+ if (len)
+ {
+ SetupGetStringFieldW( &disk_ctx, 4, op->src_path, len, NULL );
+ ptr = op->src_path + strlenW(op->src_path);
+ if (len2 && ptr > op->src_path && ptr[-1] != '\\') *ptr++ = '\\';
+ }
+ if (!SetupGetStringFieldW( &disk_ctx, 4, ptr, len2, NULL )) *ptr = 0;
+ }
+ }
+ if (!op->src_root) op->src_root = strdupW( PARSER_get_src_root(hinf) );
+}
+
+
+/***********************************************************************
+ * get_destination_dir
+ *
+ * Retrieve the destination dir for a given section.
+ */
+static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
+{
+ static const WCHAR Dest[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
+ static const WCHAR Def[] = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
+
+ const WCHAR *dir;
+ WCHAR *ptr, *ret;
+ INFCONTEXT context;
+ INT dirid;
+ DWORD len1, len2;
+
+ if (!SetupFindFirstLineW( hinf, Dest, section, &context ) &&
+ !SetupFindFirstLineW( hinf, Dest, Def, &context )) return NULL;
+ if (!SetupGetIntField( &context, 1, &dirid )) return NULL;
+ if (!(dir = DIRID_get_string( hinf, dirid ))) return NULL;
+ len1 = strlenW(dir) + 1;
+ if (!SetupGetStringFieldW( &context, 2, NULL, 0, &len2 )) len2 = 0;
+ if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len1+len2) * sizeof(WCHAR) ))) return NULL;
+ strcpyW( ret, dir );
+ ptr = ret + strlenW(ret);
+ if (len2 && ptr > ret && ptr[-1] != '\\') *ptr++ = '\\';
+ if (!SetupGetStringFieldW( &context, 2, ptr, len2, NULL )) *ptr = 0;
+ return ret;
+}
+
+
+static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
+
+/***********************************************************************
+ * extract_cabinet_file
+ *
+ * Extract a file from a .cab file.
+ */
+static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
+ const WCHAR *src, const WCHAR *dst )
+{
+ static const WCHAR extW[] = {'.','c','a','b',0};
+ static HMODULE advpack;
+
+ char *cab_path, *cab_file;
+ int len = strlenW( cabinet );
+
+ /* make sure the cabinet file has a .cab extension */
+ if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
+ if (!pExtractFiles)
+ {
+ if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
+ {
+ ERR( "could not load advpack.dll\n" );
+ return FALSE;
+ }
+ if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
+ {
+ ERR( "could not find ExtractFiles in advpack.dll\n" );
+ return FALSE;
+ }
+ }
+
+ if (!(cab_path = strdupWtoA( root ))) return FALSE;
+ len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
+ if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
+ {
+ HeapFree( GetProcessHeap(), 0, cab_path );
+ return FALSE;
+ }
+ strcpy( cab_file, cab_path );
+ if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
+ WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
+ FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
+ pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
+ HeapFree( GetProcessHeap(), 0, cab_file );
+ HeapFree( GetProcessHeap(), 0, cab_path );
+ return CopyFileW( src, dst, FALSE /*FIXME*/ );
+}
+
+
+/***********************************************************************
+ * SetupOpenFileQueue (SETUPAPI.@)
+ */
+HSPFILEQ WINAPI SetupOpenFileQueue(void)
+{
+ struct file_queue *queue;
+
+ if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
+ return (HSPFILEQ)INVALID_HANDLE_VALUE;
+ return queue;
+}
+
+
+/***********************************************************************
+ * SetupCloseFileQueue (SETUPAPI.@)
+ */
+BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
+{
+ struct file_queue *queue = handle;
+
+ free_file_op_queue( &queue->copy_queue );
+ free_file_op_queue( &queue->rename_queue );
+ free_file_op_queue( &queue->delete_queue );
+ HeapFree( GetProcessHeap(), 0, queue );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupQueueCopyIndirectA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
+{
+ struct file_queue *queue = params->QueueHandle;
+ struct file_op *op;
+
+ if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
+ op->style = params->CopyStyle;
+ op->src_root = strdupAtoW( params->SourceRootPath );
+ op->src_path = strdupAtoW( params->SourcePath );
+ op->src_file = strdupAtoW( params->SourceFilename );
+ op->src_descr = strdupAtoW( params->SourceDescription );
+ op->src_tag = strdupAtoW( params->SourceTagfile );
+ op->dst_path = strdupAtoW( params->TargetDirectory );
+ op->dst_file = strdupAtoW( params->TargetFilename );
+
+ /* some defaults */
+ if (!op->src_file) op->src_file = op->dst_file;
+ if (params->LayoutInf)
+ {
+ get_src_file_info( params->LayoutInf, op );
+ if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
+ }
+
+ TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
+ debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
+ debugstr_w(op->dst_path), debugstr_w(op->dst_file),
+ debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
+
+ queue_file_op( &queue->copy_queue, op );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupQueueCopyIndirectW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
+{
+ struct file_queue *queue = params->QueueHandle;
+ struct file_op *op;
+
+ if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
+ op->style = params->CopyStyle;
+ op->src_root = strdupW( params->SourceRootPath );
+ op->src_path = strdupW( params->SourcePath );
+ op->src_file = strdupW( params->SourceFilename );
+ op->src_descr = strdupW( params->SourceDescription );
+ op->src_tag = strdupW( params->SourceTagfile );
+ op->dst_path = strdupW( params->TargetDirectory );
+ op->dst_file = strdupW( params->TargetFilename );
+
+ /* some defaults */
+ if (!op->src_file) op->src_file = op->dst_file;
+ if (params->LayoutInf)
+ {
+ get_src_file_info( params->LayoutInf, op );
+ if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
+ }
+
+ TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
+ debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
+ debugstr_w(op->dst_path), debugstr_w(op->dst_file),
+ debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
+
+ queue_file_op( &queue->copy_queue, op );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupQueueCopyA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
+ PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
+ DWORD style )
+{
+ SP_FILE_COPY_PARAMS_A params;
+
+ params.cbSize = sizeof(params);
+ params.QueueHandle = queue;
+ params.SourceRootPath = src_root;
+ params.SourcePath = src_path;
+ params.SourceFilename = src_file;
+ params.SourceDescription = src_descr;
+ params.SourceTagfile = src_tag;
+ params.TargetDirectory = dst_dir;
+ params.TargetFilename = dst_file;
+ params.CopyStyle = style;
+ params.LayoutInf = 0;
+ params.SecurityDescriptor = NULL;
+ return SetupQueueCopyIndirectA( ¶ms );
+}
+
+
+/***********************************************************************
+ * SetupQueueCopyW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
+ PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
+ DWORD style )
+{
+ SP_FILE_COPY_PARAMS_W params;
+
+ params.cbSize = sizeof(params);
+ params.QueueHandle = queue;
+ params.SourceRootPath = src_root;
+ params.SourcePath = src_path;
+ params.SourceFilename = src_file;
+ params.SourceDescription = src_descr;
+ params.SourceTagfile = src_tag;
+ params.TargetDirectory = dst_dir;
+ params.TargetFilename = dst_file;
+ params.CopyStyle = style;
+ params.LayoutInf = 0;
+ params.SecurityDescriptor = NULL;
+ return SetupQueueCopyIndirectW( ¶ms );
+}
+
+
+/***********************************************************************
+ * SetupQueueDefaultCopyA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file,
+ PCSTR dst_file, DWORD style )
+{
+ SP_FILE_COPY_PARAMS_A params;
+
+ params.cbSize = sizeof(params);
+ params.QueueHandle = queue;
+ params.SourceRootPath = src_root;
+ params.SourcePath = NULL;
+ params.SourceFilename = src_file;
+ params.SourceDescription = NULL;
+ params.SourceTagfile = NULL;
+ params.TargetDirectory = NULL;
+ params.TargetFilename = dst_file;
+ params.CopyStyle = style;
+ params.LayoutInf = hinf;
+ params.SecurityDescriptor = NULL;
+ return SetupQueueCopyIndirectA( ¶ms );
+}
+
+
+/***********************************************************************
+ * SetupQueueDefaultCopyW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
+ PCWSTR dst_file, DWORD style )
+{
+ SP_FILE_COPY_PARAMS_W params;
+
+ params.cbSize = sizeof(params);
+ params.QueueHandle = queue;
+ params.SourceRootPath = src_root;
+ params.SourcePath = NULL;
+ params.SourceFilename = src_file;
+ params.SourceDescription = NULL;
+ params.SourceTagfile = NULL;
+ params.TargetDirectory = NULL;
+ params.TargetFilename = dst_file;
+ params.CopyStyle = style;
+ params.LayoutInf = hinf;
+ params.SecurityDescriptor = NULL;
+ return SetupQueueCopyIndirectW( ¶ms );
+}
+
+
+/***********************************************************************
+ * SetupQueueDeleteA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
+{
+ struct file_queue *queue = handle;
+ struct file_op *op;
+
+ if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
+ op->style = 0;
+ op->src_root = NULL;
+ op->src_path = NULL;
+ op->src_file = NULL;
+ op->src_descr = NULL;
+ op->src_tag = NULL;
+ op->dst_path = strdupAtoW( part1 );
+ op->dst_file = strdupAtoW( part2 );
+ queue_file_op( &queue->delete_queue, op );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupQueueDeleteW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
+{
+ struct file_queue *queue = handle;
+ struct file_op *op;
+
+ if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
+ op->style = 0;
+ op->src_root = NULL;
+ op->src_path = NULL;
+ op->src_file = NULL;
+ op->src_descr = NULL;
+ op->src_tag = NULL;
+ op->dst_path = strdupW( part1 );
+ op->dst_file = strdupW( part2 );
+ queue_file_op( &queue->delete_queue, op );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupQueueRenameA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
+ PCSTR TargetPath, PCSTR TargetFilename )
+{
+ struct file_queue *queue = handle;
+ struct file_op *op;
+
+ if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
+ op->style = 0;
+ op->src_root = NULL;
+ op->src_path = strdupAtoW( SourcePath );
+ op->src_file = strdupAtoW( SourceFilename );
+ op->src_descr = NULL;
+ op->src_tag = NULL;
+ op->dst_path = strdupAtoW( TargetPath );
+ op->dst_file = strdupAtoW( TargetFilename );
+ queue_file_op( &queue->rename_queue, op );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupQueueRenameW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
+ PCWSTR TargetPath, PCWSTR TargetFilename )
+{
+ struct file_queue *queue = handle;
+ struct file_op *op;
+
+ if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
+ op->style = 0;
+ op->src_root = NULL;
+ op->src_path = strdupW( SourcePath );
+ op->src_file = strdupW( SourceFilename );
+ op->src_descr = NULL;
+ op->src_tag = NULL;
+ op->dst_path = strdupW( TargetPath );
+ op->dst_file = strdupW( TargetFilename );
+ queue_file_op( &queue->rename_queue, op );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupQueueCopySectionA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
+ PCSTR section, DWORD style )
+{
+ UNICODE_STRING sectionW;
+ BOOL ret = FALSE;
+
+ if (!RtlCreateUnicodeStringFromAsciiz( §ionW, section ))
+ {
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ return FALSE;
+ }
+ if (!src_root)
+ ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
+ else
+ {
+ UNICODE_STRING srcW;
+ if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
+ {
+ ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
+ RtlFreeUnicodeString( &srcW );
+ }
+ else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ }
+ RtlFreeUnicodeString( §ionW );
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupQueueCopySectionW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
+ PCWSTR section, DWORD style )
+{
+ SP_FILE_COPY_PARAMS_W params;
+ INFCONTEXT context;
+ WCHAR dest[MAX_PATH], src[MAX_PATH];
+ INT flags;
+
+ TRACE( "hinf=%p/%p section=%s root=%s\n",
+ hinf, hlist, debugstr_w(section), debugstr_w(src_root) );
+
+ params.cbSize = sizeof(params);
+ params.QueueHandle = queue;
+ params.SourceRootPath = src_root;
+ params.SourcePath = NULL;
+ params.SourceDescription = NULL;
+ params.SourceTagfile = NULL;
+ params.TargetFilename = dest;
+ params.CopyStyle = style;
+ params.LayoutInf = hinf;
+ params.SecurityDescriptor = NULL;
+
+ if (!hlist) hlist = hinf;
+ if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
+ if (!(params.TargetDirectory = get_destination_dir( hinf, section ))) return FALSE;
+ do
+ {
+ if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL ))
+ return FALSE;
+ if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0;
+ if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
+
+ params.SourceFilename = *src ? src : NULL;
+ if (!SetupQueueCopyIndirectW( ¶ms )) return FALSE;
+ } while (SetupFindNextLine( &context, &context ));
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupQueueDeleteSectionA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
+{
+ UNICODE_STRING sectionW;
+ BOOL ret = FALSE;
+
+ if (RtlCreateUnicodeStringFromAsciiz( §ionW, section ))
+ {
+ ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
+ RtlFreeUnicodeString( §ionW );
+ }
+ else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupQueueDeleteSectionW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
+{
+ INFCONTEXT context;
+ WCHAR *dest_dir;
+ WCHAR buffer[MAX_PATH];
+ BOOL ret = FALSE;
+ INT flags;
+
+ TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
+
+ if (!hlist) hlist = hinf;
+ if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
+ if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
+ do
+ {
+ if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
+ goto done;
+ if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
+ if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
+ } while (SetupFindNextLine( &context, &context ));
+
+ ret = TRUE;
+ done:
+ HeapFree( GetProcessHeap(), 0, dest_dir );
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupQueueRenameSectionA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
+{
+ UNICODE_STRING sectionW;
+ BOOL ret = FALSE;
+
+ if (RtlCreateUnicodeStringFromAsciiz( §ionW, section ))
+ {
+ ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
+ RtlFreeUnicodeString( §ionW );
+ }
+ else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupQueueRenameSectionW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
+{
+ INFCONTEXT context;
+ WCHAR *dest_dir;
+ WCHAR src[MAX_PATH], dst[MAX_PATH];
+ BOOL ret = FALSE;
+
+ TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
+
+ if (!hlist) hlist = hinf;
+ if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
+ if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
+ do
+ {
+ if (!SetupGetStringFieldW( &context, 1, dst, sizeof(dst)/sizeof(WCHAR), NULL ))
+ goto done;
+ if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL ))
+ goto done;
+ if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
+ } while (SetupFindNextLine( &context, &context ));
+
+ ret = TRUE;
+ done:
+ HeapFree( GetProcessHeap(), 0, dest_dir );
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupCommitFileQueueA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
+ PVOID context )
+{
+ struct callback_WtoA_context ctx;
+
+ ctx.orig_context = context;
+ ctx.orig_handler = handler;
+ return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
+}
+
+
+/***********************************************************************
+ * create_full_pathW
+ *
+ * Recursively create all directories in the path.
+ */
+static BOOL create_full_pathW(const WCHAR *path)
+{
+ BOOL ret = TRUE;
+ int len;
+ WCHAR *new_path;
+
+ new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
+ strcpyW(new_path, path);
+
+ while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
+ new_path[len - 1] = 0;
+
+ while(!CreateDirectoryW(new_path, NULL))
+ {
+ WCHAR *slash;
+ DWORD last_error = GetLastError();
+
+ if(last_error == ERROR_ALREADY_EXISTS)
+ break;
+
+ if(last_error != ERROR_PATH_NOT_FOUND)
+ {
+ ret = FALSE;
+ break;
+ }
+
+ if(!(slash = strrchrW(new_path, '\\')))
+ {
+ ret = FALSE;
+ break;
+ }
+
+ len = slash - new_path;
+ new_path[len] = 0;
+ if(!create_full_pathW(new_path))
+ {
+ ret = FALSE;
+ break;
+ }
+ new_path[len] = '\\';
+ }
+
+ HeapFree(GetProcessHeap(), 0, new_path);
+ return ret;
+}
+
+
+/***********************************************************************
+ * SetupCommitFileQueueW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
+ PVOID context )
+{
+ struct file_queue *queue = handle;
+ struct file_op *op;
+ BOOL result = FALSE;
+ FILEPATHS_W paths;
+ UINT op_result;
+
+ paths.Source = paths.Target = NULL;
+
+ if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
+ return TRUE; /* nothing to do */
+
+ if (!handler( context, SPFILENOTIFY_STARTQUEUE, owner, 0 )) return FALSE;
+
+ /* perform deletes */
+
+ if (queue->delete_queue.count)
+ {
+ if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
+ queue->delete_queue.count ))) goto done;
+ for (op = queue->delete_queue.head; op; op = op->next)
+ {
+ build_filepathsW( op, &paths );
+ op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
+ if (op_result == FILEOP_ABORT) goto done;
+ while (op_result == FILEOP_DOIT)
+ {
+ TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
+ if (DeleteFileW( paths.Target )) break; /* success */
+ paths.Win32Error = GetLastError();
+ op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
+ if (op_result == FILEOP_ABORT) goto done;
+ }
+ handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
+ }
+ handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
+ }
+
+ /* perform renames */
+
+ if (queue->rename_queue.count)
+ {
+ if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
+ queue->rename_queue.count ))) goto done;
+ for (op = queue->rename_queue.head; op; op = op->next)
+ {
+ build_filepathsW( op, &paths );
+ op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
+ if (op_result == FILEOP_ABORT) goto done;
+ while (op_result == FILEOP_DOIT)
+ {
+ TRACE( "renaming file %s -> %s\n",
+ debugstr_w(paths.Source), debugstr_w(paths.Target) );
+ if (MoveFileW( paths.Source, paths.Target )) break; /* success */
+ paths.Win32Error = GetLastError();
+ op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
+ if (op_result == FILEOP_ABORT) goto done;
+ }
+ handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
+ }
+ handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
+ }
+
+ /* perform copies */
+
+ if (queue->copy_queue.count)
+ {
+ if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
+ queue->copy_queue.count ))) goto done;
+ for (op = queue->copy_queue.head; op; op = op->next)
+ {
+ WCHAR newpath[MAX_PATH];
+
+ build_filepathsW( op, &paths );
+ op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
+ if (op_result == FILEOP_ABORT) goto done;
+ if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
+ while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
+ {
+ TRACE( "copying file %s -> %s\n",
+ debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
+ debugstr_w(paths.Target) );
+ if (op->dst_path)
+ {
+ if (!create_full_pathW( op->dst_path ))
+ {
+ paths.Win32Error = GetLastError();
+ op_result = handler( context, SPFILENOTIFY_COPYERROR,
+ (UINT_PTR)&paths, (UINT_PTR)newpath );
+ if (op_result == FILEOP_ABORT) goto done;
+ }
+ }
+ if (CopyFileW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
+ paths.Target, FALSE /*FIXME*/ )) break; /* success */
+ /* try to extract it from the cabinet file */
+ if (op->src_tag)
+ {
+ if (extract_cabinet_file( op->src_tag, op->src_root,
+ paths.Source, paths.Target )) break;
+ }
+ paths.Win32Error = GetLastError();
+ op_result = handler( context, SPFILENOTIFY_COPYERROR,
+ (UINT_PTR)&paths, (UINT_PTR)newpath );
+ if (op_result == FILEOP_ABORT) goto done;
+ }
+ handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
+ }
+ handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
+ }
+
+
+ result = TRUE;
+
+ done:
+ handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
+ HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
+ HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
+ return result;
+}
+
+
+/***********************************************************************
+ * SetupScanFileQueueA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupScanFileQueueA( HSPFILEQ queue, DWORD flags, HWND window,
+ PSP_FILE_CALLBACK_A callback, PVOID context, PDWORD result )
+{
+ FIXME("stub\n");
+ return FALSE;
+}
+
+
+/***********************************************************************
+ * SetupScanFileQueueW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupScanFileQueueW( HSPFILEQ queue, DWORD flags, HWND window,
+ PSP_FILE_CALLBACK_W callback, PVOID context, PDWORD result )
+{
+ FIXME("stub\n");
+ return FALSE;
+}
+
+
+/***********************************************************************
+ * SetupGetFileQueueCount (SETUPAPI.@)
+ */
+BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
+{
+ struct file_queue *queue = handle;
+
+ switch(op)
+ {
+ case FILEOP_COPY:
+ *result = queue->copy_queue.count;
+ return TRUE;
+ case FILEOP_RENAME:
+ *result = queue->rename_queue.count;
+ return TRUE;
+ case FILEOP_DELETE:
+ *result = queue->delete_queue.count;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/***********************************************************************
+ * SetupGetFileQueueFlags (SETUPAPI.@)
+ */
+BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
+{
+ struct file_queue *queue = handle;
+ *flags = queue->flags;
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupSetFileQueueFlags (SETUPAPI.@)
+ */
+BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
+{
+ struct file_queue *queue = handle;
+ queue->flags = (queue->flags & ~mask) | flags;
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * SetupInitDefaultQueueCallback (SETUPAPI.@)
+ */
+PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
+{
+ return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
+}
+
+
+/***********************************************************************
+ * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
+ */
+PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
+ DWORD reserved1, PVOID reserved2 )
+{
+ struct default_callback_context *context;
+
+ if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) )))
+ {
+ context->owner = owner;
+ context->progress = progress;
+ context->message = msg;
+ }
+ return context;
+}
+
+
+/***********************************************************************
+ * SetupTermDefaultQueueCallback (SETUPAPI.@)
+ */
+void WINAPI SetupTermDefaultQueueCallback( PVOID context )
+{
+ HeapFree( GetProcessHeap(), 0, context );
+}
+
+
+/***********************************************************************
+ * SetupDefaultQueueCallbackA (SETUPAPI.@)
+ */
+UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
+ UINT_PTR param1, UINT_PTR param2 )
+{
+ FILEPATHS_A *paths = (FILEPATHS_A *)param1;
+
+ switch(notification)
+ {
+ case SPFILENOTIFY_STARTQUEUE:
+ TRACE( "start queue\n" );
+ return TRUE;
+ case SPFILENOTIFY_ENDQUEUE:
+ TRACE( "end queue\n" );
+ return 0;
+ case SPFILENOTIFY_STARTSUBQUEUE:
+ TRACE( "start subqueue %d count %d\n", param1, param2 );
+ return TRUE;
+ case SPFILENOTIFY_ENDSUBQUEUE:
+ TRACE( "end subqueue %d\n", param1 );
+ return 0;
+ case SPFILENOTIFY_STARTDELETE:
+ TRACE( "start delete %s\n", debugstr_a(paths->Target) );
+ return FILEOP_DOIT;
+ case SPFILENOTIFY_ENDDELETE:
+ TRACE( "end delete %s\n", debugstr_a(paths->Target) );
+ return 0;
+ case SPFILENOTIFY_DELETEERROR:
+ ERR( "delete error %d %s\n", paths->Win32Error, debugstr_a(paths->Target) );
+ return FILEOP_SKIP;
+ case SPFILENOTIFY_STARTRENAME:
+ TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
+ return FILEOP_DOIT;
+ case SPFILENOTIFY_ENDRENAME:
+ TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
+ return 0;
+ case SPFILENOTIFY_RENAMEERROR:
+ ERR( "rename error %d %s -> %s\n", paths->Win32Error,
+ debugstr_a(paths->Source), debugstr_a(paths->Target) );
+ return FILEOP_SKIP;
+ case SPFILENOTIFY_STARTCOPY:
+ TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
+ return FILEOP_DOIT;
+ case SPFILENOTIFY_ENDCOPY:
+ TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
+ return 0;
+ case SPFILENOTIFY_COPYERROR:
+ ERR( "copy error %d %s -> %s\n", paths->Win32Error,
+ debugstr_a(paths->Source), debugstr_a(paths->Target) );
+ return FILEOP_SKIP;
+ case SPFILENOTIFY_NEEDMEDIA:
+ TRACE( "need media\n" );
+ return FILEOP_SKIP;
+ default:
+ FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
+ break;
+ }
+ return 0;
+}
+
+
+/***********************************************************************
+ * SetupDefaultQueueCallbackW (SETUPAPI.@)
+ */
+UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
+ UINT_PTR param1, UINT_PTR param2 )
+{
+ FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
+ return FILEOP_SKIP;
+}
diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec
index 27af8b9..b12e23c 100644
--- a/dlls/setupapi/setupapi.spec
+++ b/dlls/setupapi/setupapi.spec
@@ -9,229 +9,302 @@
debug_channels (setupapi)
-# almost all functions are commented out for now. Ordinals are from setupapi.dll 4.0
-
-# 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
-56 stdcall SetupCloseFileQueue(ptr) SetupCloseFileQueue
-57 stdcall SetupCloseInfFile(long) SetupCloseInfFile
-# 58 stdcall SetupCommitFileQueue() SetupCommitFileQueue
-59 stdcall SetupCommitFileQueueA(ptr ptr ptr ptr) SetupCommitFileQueueA
-# 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
-68 stdcall SetupDefaultQueueCallbackA(ptr long long long) SetupDefaultQueueCallbackA
-# 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
-157 stdcall SetupFindFirstLineA(long str str ptr) SetupFindFirstLineA
-#158 stdcall SetupFindFirstLineW() SetupFindFirstLineW
-159 stdcall SetupFindNextLine(ptr ptr) SetupFindNextLine
-#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
-173 stdcall SetupGetLineByIndexA(ptr str long ptr) SetupGetLineByIndexA
-#174 stdcall SetupGetLineByIndexW() SetupGetLineByIndexW
-#175 stdcall SetupGetLineCountA() SetupGetLineCountA
-#176 stdcall SetupGetLineCountW() SetupGetLineCountW
-177 stdcall SetupGetLineTextA(ptr long str str ptr long ptr) SetupGetLineTextA
-#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
-187 stdcall SetupGetStringFieldA(ptr long str long ptr) SetupGetStringFieldA
-#188 stdcall SetupGetStringFieldW() SetupGetStringFieldW
-#189 stdcall SetupGetTargetPathA() SetupGetTargetPathA
-#190 stdcall SetupGetTargetPathW() SetupGetTargetPathW
-191 stdcall SetupInitDefaultQueueCallback(long) SetupInitDefaultQueueCallback
-192 stdcall SetupInitDefaultQueueCallbackEx(long long long long ptr) SetupInitDefaultQueueCallbackEx
-#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
-201 stdcall SetupInstallFromInfSectionA(long long str long long str long ptr ptr long ptr) SetupInstallFromInfSectionA
-#202 stdcall SetupInstallFromInfSectionW() SetupInstallFromInfSectionW
-#203 stdcall SetupInstallServicesFromInfSectionA() SetupInstallServicesFromInfSectionA
-#204 stdcall SetupInstallServicesFromInfSectionW() SetupInstallServicesFromInfSectionW
-205 stdcall SetupIterateCabinetA(str long ptr ptr) SetupIterateCabinetA
-206 stdcall SetupIterateCabinetW(wstr long ptr ptr) SetupIterateCabinetW
-#207 stdcall SetupLogFileA() SetupLogFileA
-#208 stdcall SetupLogFileW() SetupLogFileW
-209 stdcall SetupOpenAppendInfFileA(str ptr ptr) SetupOpenAppendInfFileA
-#210 stdcall SetupOpenAppendInfFileW() SetupOpenAppendInfFileW
-211 stdcall SetupOpenFileQueue() SetupOpenFileQueue
-212 stdcall SetupOpenInfFileA(str str long ptr) SetupOpenInfFileA
-#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
-230 stdcall SetupQueueCopyA(ptr str str str str str str str long) SetupQueueCopyA
-#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
-259 stdcall SetupSetDirectoryIdA(long long str) SetupSetDirectoryIdA
-#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
-267 stdcall SetupTermDefaultQueueCallback(ptr) SetupTermDefaultQueueCallback
-#268 stdcall SetupTerminateFileLog(ptr) SetupTerminateFileLog
+@ stub AddMiniIconToList
+@ stub AddTagToGroupOrderListEntry
+@ stub AppendStringToMultiSz
+@ stub AssertFail
+@ stub CaptureAndConvertAnsiArg
+@ stub CaptureStringArg
+@ stub CenterWindowRelativeToParent
+@ stub ConcatenatePaths
+@ stub DelayedMove
+@ stub DelimStringToMultiSz
+@ stub DestroyTextFileReadBuffer
+@ stub DoesUserHavePrivilege
+@ stub DuplicateString
+@ stub EnablePrivilege
+@ stub ExtensionPropSheetPageProc
+@ stub FileExists
+@ stub FreeStringArray
+@ stub GetNewInfName
+@ stub GetSetFileTimestamp
+@ stub GetVersionInfoFromImage
+@ stub InfIsFromOemLocation
+@ stub InstallHinfSection
+@ stub InstallHinfSectionA
+@ stub InstallHinfSectionW
+@ stub InstallStop
+@ stub IsUserAdmin
+@ stub LookUpStringInTable
+@ stub MemoryInitialize
+@ stub MultiByteToUnicode
+@ stub MultiSzFromSearchControl
+@ stub MyFree
+@ stub MyGetFileTitle
+@ stub MyMalloc
+@ stub MyRealloc
+@ stub OpenAndMapFileForRead
+@ stub OutOfMemory
+@ stub QueryMultiSzValueToArray
+@ stub QueryRegistryValue
+@ stub ReadAsciiOrUnicodeTextFile
+@ stub RegistryDelnode
+@ stub RetreiveFileSecurity
+@ stub RetrieveServiceConfig
+@ stub SearchForInfFile
+@ stub SetArrayToMultiSzValue
+@ stub SetupAddInstallSectionToDiskSpaceListA
+@ stub SetupAddInstallSectionToDiskSpaceListW
+@ stub SetupAddSectionToDiskSpaceListA
+@ stub SetupAddSectionToDiskSpaceListW
+@ stub SetupAddToDiskSpaceListA
+@ stub SetupAddToDiskSpaceListW
+@ stub SetupAddToSourceListA
+@ stub SetupAddToSourceListW
+@ stub SetupAdjustDiskSpaceListA
+@ stub SetupAdjustDiskSpaceListW
+@ stub SetupCancelTemporarySourceList
+@ stdcall SetupCloseFileQueue(ptr) SetupCloseFileQueue
+@ stdcall SetupCloseInfFile(long) SetupCloseInfFile
+@ stub SetupCommitFileQueue
+@ stdcall SetupCommitFileQueueA(long long ptr ptr) SetupCommitFileQueueA
+@ stdcall SetupCommitFileQueueW(long long ptr ptr) SetupCommitFileQueueW
+@ stub SetupCopyErrorA
+@ stub SetupCopyErrorW
+@ stub SetupCreateDiskSpaceListA
+@ stub SetupCreateDiskSpaceListW
+@ stub SetupDecompressOrCopyFileA
+@ stub SetupDecompressOrCopyFileW
+@ stub SetupDefaultQueueCallback
+@ stdcall SetupDefaultQueueCallbackA(ptr long long long) SetupDefaultQueueCallbackA
+@ stdcall SetupDefaultQueueCallbackW(ptr long long long) SetupDefaultQueueCallbackW
+@ stub SetupDeleteErrorA
+@ stub SetupDeleteErrorW
+@ stub SetupDestroyDiskSpaceList
+@ stub SetupDiAskForOEMDisk
+@ stub SetupDiBuildClassInfoList
+@ stub SetupDiBuildDriverInfoList
+@ stub SetupDiCallClassInstaller
+@ stub SetupDiCancelDriverInfoSearch
+@ stub SetupDiChangeState
+@ stub SetupDiClassGuidsFromNameA
+@ stub SetupDiClassGuidsFromNameW
+@ stub SetupDiClassNameFromGuidA
+@ stub SetupDiClassNameFromGuidW
+@ stub SetupDiCreateDevRegKeyA
+@ stub SetupDiCreateDevRegKeyW
+@ stub SetupDiCreateDeviceInfoA
+@ stub SetupDiCreateDeviceInfoList
+@ stub SetupDiCreateDeviceInfoW
+@ stub SetupDiDeleteDevRegKey
+@ stub SetupDiDeleteDeviceInfo
+@ stub SetupDiDestroyClassImageList
+@ stub SetupDiDestroyDeviceInfoList
+@ stub SetupDiDestroyDriverInfoList
+@ stub SetupDiDrawMiniIcon
+@ stub SetupDiEnumDeviceInfo
+@ stub SetupDiEnumDriverInfoA
+@ stub SetupDiEnumDriverInfoW
+@ stub SetupDiGetActualSectionToInstallA
+@ stub SetupDiGetActualSectionToInstallW
+@ stub SetupDiGetClassBitmapIndex
+@ stub SetupDiGetClassDescriptionA
+@ stub SetupDiGetClassDescriptionW
+@ stub SetupDiGetClassDevPropertySheetsA
+@ stub SetupDiGetClassDevPropertySheetsW
+@ stub SetupDiGetClassDevsA
+@ stub SetupDiGetClassDevsW
+@ stub SetupDiGetClassImageIndex
+@ stub SetupDiGetClassImageList
+@ stub SetupDiGetClassInstallParamsA
+@ stub SetupDiGetClassInstallParamsW
+@ stub SetupDiGetDeviceInfoListClass
+@ stub SetupDiGetDeviceInstallParamsA
+@ stub SetupDiGetDeviceInstallParamsW
+@ stub SetupDiGetDeviceInstanceIdA
+@ stub SetupDiGetDeviceInstanceIdW
+@ stub SetupDiGetDeviceRegistryPropertyA
+@ stub SetupDiGetDeviceRegistryPropertyW
+@ stub SetupDiGetDriverInfoDetailA
+@ stub SetupDiGetDriverInfoDetailW
+@ stub SetupDiGetDriverInstallParamsA
+@ stub SetupDiGetDriverInstallParamsW
+@ stub SetupDiGetHwProfileFriendlyNameA
+@ stub SetupDiGetHwProfileFriendlyNameW
+@ stub SetupDiGetHwProfileList
+@ stub SetupDiGetINFClassA
+@ stub SetupDiGetINFClassW
+@ stub SetupDiGetSelectedDevice
+@ stub SetupDiGetSelectedDriverA
+@ stub SetupDiGetSelectedDriverW
+@ stub SetupDiGetWizardPage
+@ stub SetupDiInstallClassA
+@ stub SetupDiInstallClassW
+@ stub SetupDiInstallDevice
+@ stub SetupDiInstallDriverFiles
+@ stub SetupDiLoadClassIcon
+@ stub SetupDiMoveDuplicateDevice
+@ stub SetupDiOpenClassRegKey
+@ stub SetupDiOpenDevRegKey
+@ stub SetupDiOpenDeviceInfoA
+@ stub SetupDiOpenDeviceInfoW
+@ stub SetupDiRegisterDeviceInfo
+@ stub SetupDiRemoveDevice
+@ stub SetupDiSelectDevice
+@ stub SetupDiSelectOEMDrv
+@ stub SetupDiSetClassInstallParamsA
+@ stub SetupDiSetClassInstallParamsW
+@ stub SetupDiSetDeviceInstallParamsA
+@ stub SetupDiSetDeviceInstallParamsW
+@ stub SetupDiSetDeviceRegistryPropertyA
+@ stub SetupDiSetDeviceRegistryPropertyW
+@ stub SetupDiSetDriverInstallParamsA
+@ stub SetupDiSetDriverInstallParamsW
+@ stub SetupDiSetSelectedDevice
+@ stub SetupDiSetSelectedDriverA
+@ stub SetupDiSetSelectedDriverW
+@ stub SetupDuplicateDiskSpaceListA
+@ stub SetupDuplicateDiskSpaceListW
+@ stdcall SetupFindFirstLineA(long str str ptr) SetupFindFirstLineA
+@ stdcall SetupFindFirstLineW(long wstr wstr ptr) SetupFindFirstLineW
+@ stdcall SetupFindNextLine(ptr ptr) SetupFindNextLine
+@ stdcall SetupFindNextMatchLineA(ptr str ptr) SetupFindNextMatchLineA
+@ stdcall SetupFindNextMatchLineW(ptr wstr ptr) SetupFindNextMatchLineW
+@ stub SetupFreeSourceListA
+@ stub SetupFreeSourceListW
+@ stdcall SetupGetBinaryField(ptr long ptr long ptr) SetupGetBinaryField
+@ stdcall SetupGetFieldCount(ptr) SetupGetFieldCount
+@ stub SetupGetFileCompressionInfoA
+@ stub SetupGetFileCompressionInfoW
+@ stdcall SetupGetFileQueueCount(long long ptr) SetupGetFileQueueCount
+@ stdcall SetupGetFileQueueFlags(long ptr) SetupGetFileQueueFlags
+@ stub SetupGetInfFileListA
+@ stub SetupGetInfFileListW
+@ stub SetupGetInfInformationA
+@ stub SetupGetInfInformationW
+@ stdcall SetupGetIntField(ptr long ptr) SetupGetIntField
+@ stdcall SetupGetLineByIndexA(long str long ptr) SetupGetLineByIndexA
+@ stdcall SetupGetLineByIndexW(long wstr long ptr) SetupGetLineByIndexW
+@ stdcall SetupGetLineCountA(long str) SetupGetLineCountA
+@ stdcall SetupGetLineCountW(long wstr) SetupGetLineCountW
+@ stdcall SetupGetLineTextA(ptr long str str ptr long ptr) SetupGetLineTextA
+@ stdcall SetupGetLineTextW(ptr long wstr wstr ptr long ptr) SetupGetLineTextW
+@ stdcall SetupGetMultiSzFieldA(ptr long ptr long ptr) SetupGetMultiSzFieldA
+@ stdcall SetupGetMultiSzFieldW(ptr long ptr long ptr) SetupGetMultiSzFieldW
+@ stub SetupGetSourceFileLocationA
+@ stub SetupGetSourceFileLocationW
+@ stub SetupGetSourceFileSizeA
+@ stub SetupGetSourceFileSizeW
+@ stub SetupGetSourceInfoA
+@ stub SetupGetSourceInfoW
+@ stdcall SetupGetStringFieldA(ptr long ptr long ptr) SetupGetStringFieldA
+@ stdcall SetupGetStringFieldW(ptr long ptr long ptr) SetupGetStringFieldW
+@ stub SetupGetTargetPathA
+@ stub SetupGetTargetPathW
+@ stdcall SetupInitDefaultQueueCallback(long) SetupInitDefaultQueueCallback
+@ stdcall SetupInitDefaultQueueCallbackEx(long long long long ptr) SetupInitDefaultQueueCallbackEx
+@ stub SetupInitializeFileLogA
+@ stub SetupInitializeFileLogW
+@ stub SetupInstallFileA
+@ stub SetupInstallFileExA
+@ stub SetupInstallFileExW
+@ stub SetupInstallFileW
+@ stdcall SetupInstallFilesFromInfSectionA(long long long str str long) SetupInstallFilesFromInfSectionA
+@ stdcall SetupInstallFilesFromInfSectionW(long long long wstr wstr long) SetupInstallFilesFromInfSectionW
+@ stdcall SetupInstallFromInfSectionA(long long str long long str long ptr ptr long ptr) SetupInstallFromInfSectionA
+@ stdcall SetupInstallFromInfSectionW(long long wstr long long wstr long ptr ptr long ptr) SetupInstallFromInfSectionW
+@ stub SetupInstallServicesFromInfSectionA
+@ stub SetupInstallServicesFromInfSectionW
+@ stdcall SetupIterateCabinetA(str long ptr ptr) SetupIterateCabinetA
+@ stdcall SetupIterateCabinetW(wstr long ptr ptr) SetupIterateCabinetW
+@ stub SetupLogFileA
+@ stub SetupLogFileW
+@ stdcall SetupOpenAppendInfFileA(str long ptr) SetupOpenAppendInfFileA
+@ stdcall SetupOpenAppendInfFileW(wstr long ptr) SetupOpenAppendInfFileW
+@ stdcall SetupOpenFileQueue() SetupOpenFileQueue
+@ stdcall SetupOpenInfFileA(str str long ptr) SetupOpenInfFileA
+@ stdcall SetupOpenInfFileW(wstr wstr long ptr) SetupOpenInfFileW
+@ stub SetupOpenMasterInf
+@ stub SetupPromptForDiskA
+@ stub SetupPromptForDiskW
+@ stub SetupPromptReboot
+@ stub SetupQueryDrivesInDiskSpaceListA
+@ stub SetupQueryDrivesInDiskSpaceListW
+@ stub SetupQueryFileLogA
+@ stub SetupQueryFileLogW
+@ stub SetupQueryInfFileInformationA
+@ stub SetupQueryInfFileInformationW
+@ stub SetupQueryInfVersionInformationA
+@ stub SetupQueryInfVersionInformationW
+@ stub SetupQuerySourceListA
+@ stub SetupQuerySourceListW
+@ stub SetupQuerySpaceRequiredOnDriveA
+@ stub SetupQuerySpaceRequiredOnDriveW
+@ stdcall SetupQueueCopyA(long str str str str str str str long) SetupQueueCopyA
+@ stdcall SetupQueueCopyIndirectA(ptr) SetupQueueCopyIndirectA
+@ stdcall SetupQueueCopyIndirectW(ptr) SetupQueueCopyIndirectW
+@ stdcall SetupQueueCopySectionA(long str long long str long) SetupQueueCopySectionA
+@ stdcall SetupQueueCopySectionW(long wstr long long wstr long) SetupQueueCopySectionW
+@ stdcall SetupQueueCopyW(long wstr wstr wstr wstr wstr wstr wstr long) SetupQueueCopyW
+@ stdcall SetupQueueDefaultCopyA(long long str str long) SetupQueueDefaultCopyA
+@ stdcall SetupQueueDefaultCopyW(long long wstr wstr long) SetupQueueDefaultCopyW
+@ stdcall SetupQueueDeleteA(long str str) SetupQueueDeleteA
+@ stdcall SetupQueueDeleteSectionA(long long long str) SetupQueueDeleteSectionA
+@ stdcall SetupQueueDeleteSectionW(long long long wstr) SetupQueueDeleteSectionW
+@ stdcall SetupQueueDeleteW(long wstr wstr) SetupQueueDeleteW
+@ stdcall SetupQueueRenameA(long str str str str) SetupQueueRenameA
+@ stdcall SetupQueueRenameSectionA(long long long str) SetupQueueRenameSectionA
+@ stdcall SetupQueueRenameSectionW(long long long wstr) SetupQueueRenameSectionW
+@ stdcall SetupQueueRenameW(long wstr wstr wstr wstr) SetupQueueRenameW
+@ stub SetupRemoveFileLogEntryA
+@ stub SetupRemoveFileLogEntryW
+@ stub SetupRemoveFromDiskSpaceListA
+@ stub SetupRemoveFromDiskSpaceListW
+@ stub SetupRemoveFromSourceListA
+@ stub SetupRemoveFromSourceListW
+@ stub SetupRemoveInstallSectionFromDiskSpaceListA
+@ stub SetupRemoveInstallSectionFromDiskSpaceListW
+@ stub SetupRemoveSectionFromDiskSpaceListA
+@ stub SetupRemoveSectionFromDiskSpaceListW
+@ stub SetupRenameErrorA
+@ stub SetupRenameErrorW
+@ stub SetupScanFileQueue
+@ stdcall SetupScanFileQueueA(long long long ptr ptr ptr) SetupScanFileQueueA
+@ stdcall SetupScanFileQueueW(long long long ptr ptr ptr) SetupScanFileQueueW
+@ stdcall SetupSetDirectoryIdA(long long str) SetupSetDirectoryIdA
+@ stub SetupSetDirectoryIdExA
+@ stub SetupSetDirectoryIdExW
+@ stdcall SetupSetDirectoryIdW(long long wstr) SetupSetDirectoryIdW
+@ stdcall SetupSetFileQueueFlags(long long long) SetupSetFileQueueFlags
+@ stub SetupSetPlatformPathOverrideA
+@ stub SetupSetPlatformPathOverrideW
+@ stub SetupSetSourceListA
+@ stub SetupSetSourceListW
+@ stdcall SetupTermDefaultQueueCallback(ptr) SetupTermDefaultQueueCallback
+@ stub SetupTerminateFileLog
+@ stub ShouldDeviceBeExcluded
+@ stub StampFileSecurity
+@ stub StringTableAddString
+@ stub StringTableAddStringEx
+@ stub StringTableDestroy
+@ stub StringTableDuplicate
+@ stub StringTableEnum
+@ stub StringTableGetExtraData
+@ stub StringTableInitialize
+@ stub StringTableInitializeEx
+@ stub StringTableLookUpString
+@ stub StringTableLookUpStringEx
+@ stub StringTableSetExtraData
+@ stub StringTableStringFromId
+@ stub StringTableTrim
+@ stub TakeOwnershipOfFile
+@ stub UnicodeToMultiByte
+@ stub UnmapAndCloseFile
+@ stub pSetupDirectoryIdToPath
+@ stub pSetupGetField
+@ stub pSetupGetOsLoaderDriveAndPath
+@ stub pSetupGetVersionDatum
+@ stub pSetupGuidFromString
+@ stub pSetupIsGuidNull
+@ stub pSetupMakeSurePathExists
+@ stub pSetupStringFromGuid
diff --git a/dlls/setupapi/setupapi_private.h b/dlls/setupapi/setupapi_private.h
index 8a9b709..73018aa 100644
--- a/dlls/setupapi/setupapi_private.h
+++ b/dlls/setupapi/setupapi_private.h
@@ -20,6 +20,7 @@
#define __SETUPAPI_PRIVATE_H
#include "wine/windef16.h"
+#include "setupx16.h"
#define COPYFILEDLGORD 1000
#define SOURCESTRORD 500
@@ -54,4 +55,24 @@
extern LPCSTR IP_GetFileName(HINF16 hInf);
+/* string substitutions */
+
+struct inf_file;
+extern const WCHAR *DIRID_get_string( HINF hinf, int dirid );
+extern unsigned int PARSER_string_substA( struct inf_file *file, const WCHAR *text,
+ char *buffer, unsigned int size );
+extern unsigned int PARSER_string_substW( struct inf_file *file, const WCHAR *text,
+ WCHAR *buffer, unsigned int size );
+extern const WCHAR *PARSER_get_src_root( HINF hinf );
+
+/* support for Ascii queue callback functions */
+
+struct callback_WtoA_context
+{
+ void *orig_context;
+ PSP_FILE_CALLBACK_A orig_handler;
+};
+
+UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification, UINT_PTR, UINT_PTR );
+
#endif /* __SETUPAPI_PRIVATE_H */
diff --git a/dlls/setupapi/setupx.spec b/dlls/setupapi/setupx.spec
index 05d9536..19206b1 100644
--- a/dlls/setupapi/setupx.spec
+++ b/dlls/setupapi/setupx.spec
@@ -59,8 +59,8 @@
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)
+61 pascal suErrorToIds(word word) suErrorToIds16
+62 pascal16 TPWriteProfileString(str str str) TPWriteProfileString16
63 stub SURPLSETUP
# does SUSTORELDIDPATH set the path of an LDID in the registry ?
64 stub SUSTORELDIDPATH
diff --git a/dlls/setupapi/setupx_main.c b/dlls/setupapi/setupx_main.c
index 0964aec..59b27d3 100644
--- a/dlls/setupapi/setupx_main.c
+++ b/dlls/setupapi/setupx_main.c
@@ -59,7 +59,9 @@
#include <stdio.h>
#include <string.h>
#include "winreg.h"
+#include "winerror.h"
#include "wine/winuser16.h"
+#include "setupapi.h"
#include "setupx16.h"
#include "setupapi_private.h"
#include "winerror.h"
@@ -154,139 +156,6 @@
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 (SETUPX.527)
@@ -707,7 +576,7 @@
pPrev = pCurr;
pCurr = pCurr->next;
}
- if (pCurr == NULL) /* hit end of list */
+ if (!pCurr || pldd->ldid != pCurr->pldd->ldid)
{
is_new = TRUE;
pCurr = HeapAlloc(heap, 0, sizeof(LDD_LIST));
@@ -850,400 +719,8 @@
LOGDISKDESC_S ldd;
TRACE("(%d, '%s');\n", ldid, szPath);
+ SetupSetDirectoryIdA( 0, 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")) continue;
- p = pEqual+1;
- goto found;
- }
- }
- }
- }
- 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 (SETUPX.103)
- *
- * 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);
-}
-
-/*
- * 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 bSingle = FALSE;
- unsigned int n;
- LPCSTR filename = IP_GetFileName(hInf);
- LPSTR pCopyEntry;
- char pDstStr[MAX_PATH];
- LPSTR pSrcDir, pDstDir;
- LPSTR pFileEntries, p;
- WORD ldid;
- LOGDISKDESC_S ldd;
- LPSTR *pSubFile;
- LPSTR pSrcFile, pDstFile;
- WORD flag;
-
- for (n=0; n < *(DWORD *)pSub; n++)
- {
- pCopyEntry = *(pSub+1+n);
- if (*pCopyEntry == '@')
- {
- pCopyEntry++;
- bSingle = TRUE;
- }
- else
- bSingle = FALSE;
-
- /* 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, "",
- pDstStr, sizeof(pDstStr), filename)))
- {
- /* hmm, not found; try the default entry */
- if (!(GetPrivateProfileStringA("DestinationDirs", "DefaultDestDir", "", pDstStr, sizeof(pDstStr), filename)))
- {
- WARN("DefaultDestDir not found.\n");
- continue;
- }
- }
-
- /* translate destination dir if given as LDID */
- ldid = atoi(pDstStr);
- if (ldid)
- {
- if (!(SETUPX_IP_TranslateLDID(ldid, &pDstDir, hInf)))
- continue;
- }
- else
- pDstDir = pDstStr;
-
- /* now that we have the destination dir, register file copying */
-
- if (bSingle)
- {
- VcpQueueCopy16(pCopyEntry, pCopyEntry, pSrcDir, pDstDir, LDID_SRCPATH, ldid ? ldid : 0xffff, 0, VFNL_COPY, 0);
- return TRUE;
- }
-
- /* entry wasn't a single file, so let's iterate over section */
- pFileEntries = SETUPX_GetSectionEntries(filename, pCopyEntry);
- if (pFileEntries == NULL) continue;
- 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);
- flag = 0;
- if (*(DWORD *)pSubFile > 2)
- {
- 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));
- /* we probably need to set VIRTNODE.vhstrDstFinalName to
- * the final destination name, and the temp name is merely
- * the copy destination */
- }
- }
- VcpQueueCopy16(pSrcFile, pDstFile, pSrcDir, pDstDir, LDID_SRCPATH, ldid ? ldid : 0xffff, 0, VFNL_COPY|flag, 0);
- SETUPX_FreeSubStrings(pSubFile);
- }
- }
-
- return TRUE;
-}
-
-/***********************************************************************
- * GenInstall (SETUPX.101)
- *
- * generic installer 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;
-}
diff --git a/dlls/setupapi/stubs.c b/dlls/setupapi/stubs.c
index d4b7834..36fee7d 100644
--- a/dlls/setupapi/stubs.c
+++ b/dlls/setupapi/stubs.c
@@ -1,4 +1,3 @@
-/* -*- tab-width: 8; c-basic-offset: 8 -*- */
/*
* SetupAPI stubs
*
@@ -27,25 +26,6 @@
/***********************************************************************
- * SetupCloseFileQueue (SETUPAPI.56)
- */
-VOID WINAPI SetupCloseFileQueue(HSPFILEQ QueueHandle)
-{
- FIXME("not implemented (setupapi.dll) \n");
-}
-
-/***********************************************************************
- * SetupCommitFileQueueA (SETUPAPI.59)
- */
-BOOL WINAPI SetupCommitFileQueueA(HWND Owner, HSPFILEQ QueueHandle,
- PSP_FILE_CALLBACK_A MsgHandler,
- PVOID Context)
-{
- FIXME("not implemented (setupapi.dll) \n");
- return FALSE;
-}
-
-/***********************************************************************
* SetupIterateCabinetA (SETUPAPI.205)
*/
BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved,
@@ -67,171 +47,20 @@
/***********************************************************************
- * SetupGetLineTextA (SETUPAPI.177)
+ * TPWriteProfileString16 (SETUPX.62)
*/
-BOOL WINAPI SetupGetLineTextA (PINFCONTEXT Context, HINF InfHandle,
- PCSTR Section, PCSTR Key, LPSTR ReturnBuffer,
- DWORD ReturnBufferSize, PDWORD RequiredSize)
+BOOL WINAPI TPWriteProfileString16( LPCSTR section, LPCSTR entry, LPCSTR string )
{
- FIXME("not implemented (setupapi.dll) \n");
- return 0;
-}
-
-/***********************************************************************
- * SetupGetStringFieldA (SETUPAPI.187)
- */
-BOOL WINAPI SetupGetStringFieldA(PINFCONTEXT Context, DWORD FieldIndex,
- LPSTR ReturnBuffer, DWORD ReturnBufferSize,
- PDWORD RequiredSize)
-{
- FIXME("not implemented (setupapi.dll) \n");
- return 0;
+ FIXME( "%s %s %s: stub\n", debugstr_a(section), debugstr_a(entry), debugstr_a(string) );
+ return TRUE;
}
/***********************************************************************
- * SetupFindNextLine (SETUPAPI.159)
+ * suErrorToIds16 (SETUPX.61)
*/
-BOOL WINAPI SetupFindNextLine (PINFCONTEXT ContextIn, PINFCONTEXT ContextOut)
+DWORD WINAPI suErrorToIds16( WORD w1, WORD w2 )
{
- FIXME("not implemented (setupapi.dll) \n");
- return 0;
+ FIXME( "%x %x: stub\n", w1, w2 );
+ return 0;
}
-
-
-/***********************************************************************
- * SetupInitDefaultQueueCallback (SETUPAPI.191)
- */
-PVOID WINAPI SetupInitDefaultQueueCallback(HWND OwnerWindow)
-{
- FIXME("not implemented (setupapi.dll) \n");
- return 0;
-}
-
-/***********************************************************************
- * SetupInitDefaultQueueCallbackEx (SETUPAPI.192)
- */
-PVOID WINAPI SetupInitDefaultQueueCallbackEx(HWND OwnerWindow,
- HWND AlternativeProgressWindow,
- UINT ProgressMessage,
- DWORD res1,
- PVOID res2)
-{
- FIXME("not implemented (setupapi.dll) \n");
- return 0;
-}
-
-/***********************************************************************
- * SetupCloseInfFile (SETUPAPI.57)
- */
-VOID WINAPI SetupCloseInfFile (HINF InfHandle)
-{
- FIXME("not implemented (setupapi.dll) \n");
-}
-
-
-/***********************************************************************
- * SetupDefaultQueueCallbackA (SETUPAPI.68)
- */
-UINT WINAPI SetupDefaultQueueCallbackA (PVOID Context, UINT Notification,
- UINT Param1, UINT Param2)
-{
- FIXME("not implemented (setupapi.dll) \n");
- return 0;
-}
-
-
-/***********************************************************************
- * SetupFindFirstLineA (SETUPAPI.157)
- */
-BOOL WINAPI SetupFindFirstLineA (HINF InfHandle, PCSTR Section, PCSTR Key,
- PINFCONTEXT Context)
-{
- FIXME("not implemented (setupapi.dll) \n");
- return 0;
-}
-
-/***********************************************************************
- * SetupGetLineByIndexA (SETUPAPI.173)
- */
-BOOL WINAPI SetupGetLineByIndexA (HINF InfHandle, PCSTR Section, DWORD Index,
- PINFCONTEXT Context)
-{
- FIXME("not implemented (setupapi.dll) \n");
- return FALSE;
-}
-
-
-/***********************************************************************
- * SetupInstallFromInfSectionA (SETUPAPI.201)
- */
-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 (SETUPAPI.209)
- */
-BOOL WINAPI SetupOpenAppendInfFileA (PCSTR FileName, HINF InfHandle,
- PUINT ErrorLine)
-{
- FIXME("not implemented (setupapi.dll) \n");
- return FALSE;
-}
-
-/***********************************************************************
- * SetupOpenFileQueue (SETUPAPI.211)
- */
-HSPFILEQ WINAPI SetupOpenFileQueue (VOID)
-{
- FIXME("not implemented (setupapi.dll) \n");
- return (HSPFILEQ) INVALID_HANDLE_VALUE;
-}
-
-/***********************************************************************
- * SetupOpenInfFileA (SETUPAPI.212)
- */
-HINF WINAPI SetupOpenInfFileA (PCSTR FileName, PCSTR InfClass, DWORD InfStyle,
- PUINT ErrorLine)
-{
- FIXME("not implemented (setupapi.dll) \n");
- return 0;
-}
-
-/***********************************************************************
- * SetupQueueCopyA (SETUPAPI.230)
- */
-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 (SETUPAPI.259)
- */
-BOOL WINAPI SetupSetDirectoryIdA (HINF InfHandle,
- DWORD Id,
- PCSTR Directory)
-{
- FIXME("not implemented (setupapi.dll) \n");
- return FALSE;
-}
-
-
-/***********************************************************************
- * SetupTermDefaultQueueCallback (SETUPAPI.267)
- */
-VOID WINAPI SetupTermDefaultQueueCallback (PVOID Callback)
-{
- FIXME("not implemented (setupapi.dll) \n");
-}
-
diff --git a/dlls/setupapi/virtcopy.c b/dlls/setupapi/virtcopy.c
index a32927e..4fbcc3e 100644
--- a/dlls/setupapi/virtcopy.c
+++ b/dlls/setupapi/virtcopy.c
@@ -24,8 +24,9 @@
#include <string.h>
#include "winbase.h"
#include "winuser.h"
-#include "setupx16.h"
#include "winreg.h"
+#include "setupapi.h"
+#include "setupx16.h"
#include "setupapi_private.h"
#include "wine/debug.h"
@@ -660,12 +661,15 @@
if (!(VCP_UI_GetDialogTemplate(&template32)))
return VCPN_FAIL;
- hDlgCopy = CreateDialogIndirectParamA(SETUPAPI_hInstance, template32, 0,
- VCP_UI_FileCopyDlgProc, 0);
- if (!hDlgCopy)
- return VCPN_FAIL;
- SetDlgItemTextA(hDlgCopy, SOURCESTRORD, "Scanning ...");
- SetDlgItemTextA(hDlgCopy, DESTSTRORD, "NOT_IMPLEMENTED_YET");
+ if (vn_num > 10) /* hack */
+ {
+ hDlgCopy = CreateDialogIndirectParamA(SETUPAPI_hInstance, template32, 0,
+ VCP_UI_FileCopyDlgProc, 0);
+ if (!hDlgCopy)
+ return VCPN_FAIL;
+ SetDlgItemTextA(hDlgCopy, SOURCESTRORD, "Scanning ...");
+ SetDlgItemTextA(hDlgCopy, DESTSTRORD, "NOT_IMPLEMENTED_YET");
+ }
strcpy(buf, REG_INSTALLEDFILES);
if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyFiles))
return VCPN_FAIL;
@@ -749,7 +753,7 @@
res = VCP_UI_CopyStart();
break;
case VCPM_VSTATCOPYEND:
- DestroyWindow(hDlgCopy);
+ if (hDlgCopy) DestroyWindow(hDlgCopy);
break;
default:
FIXME("unhandled msg 0x%04x\n", uMsg);
diff --git a/include/setupapi.h b/include/setupapi.h
index 955610e..df3de22 100644
--- a/include/setupapi.h
+++ b/include/setupapi.h
@@ -16,8 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __SETUPAPI__
-#define __SETUPAPI__
+#ifndef _INC_SETUPAPI
+#define _INC_SETUPAPI
#include "commctrl.h"
@@ -39,12 +39,86 @@
UINT Line;
} INFCONTEXT, *PINFCONTEXT;
+typedef struct _SP_ALTPLATFORM_INFO_V2
+{
+ DWORD cbSize;
+ DWORD Platform;
+ DWORD MajorVersion;
+ DWORD MinorVersion;
+ WORD ProcessorArchitecture;
+ union
+ {
+ WORD Reserved;
+ WORD Flags;
+ } DUMMYUNIONNAME;
+ DWORD FirstValidatedMajorVersion;
+ DWORD FirstValidatedMinorVersion;
+} SP_ALTPLATFORM_INFO_V2, *PSP_ALTPLATFORM_INFO_V2;
+
+#define SP_ALTPLATFORM_FLAGS_VERSION_RANGE 0x0001
+
+typedef struct _SP_ALTPLATFORM_INFO_V1
+{
+ DWORD cbSize;
+ DWORD Platform;
+ DWORD MajorVersion;
+ DWORD MinorVersion;
+ WORD ProcessorArchitecture;
+ WORD Reserved;
+} SP_ALTPLATFORM_INFO_V1, *PSP_ALTPLATFORM_INFO_V1;
+
+typedef SP_ALTPLATFORM_INFO_V2 SP_ALTPLATFORM_INFO;
+typedef PSP_ALTPLATFORM_INFO_V2 PSP_ALTPLATFORM_INFO;
+
+typedef struct _SP_FILE_COPY_PARAMS_A
+{
+ DWORD cbSize;
+ HSPFILEQ QueueHandle;
+ PCSTR SourceRootPath;
+ PCSTR SourcePath;
+ PCSTR SourceFilename;
+ PCSTR SourceDescription;
+ PCSTR SourceTagfile;
+ PCSTR TargetDirectory;
+ PCSTR TargetFilename;
+ DWORD CopyStyle;
+ HINF LayoutInf;
+ PCSTR SecurityDescriptor;
+} SP_FILE_COPY_PARAMS_A, *PSP_FILE_COPY_PARAMS_A;
+
+typedef struct _SP_FILE_COPY_PARAMS_W
+{
+ DWORD cbSize;
+ HSPFILEQ QueueHandle;
+ PCWSTR SourceRootPath;
+ PCWSTR SourcePath;
+ PCWSTR SourceFilename;
+ PCWSTR SourceDescription;
+ PCWSTR SourceTagfile;
+ PCWSTR TargetDirectory;
+ PCWSTR TargetFilename;
+ DWORD CopyStyle;
+ HINF LayoutInf;
+ PCWSTR SecurityDescriptor;
+} SP_FILE_COPY_PARAMS_W, *PSP_FILE_COPY_PARAMS_W;
+
+DECL_WINELIB_TYPE_AW(SP_FILE_COPY_PARAMS_)
+DECL_WINELIB_TYPE_AW(PSP_FILE_COPY_PARAMS_)
+
typedef UINT (CALLBACK *PSP_FILE_CALLBACK_A)( PVOID Context, UINT Notification,
UINT Param1, UINT Param2 );
typedef UINT (CALLBACK *PSP_FILE_CALLBACK_W)( PVOID Context, UINT Notification,
UINT Param1, UINT Param2 );
#define PSP_FILE_CALLBACK WINELIB_NAME_AW(PSP_FILE_CALLBACK_)
+#define LINE_LEN 256
+#define MAX_INF_STRING_LENGTH 4096
+#define MAX_TITLE_LEN 60
+#define MAX_INSTRUCTION_LEN 256
+#define MAX_LABEL_LEN 30
+#define MAX_SERVICE_NAME_LEN 256
+#define MAX_SUBTITLE_LEN 256
+#define SP_MAX_MACHINENAME_LENGTH (MAX_PATH + 3)
/* Device Information structure (references a device instance that is a member
of a device information set) */
@@ -56,4 +130,392 @@
DWORD Reserved;
} SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;
-#endif /* __SETUPAPI__ */
+#define INF_STYLE_NONE 0x00
+#define INF_STYLE_OLDNT 0x01
+#define INF_STYLE_WIN4 0x02
+#define INF_STYLE_CACHE_ENABLE 0x10
+#define INF_STYLE_CACHE_DISABLE 0x20
+
+#define FILEOP_COPY 0
+#define FILEOP_RENAME 1
+#define FILEOP_DELETE 2
+#define FILEOP_BACKUP 3
+
+#define FILEOP_ABORT 0
+#define FILEOP_DOIT 1
+#define FILEOP_SKIP 2
+#define FILEOP_RETRY FILEOP_DOIT
+#define FILEOP_NEWPATH 4
+
+typedef struct _FILEPATHS_A
+{
+ PCSTR Target;
+ PCSTR Source;
+ UINT Win32Error;
+ DWORD Flags;
+} FILEPATHS_A, *PFILEPATHS_A;
+
+typedef struct _FILEPATHS_W
+{
+ PCWSTR Target;
+ PCWSTR Source;
+ UINT Win32Error;
+ DWORD Flags;
+} FILEPATHS_W, *PFILEPATHS_W;
+
+DECL_WINELIB_TYPE_AW(FILEPATHS_)
+DECL_WINELIB_TYPE_AW(PFILEPATHS_)
+
+#define SPFILENOTIFY_STARTQUEUE 0x0001
+#define SPFILENOTIFY_ENDQUEUE 0x0002
+#define SPFILENOTIFY_STARTSUBQUEUE 0x0003
+#define SPFILENOTIFY_ENDSUBQUEUE 0x0004
+#define SPFILENOTIFY_STARTDELETE 0x0005
+#define SPFILENOTIFY_ENDDELETE 0x0006
+#define SPFILENOTIFY_DELETEERROR 0x0007
+#define SPFILENOTIFY_STARTRENAME 0x0008
+#define SPFILENOTIFY_ENDRENAME 0x0009
+#define SPFILENOTIFY_RENAMEERROR 0x000a
+#define SPFILENOTIFY_STARTCOPY 0x000b
+#define SPFILENOTIFY_ENDCOPY 0x000c
+#define SPFILENOTIFY_COPYERROR 0x000d
+#define SPFILENOTIFY_NEEDMEDIA 0x000e
+#define SPFILENOTIFY_QUEUESCAN 0x000f
+#define SPFILENOTIFY_CABINETINFO 0x0010
+#define SPFILENOTIFY_FILEINCABINET 0x0011
+#define SPFILENOTIFY_NEEDNEWCABINET 0x0012
+#define SPFILENOTIFY_FILEEXTRACTED 0x0013
+#define SPFILENOTIFY_FILEOPDELAYED 0x0014
+#define SPFILENOTIFY_STARTBACKUP 0x0015
+#define SPFILENOTIFY_BACKUPERROR 0x0016
+#define SPFILENOTIFY_ENDBACKUP 0x0017
+#define SPFILENOTIFY_QUEUESCAN_EX 0x0018
+#define SPFILENOTIFY_STARTREGISTRATION 0x0019
+#define SPFILENOTIFY_ENDREGISTRATION 0x0020
+#define SPFILENOTIFY_QUEUESCAN_SIGNERINFO 0x0040
+
+#define SPFILENOTIFY_LANGMISMATCH 0x00010000
+#define SPFILENOTIFY_TARGETEXISTS 0x00020000
+#define SPFILENOTIFY_TARGETNEWER 0x00040000
+
+#define SPINST_LOGCONFIG 0x00000001
+#define SPINST_INIFILES 0x00000002
+#define SPINST_REGISTRY 0x00000004
+#define SPINST_INI2REG 0x00000008
+#define SPINST_FILES 0x00000010
+#define SPINST_BITREG 0x00000020
+#define SPINST_REGSVR 0x00000040
+#define SPINST_UNREGSVR 0x00000080
+#define SPINST_PROFILEITEMS 0x00000100
+#define SPINST_COPYINF 0x00000200
+#define SPINST_ALL 0x000003ff
+#define SPINST_SINGLESECTION 0x00010000
+#define SPINST_LOGCONFIG_IS_FORCED 0x00020000
+#define SPINST_LOGCONFIGS_ARE_OVERRIDES 0x00040000
+#define SPINST_REGISTERCALLBACKAWARE 0x00080000
+
+#define SP_COPY_DELETESOURCE 0x00000001
+#define SP_COPY_REPLACEONLY 0x00000002
+#define SP_COPY_NEWER 0x00000004
+#define SP_COPY_NEWER_OR_SAME SP_COPY_NEWER
+#define SP_COPY_NOOVERWRITE 0x00000008
+#define SP_COPY_NODECOMP 0x00000010
+#define SP_COPY_LANGUAGEAWARE 0x00000020
+#define SP_COPY_SOURCE_ABSOLUTE 0x00000040
+#define SP_COPY_SOURCEPATH_ABSOLUTE 0x00000080
+#define SP_COPY_IN_USE_NEEDS_REBOOT 0x00000100
+#define SP_COPY_FORCE_IN_USE 0x00000200
+#define SP_COPY_NOSKIP 0x00000400
+#define SP_FLAG_CABINETCONTINUATION 0x00000800
+#define SP_COPY_FORCE_NOOVERWRITE 0x00001000
+#define SP_COPY_FORCE_NEWER 0x00002000
+#define SP_COPY_WARNIFSKIP 0x00004000
+#define SP_COPY_NOBROWSE 0x00008000
+#define SP_COPY_NEWER_ONLY 0x00010000
+#define SP_COPY_SOURCE_SIS_MASTER 0x00020000
+#define SP_COPY_OEMINF_CATALOG_ONLY 0x00040000
+#define SP_COPY_REPLACE_BOOT_FILE 0x00080000
+#define SP_COPY_NOPRUNE 0x00100000
+#define SP_COPY_OEM_F6_INF 0x00200000
+
+#define FLG_ADDREG_DELREG_BIT 0x00008000
+#define FLG_ADDREG_BINVALUETYPE 0x00000001
+#define FLG_ADDREG_NOCLOBBER 0x00000002
+#define FLG_ADDREG_DELVAL 0x00000004
+#define FLG_ADDREG_APPEND 0x00000008
+#define FLG_ADDREG_KEYONLY 0x00000010
+#define FLG_ADDREG_OVERWRITEONLY 0x00000020
+#define FLG_ADDREG_64BITKEY 0x00001000
+#define FLG_ADDREG_KEYONLY_COMMON 0x00002000
+#define FLG_ADDREG_32BITKEY 0x00004000
+#define FLG_ADDREG_TYPE_SZ 0x00000000
+#define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000
+#define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000
+#define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE)
+#define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE)
+#define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE)
+#define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
+
+#define FLG_DELREG_VALUE (0x00000000)
+#define FLG_DELREG_TYPE_MASK FLG_ADDREG_TYPE_MASK
+#define FLG_DELREG_TYPE_SZ FLG_ADDREG_TYPE_SZ
+#define FLG_DELREG_TYPE_MULTI_SZ FLG_ADDREG_TYPE_MULTI_SZ
+#define FLG_DELREG_TYPE_EXPAND_SZ FLG_ADDREG_TYPE_EXPAND_SZ
+#define FLG_DELREG_TYPE_BINARY FLG_ADDREG_TYPE_BINARY
+#define FLG_DELREG_TYPE_DWORD FLG_ADDREG_TYPE_DWORD
+#define FLG_DELREG_TYPE_NONE FLG_ADDREG_TYPE_NONE
+#define FLG_DELREG_64BITKEY FLG_ADDREG_64BITKEY
+#define FLG_DELREG_KEYONLY_COMMON FLG_ADDREG_KEYONLY_COMMON
+#define FLG_DELREG_32BITKEY FLG_ADDREG_32BITKEY
+#define FLG_DELREG_OPERATION_MASK (0x000000FE)
+#define FLG_DELREG_MULTI_SZ_DELSTRING (FLG_DELREG_TYPE_MULTI_SZ | FLG_ADDREG_DELREG_BIT | 0x00000002)
+
+/* Class installer function codes */
+#define DIF_SELECTDEVICE 0x01
+#define DIF_INSTALLDEVICE 0x02
+#define DIF_ASSIGNRESOURCES 0x03
+#define DIF_PROPERTIES 0x04
+#define DIF_REMOVE 0x05
+#define DIF_FIRSTTIMESETUP 0x06
+#define DIF_FOUNDDEVICE 0x07
+#define DIF_SELECTCLASSDRIVERS 0x08
+#define DIF_VALIDATECLASSDRIVERS 0x09
+#define DIF_INSTALLCLASSDRIVERS 0x0a
+#define DIF_CALCDISKSPACE 0x0b
+#define DIF_DESTROYPRIVATEDATA 0x0c
+#define DIF_VALIDATEDRIVER 0x0d
+#define DIF_MOVEDEVICE 0x0e
+#define DIF_DETECT 0x0f
+#define DIF_INSTALLWIZARD 0x10
+#define DIF_DESTROYWIZARDDATA 0x11
+#define DIF_PROPERTYCHANGE 0x12
+#define DIF_ENABLECLASS 0x13
+#define DIF_DETECTVERIFY 0x14
+#define DIF_INSTALLDEVICEFILES 0x15
+#define DIF_UNREMOVE 0x16
+#define DIF_SELECTBESTCOMPATDRV 0x17
+#define DIF_ALLOW_INSTALL 0x18
+#define DIF_REGISTERDEVICE 0x19
+#define DIF_NEWDEVICEWIZARD_PRESELECT 0x1a
+#define DIF_NEWDEVICEWIZARD_SELECT 0x1b
+#define DIF_NEWDEVICEWIZARD_PREANALYZE 0x1c
+#define DIF_NEWDEVICEWIZARD_POSTANALYZE 0x1d
+#define DIF_NEWDEVICEWIZARD_FINISHINSTALL 0x1e
+#define DIF_UNUSED1 0x1f
+#define DIF_INSTALLINTERFACES 0x20
+#define DIF_DETECTCANCEL 0x21
+#define DIF_REGISTER_COINSTALLERS 0x22
+#define DIF_ADDPROPERTYPAGE_ADVANCED 0x23
+#define DIF_ADDPROPERTYPAGE_BASIC 0x24
+#define DIF_RESERVED1 0x25
+#define DIF_TROUBLESHOOTER 0x26
+#define DIF_POWERMESSAGEWAKE 0x27
+#define DIF_ADDREMOTEPROPERTYPAGE_ADVANCED 0x28
+#define DIF_UPDATEDRIVER_UI 0x29
+#define DIF_RESERVED2 0x30
+
+/* Directory ids */
+#define DIRID_ABSOLUTE (-1)
+#define DIRID_ABSOLUTE_16BIT 0xffff
+#define DIRID_NULL 0
+#define DIRID_SRCPATH 1
+#define DIRID_WINDOWS 10
+#define DIRID_SYSTEM 11
+#define DIRID_DRIVERS 12
+#define DIRID_IOSUBSYS DIRID_DRIVERS
+#define DIRID_INF 17
+#define DIRID_HELP 18
+#define DIRID_FONTS 20
+#define DIRID_VIEWERS 21
+#define DIRID_COLOR 23
+#define DIRID_APPS 24
+#define DIRID_SHARED 25
+#define DIRID_BOOT 30
+#define DIRID_SYSTEM16 50
+#define DIRID_SPOOL 51
+#define DIRID_SPOOLDRIVERS 52
+#define DIRID_USERPROFILE 53
+#define DIRID_LOADER 54
+#define DIRID_PRINTPROCESSOR 55
+#define DIRID_DEFAULT DIRID_SYSTEM
+
+#define DIRID_COMMON_STARTMENU 16406
+#define DIRID_COMMON_PROGRAMS 16407
+#define DIRID_COMMON_STARTUP 16408
+#define DIRID_COMMON_DESKTOPDIRECTORY 16409
+#define DIRID_COMMON_FAVORITES 16415
+#define DIRID_COMMON_APPDATA 16419
+#define DIRID_PROGRAM_FILES 16422
+#define DIRID_SYSTEM_X86 16425
+#define DIRID_PROGRAM_FILES_X86 16426
+#define DIRID_PROGRAM_FILES_COMMON 16427
+#define DIRID_PROGRAM_FILES_COMMONX86 16428
+#define DIRID_COMMON_TEMPLATES 16429
+#define DIRID_COMMON_DOCUMENTS 16430
+
+#define DIRID_USER 0x8000
+
+
+/* Error code */
+
+#define ERROR_EXPECTED_SECTION_NAME (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0)
+#define ERROR_BAD_SECTION_NAME_LINE (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|1)
+#define ERROR_SECTION_NAME_TOO_LONG (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|2)
+#define ERROR_GENERAL_SYNTAX (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|3)
+#define ERROR_WRONG_INF_STYLE (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x100)
+#define ERROR_SECTION_NOT_FOUND (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x101)
+#define ERROR_LINE_NOT_FOUND (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x102)
+#define ERROR_NO_BACKUP (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x103)
+#define ERROR_NO_ASSOCIATED_CLASS (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x200)
+#define ERROR_CLASS_MISMATCH (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x201)
+#define ERROR_DUPLICATE_FOUND (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x202)
+#define ERROR_NO_DRIVER_SELECTED (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x203)
+#define ERROR_KEY_DOES_NOT_EXIST (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x204)
+#define ERROR_INVALID_DEVINST_NAME (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x205)
+#define ERROR_INVALID_CLASS (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x206)
+#define ERROR_DEVINST_ALREADY_EXISTS (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x207)
+#define ERROR_DEVINFO_NOT_REGISTERED (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x208)
+#define ERROR_INVALID_REG_PROPERTY (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x209)
+#define ERROR_NO_INF (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x20A)
+#define ERROR_NO_SUCH_DEVINST (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x20B)
+#define ERROR_CANT_LOAD_CLASS_ICON (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x20C)
+#define ERROR_INVALID_CLASS_INSTALLER (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x20D)
+#define ERROR_DI_DO_DEFAULT (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x20E)
+#define ERROR_DI_NOFILECOPY (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x20F)
+#define ERROR_INVALID_HWPROFILE (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x210)
+#define ERROR_NO_DEVICE_SELECTED (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x211)
+#define ERROR_DEVINFO_LIST_LOCKED (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x212)
+#define ERROR_DEVINFO_DATA_LOCKED (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x213)
+#define ERROR_DI_BAD_PATH (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x214)
+#define ERROR_NO_CLASSINSTALL_PARAMS (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x215)
+#define ERROR_FILEQUEUE_LOCKED (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x216)
+#define ERROR_BAD_SERVICE_INSTALLSECT (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x217)
+#define ERROR_NO_CLASS_DRIVER_LIST (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x218)
+#define ERROR_NO_ASSOCIATED_SERVICE (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x219)
+#define ERROR_NO_DEFAULT_DEVICE_INTERFACE (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x21A)
+#define ERROR_DEVICE_INTERFACE_ACTIVE (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x21B)
+#define ERROR_DEVICE_INTERFACE_REMOVED (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x21C)
+#define ERROR_BAD_INTERFACE_INSTALLSECT (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x21D)
+#define ERROR_NO_SUCH_INTERFACE_CLASS (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x21E)
+#define ERROR_INVALID_REFERENCE_STRING (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x21F)
+#define ERROR_INVALID_MACHINENAME (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x220)
+#define ERROR_REMOTE_COMM_FAILURE (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x221)
+#define ERROR_MACHINE_UNAVAILABLE (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x222)
+#define ERROR_NO_CONFIGMGR_SERVICES (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x223)
+#define ERROR_INVALID_PROPPAGE_PROVIDER (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x224)
+#define ERROR_NO_SUCH_DEVICE_INTERFACE (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x225)
+#define ERROR_DI_POSTPROCESSING_REQUIRED (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x226)
+#define ERROR_INVALID_COINSTALLER (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x227)
+#define ERROR_NO_COMPAT_DRIVERS (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x228)
+#define ERROR_NO_DEVICE_ICON (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x229)
+#define ERROR_INVALID_INF_LOGCONFIG (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x22A)
+#define ERROR_DI_DONT_INSTALL (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x22B)
+#define ERROR_INVALID_FILTER_DRIVER (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x22C)
+#define ERROR_NON_WINDOWS_NT_DRIVER (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x22D)
+#define ERROR_NON_WINDOWS_DRIVER (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x22E)
+#define ERROR_NO_CATALOG_FOR_OEM_INF (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x22F)
+#define ERROR_DEVINSTALL_QUEUE_NONNATIVE (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x230)
+#define ERROR_NOT_DISABLEABLE (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x231)
+#define ERROR_CANT_REMOVE_DEVINST (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x232)
+#define ERROR_INVALID_TARGET (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x233)
+#define ERROR_DRIVER_NONNATIVE (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x234)
+#define ERROR_IN_WOW64 (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x235)
+#define ERROR_SET_SYSTEM_RESTORE_POINT (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x236)
+#define ERROR_INCORRECTLY_COPIED_INF (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x237)
+#define ERROR_SCE_DISABLED (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x238)
+#define ERROR_NO_DEFAULT_INTERFACE_DEVICE ERROR_NO_DEFAULT_DEVICE_INTERFACE
+#define ERROR_INTERFACE_DEVICE_ACTIVE ERROR_DEVICE_INTERFACE_ACTIVE
+#define ERROR_INTERFACE_DEVICE_REMOVED ERROR_DEVICE_INTERFACE_REMOVED
+#define ERROR_NO_SUCH_INTERFACE_DEVICE ERROR_NO_SUCH_DEVICE_INTERFACE
+#define ERROR_NOT_INSTALLED (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x1000)
+
+HINF WINAPI SetupOpenInfFileA( PCSTR name, PCSTR class, DWORD style, UINT *error );
+HINF WINAPI SetupOpenInfFileW( PCWSTR name, PCWSTR class, DWORD style, UINT *error );
+#define SetupOpenInfFile WINELIB_NAME_AW(SetupOpenInfFile)
+BOOL WINAPI SetupOpenAppendInfFileA( PCSTR, HINF, UINT * );
+BOOL WINAPI SetupOpenAppendInfFileW( PCWSTR, HINF, UINT * );
+#define SetupOpenAppendInfFile WINELIB_NAME_AW(SetupOpenAppendInfFile)
+void WINAPI SetupCloseInfFile( HINF hinf );
+BOOL WINAPI SetupGetLineByIndexA( HINF, PCSTR, DWORD, INFCONTEXT * );
+BOOL WINAPI SetupGetLineByIndexW( HINF, PCWSTR, DWORD, INFCONTEXT * );
+#define SetupGetLineByIndex WINELIB_NAME_AW(SetupGetLineByIndex)
+LONG WINAPI SetupGetLineCountA( HINF hinf, PCSTR section );
+LONG WINAPI SetupGetLineCountW( HINF hinf, PCWSTR section );
+#define SetupGetLineCount WINELIB_NAME_AW(SetupGetLineCount)
+BOOL WINAPI SetupFindFirstLineA( HINF hinf, PCSTR section, PCSTR key, INFCONTEXT *context );
+BOOL WINAPI SetupFindFirstLineW( HINF hinf, PCWSTR section, PCWSTR key, INFCONTEXT *context );
+#define SetupFindFirstLine WINELIB_NAME_AW(SetupFindFirstLine)
+BOOL WINAPI SetupFindNextLine( const INFCONTEXT *, INFCONTEXT * );
+BOOL WINAPI SetupFindNextMatchLineA( const INFCONTEXT *, PCSTR, INFCONTEXT * );
+BOOL WINAPI SetupFindNextMatchLineW( const INFCONTEXT *, PCWSTR, INFCONTEXT * );
+#define SetupFindNextMatchLine WINELIB_NAME_AW(SetupFindNextMatchLine)
+BOOL WINAPI SetupGetLineTextA( const INFCONTEXT *, HINF, PCSTR, PCSTR, PSTR, DWORD, DWORD * );
+BOOL WINAPI SetupGetLineTextW( const INFCONTEXT *, HINF, PCWSTR, PCWSTR, PWSTR, DWORD, DWORD * );
+#define SetupGetLineText WINELIB_NAME_AW(SetupGetLineText)
+DWORD WINAPI SetupGetFieldCount( const INFCONTEXT * );
+BOOL WINAPI SetupGetIntField( const INFCONTEXT *, DWORD, INT * );
+BOOL WINAPI SetupGetStringFieldA( const INFCONTEXT *, DWORD, PSTR, DWORD, DWORD * );
+BOOL WINAPI SetupGetStringFieldW( const INFCONTEXT *, DWORD, PWSTR, DWORD, DWORD * );
+#define SetupGetStringField WINELIB_NAME_AW(SetupGetStringField)
+BOOL WINAPI SetupGetBinaryField( const INFCONTEXT *, DWORD, BYTE *, DWORD, DWORD * );
+BOOL WINAPI SetupGetMultiSzFieldA( const INFCONTEXT *, DWORD, PSTR, DWORD, DWORD * );
+BOOL WINAPI SetupGetMultiSzFieldW( const INFCONTEXT *, DWORD, PWSTR, DWORD, DWORD * );
+#define SetupGetMultiSzField WINELIB_NAME_AW(SetupGetMultiSzField)
+BOOL WINAPI SetupSetDirectoryIdA( HINF, DWORD, PCSTR );
+BOOL WINAPI SetupSetDirectoryIdW( HINF, DWORD, PCWSTR );
+#define SetupSetDirectoryId WINELIB_NAME_AW(SetupSetDirectoryId)
+HSPFILEQ WINAPI SetupOpenFileQueue(void);
+BOOL WINAPI SetupCloseFileQueue( HSPFILEQ );
+BOOL WINAPI SetupSetFileQueueAlternatePlatformA( HSPFILEQ, PSP_ALTPLATFORM_INFO, PCSTR );
+BOOL WINAPI SetupSetFileQueueAlternatePlatformW( HSPFILEQ, PSP_ALTPLATFORM_INFO, PCWSTR );
+#define SetupSetFileQueueAlternatePlatform WINELIB_NAME_AW(SetupSetFileQueueAlternatePlatform)
+BOOL WINAPI SetupQueueCopyA(HSPFILEQ,PCSTR,PCSTR,PCSTR,PCSTR,PCSTR,PCSTR,PCSTR,DWORD);
+BOOL WINAPI SetupQueueCopyW(HSPFILEQ,PCWSTR,PCWSTR,PCWSTR,PCWSTR,PCWSTR,PCWSTR,PCWSTR,DWORD);
+#define SetupQueueCopy WINELIB_NAME_AW(SetupQueueCopy)
+BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A );
+BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W );
+#define SetupQueueCopyIndirect WINELIB_NAME_AW(SetupQueueCopyIndirect)
+BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ, HINF, PCSTR, PCSTR, PCSTR, DWORD );
+BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ, HINF, PCWSTR, PCWSTR, PCWSTR, DWORD );
+#define SetupQueueDefaultCopy WINELIB_NAME_AW(SetupQueueDefaultCopy)
+BOOL WINAPI SetupQueueDeleteA( HSPFILEQ, PCSTR, PCSTR );
+BOOL WINAPI SetupQueueDeleteW( HSPFILEQ, PCWSTR, PCWSTR );
+#define SetupQueueDelete WINELIB_NAME_AW(SetupQueueDelete)
+BOOL WINAPI SetupQueueRenameA( HSPFILEQ, PCSTR, PCSTR, PCSTR, PCSTR );
+BOOL WINAPI SetupQueueRenameW( HSPFILEQ, PCWSTR, PCWSTR, PCWSTR, PCWSTR );
+#define SetupQueueRename WINELIB_NAME_AW(SetupQueueRename)
+BOOL WINAPI SetupCommitFileQueueA( HWND, HSPFILEQ, PSP_FILE_CALLBACK_A, PVOID );
+BOOL WINAPI SetupCommitFileQueueW( HWND, HSPFILEQ, PSP_FILE_CALLBACK_W, PVOID );
+#define SetupCommitFileQueue WINELIB_NAME_AW(SetupCommitFileQueue)
+BOOL WINAPI SetupScanFileQueueA( HSPFILEQ, DWORD, HWND, PSP_FILE_CALLBACK_A, PVOID, PDWORD );
+BOOL WINAPI SetupScanFileQueueW( HSPFILEQ, DWORD, HWND, PSP_FILE_CALLBACK_W, PVOID, PDWORD );
+#define SetupScanFileQueue WINELIB_NAME_AW(SetupScanFileQueue)
+BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ, UINT, PUINT );
+BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ, PDWORD );
+BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ, DWORD, DWORD );
+BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ, PCSTR, HINF, HINF, PCSTR, DWORD );
+BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ, PCWSTR, HINF, HINF, PCWSTR, DWORD );
+#define SetupQueueCopySection WINELIB_NAME_AW(SetupQueueCopySection)
+BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ, HINF, HINF, PCSTR );
+BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ, HINF, HINF, PCWSTR );
+#define SetupQueueDeleteSection WINELIB_NAME_AW(SetupQueueDeleteSection)
+BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ, HINF, HINF, PCSTR );
+BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ, HINF, HINF, PCWSTR );
+#define SetupQueueRenameSection WINELIB_NAME_AW(SetupQueueRenameSection)
+PVOID WINAPI SetupInitDefaultQueueCallback( HWND );
+PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND, HWND, UINT, DWORD, PVOID );
+void WINAPI SetupTermDefaultQueueCallback( PVOID );
+UINT WINAPI SetupDefaultQueueCallbackA( PVOID, UINT, UINT_PTR, UINT_PTR );
+UINT WINAPI SetupDefaultQueueCallbackW( PVOID, UINT, UINT_PTR, UINT_PTR );
+#define SetupDefaultQueueCallback WINELIB_NAME_AW(SetupDefaultQueueCallback)
+BOOL WINAPI SetupInstallFilesFromInfSectionA( HINF, HINF, HSPFILEQ, PCSTR, PCSTR, UINT );
+BOOL WINAPI SetupInstallFilesFromInfSectionW( HINF, HINF, HSPFILEQ, PCWSTR, PCWSTR, UINT );
+#define SetupInstallFilesFromInfSection WINELIB_NAME_AW(SetupInstallFilesFromInfSection)
+BOOL WINAPI SetupInstallFromInfSectionA(HWND,HINF,PCSTR,UINT,HKEY,PCSTR,UINT,
+ PSP_FILE_CALLBACK_A,PVOID,HDEVINFO,PSP_DEVINFO_DATA);
+BOOL WINAPI SetupInstallFromInfSectionW(HWND,HINF,PCWSTR,UINT,HKEY,PCWSTR,UINT,
+ PSP_FILE_CALLBACK_W,PVOID,HDEVINFO,PSP_DEVINFO_DATA);
+#define SetupInstallFromInfSection WINELIB_NAME_AW(SetupInstallFromInfSection)
+
+
+#endif /* _INC_SETUPAPI */
diff --git a/include/winnt.h b/include/winnt.h
index a8d9a80..76976e8 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -212,6 +212,13 @@
#define OPTIONAL
#endif
+/* Error Masks */
+#define APPLICATION_ERROR_MASK 0x20000000
+#define ERROR_SEVERITY_SUCCESS 0x00000000
+#define ERROR_SEVERITY_INFORMATIONAL 0x40000000
+#define ERROR_SEVERITY_WARNING 0x80000000
+#define ERROR_SEVERITY_ERROR 0xC0000000
+
/* Standard data types */
typedef const void *PCVOID, *LPCVOID;
typedef int BOOL, *PBOOL, *LPBOOL;