Started porting Setupapi.dll from WINE to ReactOS.

svn path=/trunk/; revision=7863
This commit is contained in:
Steven Edwards 2004-01-24 15:39:47 +00:00
parent 7fd96c83a7
commit ed4bb6a2cd
19 changed files with 8056 additions and 0 deletions

View file

@ -0,0 +1,22 @@
/*
* Compatibility header
*
* This header is wrapper to allow compilation of Wine DLLs under ReactOS
* build system. It contains definitions commonly refered to as Wineisms
* and definitions that are missing in w32api.
*/
#ifndef __WINE_SETUPAPI_H
#define __WINE_SETUPAPI_H
#include_next <setupapi.h>
#define FLG_ADDREG_DELREG_BIT 0x00008000
#define FLG_DELREG_KEYONLY_COMMON FLG_ADDREG_KEYONLY_COMMON
#define FLG_DELREG_MULTI_SZ_DELSTRING (FLG_DELREG_TYPE_MULTI_SZ | FLG_ADDREG_DELREG_BIT | 0x00000002)
#define FLG_DELREG_TYPE_MULTI_SZ FLG_ADDREG_TYPE_MULTI_SZ
#define FLG_ADDREG_KEYONLY_COMMON 0x00002000
#define FLG_ADDREG_DELREG_BIT 0x00008000
#define SPINST_COPYINF 0x00000200
#endif /* __WINE_SETUPAPI_H */

View file

@ -0,0 +1,32 @@
EXTRADEFS = -D_SETUPAPI_
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = setupapi.dll
IMPORTS = user32 version advapi32 kernel32 ntdll
ALTNAMES = setupx.dll
EXTRALIBS = $(LIBUNICODE)
SPEC_SRCS16 = $(ALTNAMES:.dll=.spec)
C_SRCS = \
devinst.c \
dirid.c \
install.c \
parser.c \
queue.c \
setupcab.c \
stubs.c
C_SRCS16 = \
devinst16.c \
infparse.c \
setupx_main.c \
virtcopy.c
RC_SRCS= setupapi.rc
@MAKE_DLL_RULES@
### Dependencies:

View file

@ -0,0 +1,21 @@
# $Id: Makefile.ros-template,v 1.1 2004/01/24 15:39:18 sedwards Exp $
TARGET_NAME = setupapi
TARGET_OBJECTS = @C_SRCS@
TARGET_CFLAGS = @EXTRADEFS@ -D__REACTOS__
TARGET_SDKLIBS = @IMPORTS@ libwine.a ntdll.a libwine_unicode.a
TARGET_BASE = 0x76160000
TARGET_RC_SRCS = @RC_SRCS@
TARGET_RC_BINSRC = @RC_BINSRC@
TARGET_RC_BINARIES = @RC_BINARIES@
default: all
DEP_OBJECTS = $(TARGET_OBJECTS)
include $(TOOLS_PATH)/depend.mk

View file

@ -0,0 +1,149 @@
/*
* SetupAPI device installer
*
* Copyright 2000 Andreas Mohr 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 <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "winreg.h"
#include "setupapi.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
/***********************************************************************
* SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
HDEVINFO DeviceInfoSet,
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
DWORD DeviceInterfaceDetailDataSize,
PDWORD RequiredSize,
PSP_DEVINFO_DATA DeviceInfoData )
{
FIXME("\n");
return FALSE;
}
/***********************************************************************
* SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
HDEVINFO DeviceInfoSet,
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
DWORD DeviceInterfaceDetailDataSize,
PDWORD RequiredSize,
PSP_DEVINFO_DATA DeviceInfoData )
{
FIXME("\n");
return FALSE;
}
/***********************************************************************
* SetupDiEnumDeviceInterfaces (SETUPAPI.@)
*/
BOOL WINAPI SetupDiEnumDeviceInterfaces(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
CONST GUID * InterfaceClassGuid,
DWORD MemberIndex,
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
{
FIXME("\n");
return FALSE;
}
/***********************************************************************
* SetupDiGetClassDevsA (SETUPAPI.@)
*/
HDEVINFO WINAPI SetupDiGetClassDevsA(
CONST GUID *class,
LPCSTR enumstr,
HWND parent,
DWORD flags)
{
FIXME("%s %s %p %08lx\n",debugstr_guid(class),enumstr,parent,flags);
return (HDEVINFO) INVALID_HANDLE_VALUE;
}
/***********************************************************************
* SetupDiGetClassDevsW (SETUPAPI.@)
*/
HDEVINFO WINAPI SetupDiGetClassDevsW(
CONST GUID *class,
LPCWSTR enumstr,
HWND parent,
DWORD flags)
{
FIXME("%s %s %p %08lx\n",debugstr_guid(class),debugstr_w(enumstr),parent,flags);
return (HDEVINFO) INVALID_HANDLE_VALUE;
}
/***********************************************************************
* SetupDiEnumDeviceInfo (SETUPAPI.@)
*/
BOOL WINAPI SetupDiEnumDeviceInfo(
HDEVINFO devinfo,
DWORD index,
PSP_DEVINFO_DATA info)
{
FIXME("%p %ld %p\n", devinfo, index, info );
if(info==NULL)
return FALSE;
if(info->cbSize < sizeof(*info))
return FALSE;
return FALSE;
}
/***********************************************************************
* SetupDiDestroyDeviceInfoList (SETUPAPI.@)
*/
BOOL WINAPI SetupDiDestroyDeviceInfoList( HDEVINFO devinfo )
{
FIXME("%04lx\n", (DWORD)devinfo);
return FALSE;
}
/***********************************************************************
* SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
HDEVINFO devinfo,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Property,
PDWORD PropertyRegDataType,
PBYTE PropertyBuffer,
DWORD PropertyBufferSize,
PDWORD RequiredSize)
{
FIXME("%04lx %p %ld %p %p %ld %p\n", (DWORD)devinfo, DeviceInfoData,
Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
RequiredSize);
return FALSE;
}

View file

@ -0,0 +1,124 @@
/*
* SetupAPI device installer
*
* Copyright 2000 Andreas Mohr 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 <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "setupx16.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
/***********************************************************************
* DiGetClassDevs (SETUPX.304)
* Return a list of installed system devices.
* Uses HKLM\\ENUM to list devices.
*/
RETERR16 WINAPI DiGetClassDevs16(LPLPDEVICE_INFO16 lplpdi,
LPCSTR lpszClassName, HWND16 hwndParent, INT16 iFlags)
{
LPDEVICE_INFO16 lpdi;
FIXME("(%p, '%s', %04x, %04x), semi-stub.\n",
lplpdi, lpszClassName, hwndParent, iFlags);
lpdi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DEVICE_INFO16));
lpdi->cbSize = sizeof(DEVICE_INFO16);
*lplpdi = (LPDEVICE_INFO16)MapLS(lpdi);
return OK;
}
/***********************************************************************
* DiBuildCompatDrvList (SETUPX.300)
*/
RETERR16 WINAPI DiBuildCompatDrvList16(LPDEVICE_INFO16 lpdi)
{
FIXME("(%p): stub\n", lpdi);
lpdi->lpCompatDrvList = NULL;
return FALSE;
}
/***********************************************************************
* DiCallClassInstaller (SETUPX.308)
*/
RETERR16 WINAPI DiCallClassInstaller16(/*DI_FUNCTIONS*/WORD diFctn, LPDEVICE_INFO16 lpdi)
{
FIXME("(%x, %p): stub\n", diFctn, lpdi);
return FALSE;
}
/***********************************************************************
* DiCreateDevRegKey (SETUPX.318)
*/
RETERR16 WINAPI DiCreateDevRegKey16(LPDEVICE_INFO16 lpdi,
VOID* p2, WORD w3,
LPCSTR s4, WORD w5)
{
FIXME("(%p, %p, %x, %s, %x): stub\n", lpdi, p2, w3, debugstr_a(s4), w5);
return FALSE;
}
/***********************************************************************
* DiDeleteDevRegKey (SETUPX.344)
*/
RETERR16 WINAPI DiDeleteDevRegKey16(LPDEVICE_INFO16 lpdi, INT16 iFlags)
{
FIXME("(%p, %x): stub\n", lpdi, iFlags);
return FALSE;
}
/***********************************************************************
* DiCreateDeviceInfo (SETUPX.303)
*/
RETERR16 WINAPI DiCreateDeviceInfo16(LPLPDEVICE_INFO16 lplpdi,
LPCSTR lpszDescription, DWORD dnDevnode,
HKEY16 hkey, LPCSTR lpszRegsubkey,
LPCSTR lpszClassName, HWND16 hwndParent)
{
LPDEVICE_INFO16 lpdi;
FIXME("(%p %s %08lx %x %s %s %x): stub\n", lplpdi,
debugstr_a(lpszDescription), dnDevnode, hkey,
debugstr_a(lpszRegsubkey), debugstr_a(lpszClassName), hwndParent);
lpdi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DEVICE_INFO16));
lpdi->cbSize = sizeof(DEVICE_INFO16);
strcpy(lpdi->szClassName, lpszClassName);
lpdi->hwndParent = hwndParent;
*lplpdi = (LPDEVICE_INFO16)MapLS(lpdi);
return OK;
}
/***********************************************************************
* DiDestroyDeviceInfoList (SETUPX.305)
*/
RETERR16 WINAPI DiDestroyDeviceInfoList16(LPDEVICE_INFO16 lpdi)
{
FIXME("(%p): stub\n", lpdi);
return FALSE;
}
/***********************************************************************
* DiOpenDevRegKey (SETUPX.319)
*/
RETERR16 WINAPI DiOpenDevRegKey16(LPDEVICE_INFO16 lpdi,
LPHKEY16 lphk,INT16 iFlags)
{
FIXME("(%p %p %d): stub\n", lpdi, lphk, iFlags);
return FALSE;
}

View file

@ -0,0 +1,260 @@
/*
* 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 "config.h"
#include "wine/port.h"
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winternl.h"
#include "winerror.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.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( "unknown 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;
if (user_dirids)
new = HeapReAlloc( GetProcessHeap(), 0, user_dirids,
new_size * sizeof(*new) );
else
new = HeapAlloc( GetProcessHeap(), 0,
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;
}
/***********************************************************************
* SetupSetDirectoryIdA (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 );
}

View file

@ -0,0 +1,198 @@
/*
* SetupX .inf file parsing functions
*
* Copyright 2000 Andreas Mohr 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
*
* FIXME:
* - return values ???
* - this should be reimplemented at some point to have its own
* file parsing instead of using profile functions,
* as some SETUPX exports probably demand that
* (IpSaveRestorePosition, IpFindNextMatchLine, ...).
*/
#include <stdarg.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winternl.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.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) FIXME( "unsupported flag: GENINSTALL_DO_REGSRCPATH\n" );
if (genflags & GENINSTALL_DO_CFGAUTO) FIXME( "unsupported flag: GENINSTALL_DO_CFGAUTO\n" );
if (genflags & GENINSTALL_DO_PERUSER) FIXME( "unsupported flag: GENINSTALL_DO_PERUSER\n" );
context = SetupInitDefaultQueueCallback( 0 );
if (!SetupInstallFromInfSectionA( 0, hinf, section, flags, 0, NULL,
SP_COPY_NEWER_OR_SAME, SetupDefaultQueueCallbackA,
context, 0, 0 ))
ret = get_last_error();
SetupTermDefaultQueueCallback( context );
return ret;
}

View file

@ -0,0 +1,675 @@
/*
* 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 "config.h"
#include "wine/port.h"
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winternl.h"
#include "winerror.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "setupapi.h"
#include "setupapi_private.h"
#include "wine/unicode.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 ? strtoulW( 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 %p %s\n", root_key, debugstr_w(buffer) );
continue;
}
TRACE( "key %p %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 )
{
INFCONTEXT context;
BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
for (; ok; ok = SetupFindNextLine( &context, &context ))
{
WCHAR buffer[MAX_INF_STRING_LENGTH];
WCHAR filename[MAX_INF_STRING_LENGTH];
WCHAR section[MAX_INF_STRING_LENGTH];
WCHAR entry[MAX_INF_STRING_LENGTH];
WCHAR string[MAX_INF_STRING_LENGTH];
LPWSTR divider;
if (!SetupGetStringFieldW( &context, 1, filename,
sizeof(filename)/sizeof(WCHAR), NULL ))
continue;
if (!SetupGetStringFieldW( &context, 2, section,
sizeof(section)/sizeof(WCHAR), NULL ))
continue;
if (!SetupGetStringFieldW( &context, 4, buffer,
sizeof(buffer)/sizeof(WCHAR), NULL ))
continue;
divider = strchrW(buffer,'=');
if (divider)
{
*divider = 0;
strcpyW(entry,buffer);
divider++;
strcpyW(string,divider);
}
else
{
strcpyW(entry,buffer);
string[0]=0;
}
TRACE("Writing %s = %s in %s of file %s\n",debugstr_w(entry),
debugstr_w(string),debugstr_w(section),debugstr_w(filename));
WritePrivateProfileStringW(section,entry,string,filename);
}
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( &sectionW, 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( &sectionW );
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( &sectionW, 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( &sectionW );
}
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 = TRUE;
if (!iterate_section_fields( hinf, section, DelReg, registry_callback, &info ))
return FALSE;
info.delete = FALSE;
if (!iterate_section_fields( hinf, section, AddReg, 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;
}

View file

@ -0,0 +1,9 @@
# $Id: makefile,v 1.1 2004/01/24 15:39:18 sedwards Exp $
PATH_TO_TOP = ../..
TARGET_TYPE = winedll
include $(PATH_TO_TOP)/rules.mak
include $(TOOLS_PATH)/helper.mk

File diff suppressed because it is too large Load diff

1376
reactos/lib/setupapi/queue.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,38 @@
#include <defines.h>
#include <reactos/resource.h>
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO
FILEVERSION RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD
PRODUCTVERSION RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", RES_STR_COMPANY_NAME
VALUE "FileDescription", "WINE IMM32 API Client DLL\0"
VALUE "FileVersion", RES_STR_FILE_VERSION
VALUE "InternalName", "imm32\0"
VALUE "LegalCopyright", RES_STR_LEGAL_COPYRIGHT
VALUE "OriginalFilename", "imm32.dll\0"
VALUE "ProductName", RES_STR_PRODUCT_NAME
VALUE "ProductVersion", RES_STR_PRODUCT_VERSION
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

View file

@ -0,0 +1,329 @@
@ stdcall CM_Connect_MachineW(wstr ptr)
@ stdcall CM_Disconnect_Machine(long)
@ stub CM_Free_Log_Conf_Handle
@ stub CM_Free_Res_Des_Handle
@ stub CM_Get_DevNode_Status_Ex
@ stub CM_Get_Device_ID_ExW
@ stub CM_Get_First_Log_Conf_Ex
@ stub CM_Get_Next_Res_Des_Ex
@ stub CM_Get_Res_Des_Data_Ex
@ stub CM_Get_Res_Des_Data_Size_Ex
@ stub CM_Locate_DevNode_ExW
@ stub CM_Reenumerate_DevNode_Ex
@ 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
@ stdcall InstallHinfSection(long long str long)
@ 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)
@ stdcall SetupCloseInfFile(long)
@ stub SetupCommitFileQueue
@ stdcall SetupCommitFileQueueA(long long ptr ptr)
@ stdcall SetupCommitFileQueueW(long long ptr ptr)
@ stub SetupCopyErrorA
@ stub SetupCopyErrorW
@ stdcall SetupCopyOEMInfA(str str long long ptr long ptr ptr)
@ stub SetupCopyOEMInfW
@ stub SetupCreateDiskSpaceListA
@ stub SetupCreateDiskSpaceListW
@ stub SetupDecompressOrCopyFileA
@ stub SetupDecompressOrCopyFileW
@ stub SetupDefaultQueueCallback
@ stdcall SetupDefaultQueueCallbackA(ptr long long long)
@ stdcall SetupDefaultQueueCallbackW(ptr long long long)
@ stub SetupDeleteErrorA
@ stub SetupDeleteErrorW
@ stub SetupDestroyDiskSpaceList
@ stub SetupDiAskForOEMDisk
@ stub SetupDiBuildClassInfoList
@ stdcall SetupDiBuildClassInfoListExW(long ptr long ptr wstr ptr)
@ stub SetupDiBuildDriverInfoList
@ stub SetupDiCallClassInstaller
@ stub SetupDiCancelDriverInfoSearch
@ stub SetupDiChangeState
@ stub SetupDiClassGuidsFromNameA
@ stdcall SetupDiClassGuidsFromNameExW(wstr ptr long ptr wstr ptr)
@ stub SetupDiClassGuidsFromNameW
@ stub SetupDiClassNameFromGuidA
@ stdcall SetupDiClassNameFromGuidExW(ptr ptr long ptr wstr ptr)
@ stub SetupDiClassNameFromGuidW
@ stub SetupDiCreateDevRegKeyA
@ stub SetupDiCreateDevRegKeyW
@ stub SetupDiCreateDeviceInfoA
@ stdcall SetupDiCreateDeviceInfoList(ptr ptr)
@ stdcall SetupDiCreateDeviceInfoListExW(ptr long str ptr)
@ stub SetupDiCreateDeviceInfoW
@ stub SetupDiDeleteDevRegKey
@ stub SetupDiDeleteDeviceInfo
@ stub SetupDiDestroyClassImageList
@ stdcall SetupDiDestroyDeviceInfoList(long)
@ stub SetupDiDestroyDriverInfoList
@ stub SetupDiDrawMiniIcon
@ stdcall SetupDiEnumDeviceInfo(long long ptr)
@ stdcall SetupDiEnumDeviceInterfaces(long ptr ptr long ptr)
@ stub SetupDiEnumDriverInfoA
@ stub SetupDiEnumDriverInfoW
@ stub SetupDiGetActualSectionToInstallA
@ stub SetupDiGetActualSectionToInstallW
@ stub SetupDiGetClassBitmapIndex
@ stub SetupDiGetClassDescriptionA
@ stdcall SetupDiGetClassDescriptionExW(ptr ptr long ptr wstr ptr)
@ stub SetupDiGetClassDescriptionW
@ stub SetupDiGetClassDevPropertySheetsA
@ stub SetupDiGetClassDevPropertySheetsW
@ stdcall SetupDiGetClassDevsA(ptr ptr long long)
@ stdcall SetupDiGetClassDevsExA(ptr str ptr long ptr str ptr)
@ stdcall SetupDiGetClassDevsExW(ptr wstr ptr long ptr wstr ptr)
@ stdcall SetupDiGetClassDevsW(ptr ptr long long)
@ stub SetupDiGetClassImageIndex
@ stub SetupDiGetClassImageList
@ stub SetupDiGetClassImageListExW
@ stub SetupDiGetClassInstallParamsA
@ stub SetupDiGetClassInstallParamsW
@ stub SetupDiGetDeviceInfoListClass
@ stdcall SetupDiGetDeviceInfoListDetailA(ptr ptr)
@ stdcall SetupDiGetDeviceInfoListDetailW(ptr ptr)
@ stub SetupDiGetDeviceInstallParamsA
@ stub SetupDiGetDeviceInstallParamsW
@ stub SetupDiGetDeviceInstanceIdA
@ stub SetupDiGetDeviceInstanceIdW
@ stdcall SetupDiGetDeviceRegistryPropertyA(long ptr long ptr ptr long ptr)
@ stub SetupDiGetDeviceRegistryPropertyW
@ stub SetupDiGetDriverInfoDetailA
@ stub SetupDiGetDriverInfoDetailW
@ stub SetupDiGetDriverInstallParamsA
@ stub SetupDiGetDriverInstallParamsW
@ stub SetupDiGetDeviceInterfaceAlias
@ stdcall SetupDiGetDeviceInterfaceDetailA(long ptr ptr long ptr ptr)
@ stdcall SetupDiGetDeviceInterfaceDetailW(long ptr ptr long ptr ptr)
@ 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
@ stdcall SetupDiOpenClassRegKeyExW(ptr long long wstr ptr)
@ stub SetupDiOpenDevRegKey
@ stub SetupDiOpenDeviceInfoA
@ stub SetupDiOpenDeviceInfoW
@ stub SetupDiOpenDeviceInterfaceRegKey
@ 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)
@ stdcall SetupFindFirstLineW(long wstr wstr ptr)
@ stdcall SetupFindNextLine(ptr ptr)
@ stdcall SetupFindNextMatchLineA(ptr str ptr)
@ stdcall SetupFindNextMatchLineW(ptr wstr ptr)
@ stub SetupFreeSourceListA
@ stub SetupFreeSourceListW
@ stdcall SetupGetBinaryField(ptr long ptr long ptr)
@ stdcall SetupGetFieldCount(ptr)
@ stub SetupGetFileCompressionInfoA
@ stub SetupGetFileCompressionInfoW
@ stdcall SetupGetFileQueueCount(long long ptr)
@ stdcall SetupGetFileQueueFlags(long ptr)
@ stub SetupGetInfFileListA
@ stub SetupGetInfFileListW
@ stub SetupGetInfInformationA
@ stub SetupGetInfInformationW
@ stdcall SetupGetIntField(ptr long ptr)
@ stdcall SetupGetLineByIndexA(long str long ptr)
@ stdcall SetupGetLineByIndexW(long wstr long ptr)
@ stdcall SetupGetLineCountA(long str)
@ stdcall SetupGetLineCountW(long wstr)
@ stdcall SetupGetLineTextA(ptr long str str ptr long ptr)
@ stdcall SetupGetLineTextW(ptr long wstr wstr ptr long ptr)
@ stdcall SetupGetMultiSzFieldA(ptr long ptr long ptr)
@ stdcall SetupGetMultiSzFieldW(ptr long ptr long ptr)
@ stub SetupGetSourceFileLocationA
@ stub SetupGetSourceFileLocationW
@ stub SetupGetSourceFileSizeA
@ stub SetupGetSourceFileSizeW
@ stub SetupGetSourceInfoA
@ stub SetupGetSourceInfoW
@ stdcall SetupGetStringFieldA(ptr long ptr long ptr)
@ stdcall SetupGetStringFieldW(ptr long ptr long ptr)
@ stub SetupGetTargetPathA
@ stub SetupGetTargetPathW
@ stdcall SetupInitDefaultQueueCallback(long)
@ stdcall SetupInitDefaultQueueCallbackEx(long long long long ptr)
@ stub SetupInitializeFileLogA
@ stub SetupInitializeFileLogW
@ stub SetupInstallFileA
@ stub SetupInstallFileExA
@ stub SetupInstallFileExW
@ stub SetupInstallFileW
@ stdcall SetupInstallFilesFromInfSectionA(long long long str str long)
@ stdcall SetupInstallFilesFromInfSectionW(long long long wstr wstr long)
@ stdcall SetupInstallFromInfSectionA(long long str long long str long ptr ptr long ptr)
@ stdcall SetupInstallFromInfSectionW(long long wstr long long wstr long ptr ptr long ptr)
@ stub SetupInstallServicesFromInfSectionA
@ stub SetupInstallServicesFromInfSectionW
@ stdcall SetupIterateCabinetA(str long ptr ptr)
@ stdcall SetupIterateCabinetW(wstr long ptr ptr)
@ stub SetupLogFileA
@ stub SetupLogFileW
@ stdcall SetupOpenAppendInfFileA(str long ptr)
@ stdcall SetupOpenAppendInfFileW(wstr long ptr)
@ stdcall SetupOpenFileQueue()
@ stdcall SetupOpenInfFileA(str str long ptr)
@ stdcall SetupOpenInfFileW(wstr wstr long ptr)
@ 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 SetupQueryInfOriginalFileInformationW
@ stub SetupQuerySourceListA
@ stub SetupQuerySourceListW
@ stub SetupQuerySpaceRequiredOnDriveA
@ stub SetupQuerySpaceRequiredOnDriveW
@ stdcall SetupQueueCopyA(long str str str str str str str long)
@ stdcall SetupQueueCopyIndirectA(ptr)
@ stdcall SetupQueueCopyIndirectW(ptr)
@ stdcall SetupQueueCopySectionA(long str long long str long)
@ stdcall SetupQueueCopySectionW(long wstr long long wstr long)
@ stdcall SetupQueueCopyW(long wstr wstr wstr wstr wstr wstr wstr long)
@ stdcall SetupQueueDefaultCopyA(long long str str str long)
@ stdcall SetupQueueDefaultCopyW(long long wstr wstr wstr long)
@ stdcall SetupQueueDeleteA(long str str)
@ stdcall SetupQueueDeleteSectionA(long long long str)
@ stdcall SetupQueueDeleteSectionW(long long long wstr)
@ stdcall SetupQueueDeleteW(long wstr wstr)
@ stdcall SetupQueueRenameA(long str str str str)
@ stdcall SetupQueueRenameSectionA(long long long str)
@ stdcall SetupQueueRenameSectionW(long long long wstr)
@ stdcall SetupQueueRenameW(long wstr wstr wstr wstr)
@ 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)
@ stdcall SetupScanFileQueueW(long long long ptr ptr ptr)
@ stdcall SetupSetDirectoryIdA(long long str)
@ stub SetupSetDirectoryIdExA
@ stub SetupSetDirectoryIdExW
@ stdcall SetupSetDirectoryIdW(long long wstr)
@ stdcall SetupSetFileQueueFlags(long long long)
@ stub SetupSetPlatformPathOverrideA
@ stub SetupSetPlatformPathOverrideW
@ stub SetupSetSourceListA
@ stub SetupSetSourceListW
@ stdcall SetupTermDefaultQueueCallback(ptr)
@ 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 pSetupAddMiniIconToList
@ stub pSetupAddTagToGroupOrderListEntry
@ stub pSetupAppendStringToMultiSz
@ stub pSetupDirectoryIdToPath
@ stub pSetupGetField
@ stub pSetupGetOsLoaderDriveAndPath
@ stub pSetupGetVersionDatum
@ stub pSetupGuidFromString
@ stub pSetupIsGuidNull
@ stub pSetupMakeSurePathExists
@ stub pSetupStringFromGuid

View file

@ -0,0 +1,56 @@
/*
* Copyright 2001 Andreas Mohr
*
* 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
*/
#ifndef __SETUPAPI_PRIVATE_H
#define __SETUPAPI_PRIVATE_H
#define COPYFILEDLGORD 1000
#define SOURCESTRORD 500
#define DESTSTRORD 501
#define PROGRESSORD 502
#define REG_INSTALLEDFILES "System\\CurrentControlSet\\Control\\InstalledFiles"
#define REGPART_RENAME "\\Rename"
#define REG_VERSIONCONFLICT "Software\\Microsoft\\VersionConflictManager"
/* 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 );
/* from msvcrt/sys/stat.h */
#define _S_IWRITE 0x0080
#define _S_IREAD 0x0100
#endif /* __SETUPAPI_PRIVATE_H */

View file

@ -0,0 +1,686 @@
/*
* Setupapi cabinet routines
*
* Copyright 2003 Gregory M. Turner
*
* 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
*
*
* Many useful traces are commented in code, uncomment them if you have
* trouble and run with --debugmsg +setupapi
*
*/
#include <stdarg.h>
#include "string.h"
#include "stdlib.h"
#include "wine/debug.h"
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "winreg.h"
#include "setupapi.h"
#include "setupapi_private.h"
#include "fdi.h"
#include "wine/unicode.h"
#include "fcntl.h"
#include "share.h"
#include "wine/debug.h"
static HINSTANCE CABINET_hInstance = 0;
static HFDI (__cdecl *sc_FDICreate)(PFNALLOC, PFNFREE, PFNOPEN,
PFNREAD, PFNWRITE, PFNCLOSE, PFNSEEK, int, PERF);
static BOOL (__cdecl *sc_FDICopy)(HFDI, char *, char *, int,
PFNFDINOTIFY, PFNFDIDECRYPT, void *);
static BOOL (__cdecl *sc_FDIDestroy)(HFDI);
#define SC_HSC_A_MAGIC 0xACABFEED
typedef struct {
UINT magic;
HFDI hfdi;
PSP_FILE_CALLBACK_A msghandler;
PVOID context;
CHAR most_recent_cabinet_name[MAX_PATH];
} SC_HSC_A, *PSC_HSC_A;
#define SC_HSC_W_MAGIC 0x0CABFEED
typedef struct {
UINT magic;
HFDI hfdi;
PSP_FILE_CALLBACK_W msghandler;
PVOID context;
WCHAR most_recent_cabinet_name[MAX_PATH];
} SC_HSC_W, *PSC_HSC_W;
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
static BOOL LoadCABINETDll(void)
{
if (!CABINET_hInstance) {
CABINET_hInstance = LoadLibraryA("cabinet.dll");
if (CABINET_hInstance) {
sc_FDICreate = (void *)GetProcAddress(CABINET_hInstance, "FDICreate");
sc_FDICopy = (void *)GetProcAddress(CABINET_hInstance, "FDICopy");
sc_FDIDestroy = (void *)GetProcAddress(CABINET_hInstance, "FDIDestroy");
return TRUE;
} else {
ERR("load cabinet dll failed.\n");
return FALSE;
}
} else
return TRUE;
}
static void UnloadCABINETDll(void)
{
if (CABINET_hInstance) {
FreeLibrary(CABINET_hInstance);
CABINET_hInstance = 0;
}
}
/* FDICreate callbacks */
static void *sc_cb_alloc(ULONG cb)
{
return malloc(cb);
}
static void sc_cb_free(void *pv)
{
free(pv);
}
static INT_PTR sc_cb_open(char *pszFile, int oflag, int pmode)
{
DWORD creation = 0, sharing = 0;
int ioflag = 0;
INT_PTR ret = 0;
SECURITY_ATTRIBUTES sa;
/* TRACE("(pszFile == %s, oflag == %d, pmode == %d)\n", debugstr_a(pszFile), oflag, pmode); */
switch(oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
case _O_RDONLY:
ioflag |= GENERIC_READ;
break;
case _O_WRONLY:
ioflag |= GENERIC_WRITE;
break;
case _O_RDWR:
ioflag |= GENERIC_READ & GENERIC_WRITE;
break;
case _O_WRONLY | _O_RDWR: /* hmmm.. */
ERR("_O_WRONLY & _O_RDWR in oflag?\n");
return -1;
}
if (oflag & _O_CREAT) {
if (oflag & _O_EXCL)
creation = CREATE_NEW;
else if (oflag & _O_TRUNC)
creation = CREATE_ALWAYS;
else
creation = OPEN_ALWAYS;
} else /* no _O_CREAT */ {
if (oflag & _O_TRUNC)
creation = TRUNCATE_EXISTING;
else
creation = OPEN_EXISTING;
}
switch( pmode & 0x70 ) {
case _SH_DENYRW:
sharing = 0L;
break;
case _SH_DENYWR:
sharing = FILE_SHARE_READ;
break;
case _SH_DENYRD:
sharing = FILE_SHARE_WRITE;
break;
case _SH_COMPAT:
case _SH_DENYNO:
sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
break;
default:
ERR("<-- -1 (Unhandled pmode 0x%x)\n", pmode);
return -1;
}
if (oflag & ~(_O_BINARY | _O_TRUNC | _O_EXCL | _O_CREAT | _O_RDWR | _O_WRONLY | _O_NOINHERIT))
WARN("unsupported oflag 0x%04x\n",oflag);
sa.nLength = sizeof( SECURITY_ATTRIBUTES );
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = (ioflag & _O_NOINHERIT) ? FALSE : TRUE;
ret = (INT_PTR) CreateFileA(pszFile, ioflag, sharing, &sa, creation, FILE_ATTRIBUTE_NORMAL, NULL);
/* TRACE("<-- %d\n", ret); */
return ret;
}
static UINT sc_cb_read(INT_PTR hf, void *pv, UINT cb)
{
DWORD num_read;
BOOL rslt;
/* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
rslt = ReadFile((HANDLE) hf, pv, cb, &num_read, NULL);
/* eof and failure both give "-1" return */
if ((! rslt) || ((cb > 0) && (num_read == 0))) {
/* TRACE("<-- -1\n"); */
return -1;
}
/* TRACE("<-- %lu\n", num_read); */
return num_read;
}
static UINT sc_cb_write(INT_PTR hf, void *pv, UINT cb)
{
DWORD num_written;
/* BOOL rv; */
/* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
if ( /* (rv = */ WriteFile((HANDLE) hf, pv, cb, &num_written, NULL) /* ) */
&& (num_written == cb)) {
/* TRACE("<-- %lu\n", num_written); */
return num_written;
} else {
/* TRACE("rv == %d, num_written == %lu, cb == %u\n", rv, num_written,cb); */
/* TRACE("<-- -1\n"); */
return -1;
}
}
static int sc_cb_close(INT_PTR hf)
{
/* TRACE("(hf == %d)\n", hf); */
if (CloseHandle((HANDLE) hf))
return 0;
else
return -1;
}
static long sc_cb_lseek(INT_PTR hf, long dist, int seektype)
{
DWORD ret;
/* TRACE("(hf == %d, dist == %ld, seektype == %d)\n", hf, dist, seektype); */
if (seektype < 0 || seektype > 2)
return -1;
if (((ret = SetFilePointer((HANDLE) hf, dist, NULL, seektype)) != INVALID_SET_FILE_POINTER) || !GetLastError()) {
/* TRACE("<-- %lu\n", ret); */
return ret;
} else {
/* TRACE("<-- -1\n"); */
return -1;
}
}
#define SIZEOF_MYSTERIO (MAX_PATH*3)
/* FDICopy callbacks */
static INT_PTR sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
{
FILE_IN_CABINET_INFO_A fici;
PSC_HSC_A phsc;
CABINET_INFO_A ci;
FILEPATHS_A fp;
UINT err;
CHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! probably 256... */
memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO);
TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
if (pfdin && pfdin->pv && (*((void **) pfdin->pv) == (void *)SC_HSC_A_MAGIC))
phsc = (PSC_HSC_A) pfdin->pv;
else {
ERR("pv %p is not an SC_HSC_A.\n", (pfdin) ? pfdin->pv : NULL);
return -1;
}
switch (fdint) {
case fdintCABINET_INFO:
TRACE("Cabinet info notification\n");
/* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
TRACE(" Cabinet Set#: %d\n", pfdin->setID);
TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]);
ci.CabinetPath = pfdin->psz3;
ci.DiskName = pfdin->psz2;
ci.SetId = pfdin->setID;
ci.CabinetNumber = pfdin->iCabinet;
phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT) &ci, 0);
return 0;
case fdintPARTIAL_FILE:
TRACE("Partial file notification\n");
/* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
return 0;
case fdintCOPY_FILE:
TRACE("Copy file notification\n");
TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
/* TRACE(" File size: %ld\n", pfdin->cb);
TRACE(" File date: %u\n", pfdin->date);
TRACE(" File time: %u\n", pfdin->time);
TRACE(" File attr: %u\n", pfdin->attribs); */
fici.NameInCabinet = pfdin->psz1;
fici.FileSize = pfdin->cb;
fici.Win32Error = 0;
fici.DosDate = pfdin->date;
fici.DosTime = pfdin->time;
fici.DosAttribs = pfdin->attribs;
memset(&(fici.FullTargetName[0]), 0, MAX_PATH);
err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
(UINT) &fici, (UINT) pfdin->psz1);
if (err == FILEOP_DOIT) {
TRACE(" Callback specified filename: %s\n", debugstr_a(&(fici.FullTargetName[0])));
if (!fici.FullTargetName[0]) {
WARN(" Empty return string causing abort.");
SetLastError(ERROR_PATH_NOT_FOUND);
return -1;
}
return sc_cb_open(&(fici.FullTargetName[0]), _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE);
} else {
TRACE(" Callback skipped file.\n");
return 0;
}
case fdintCLOSE_FILE_INFO:
TRACE("Close file notification\n");
/* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
TRACE(" File hndl: %d\n", pfdin->hf); */
fp.Source = &(phsc->most_recent_cabinet_name[0]);
fp.Target = pfdin->psz1;
fp.Win32Error = 0;
fp.Flags = 0;
/* the following should be a fixme -- but it occurs too many times */
WARN("Should set file date/time/attribs (and execute files?)\n");
err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT) &fp, 0);
if (sc_cb_close(pfdin->hf))
WARN("_close failed.\n");
if (err) {
SetLastError(err);
return FALSE;
} else
return TRUE;
case fdintNEXT_CABINET:
TRACE("Next cabinet notification\n");
/* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
TRACE(" Cabinet Set#: %d\n", pfdin->setID);
TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
ci.CabinetFile = pfdin->psz1;
ci.CabinetPath = pfdin->psz3;
ci.DiskName = pfdin->psz2;
ci.SetId = pfdin->setID;
ci.CabinetNumber = pfdin->iCabinet;
/* remember the new cabinet name */
strcpy(&(phsc->most_recent_cabinet_name[0]), pfdin->psz1);
err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT) &ci, (UINT) &(mysterio[0]));
if (err) {
SetLastError(err);
return -1;
} else {
if (mysterio[0]) {
/* some easy paranoia. no such carefulness exists on the wide API IIRC */
mysterio[SIZEOF_MYSTERIO - 1] = '\0';
strncpy(pfdin->psz3, &(mysterio[0]), 255);
mysterio[255] = '\0';
}
return 0;
}
default:
FIXME("Unknown notification type %d.\n", fdint);
return 0;
}
}
static INT_PTR sc_FNNOTIFY_W(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
{
FILE_IN_CABINET_INFO_W fici;
PSC_HSC_W phsc;
CABINET_INFO_W ci;
FILEPATHS_W fp;
UINT err;
int len;
WCHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! */
WCHAR buf[MAX_PATH], buf2[MAX_PATH];
CHAR charbuf[MAX_PATH];
memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO * sizeof(WCHAR));
memset(&(buf[0]), 0, MAX_PATH * sizeof(WCHAR));
memset(&(buf2[0]), 0, MAX_PATH * sizeof(WCHAR));
memset(&(charbuf[0]), 0, MAX_PATH);
TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
if (pfdin && pfdin->pv && (*((void **) pfdin->pv) == (void *)SC_HSC_W_MAGIC))
phsc = (PSC_HSC_W) pfdin->pv;
else {
ERR("pv %p is not an SC_HSC_W.\n", (pfdin) ? pfdin->pv : NULL);
return -1;
}
switch (fdint) {
case fdintCABINET_INFO:
TRACE("Cabinet info notification\n");
/* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
TRACE(" Cabinet Set#: %d\n", pfdin->setID);
TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]);
len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, &(buf[0]), MAX_PATH);
if ((len > MAX_PATH) || (len <= 1))
buf[0] = '\0';
ci.CabinetPath = &(buf[0]);
len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, &(buf2[0]), MAX_PATH);
if ((len > MAX_PATH) || (len <= 1))
buf2[0] = '\0';
ci.DiskName = &(buf2[0]);
ci.SetId = pfdin->setID;
ci.CabinetNumber = pfdin->iCabinet;
phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT) &ci, 0);
return 0;
case fdintPARTIAL_FILE:
TRACE("Partial file notification\n");
/* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
return 0;
case fdintCOPY_FILE:
TRACE("Copy file notification\n");
TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
/* TRACE(" File size: %ld\n", pfdin->cb);
TRACE(" File date: %u\n", pfdin->date);
TRACE(" File time: %u\n", pfdin->time);
TRACE(" File attr: %u\n", pfdin->attribs); */
len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(buf2[0]), MAX_PATH);
if ((len > MAX_PATH) || (len <= 1))
buf2[0] = '\0';
fici.NameInCabinet = &(buf2[0]);
fici.FileSize = pfdin->cb;
fici.Win32Error = 0;
fici.DosDate = pfdin->date;
fici.DosTime = pfdin->time;
fici.DosAttribs = pfdin->attribs;
memset(&(fici.FullTargetName[0]), 0, MAX_PATH * sizeof(WCHAR));
err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
(UINT) &fici, (UINT) pfdin->psz1);
if (err == FILEOP_DOIT) {
TRACE(" Callback specified filename: %s\n", debugstr_w(&(fici.FullTargetName[0])));
if (fici.FullTargetName[0]) {
len = strlenW(&(fici.FullTargetName[0])) + 1;
if ((len > MAX_PATH ) || (len <= 1))
return 0;
if (!WideCharToMultiByte(CP_ACP, 0, &(fici.FullTargetName[0]), len, &(charbuf[0]), MAX_PATH, 0, 0))
return 0;
} else {
WARN("Empty buffer string caused abort.\n");
SetLastError(ERROR_PATH_NOT_FOUND);
return -1;
}
return sc_cb_open(&(charbuf[0]), _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE);
} else {
TRACE(" Callback skipped file.\n");
return 0;
}
case fdintCLOSE_FILE_INFO:
TRACE("Close file notification\n");
/* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
TRACE(" File hndl: %d\n", pfdin->hf); */
fp.Source = &(phsc->most_recent_cabinet_name[0]);
len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(buf[0]), MAX_PATH);
if ((len > MAX_PATH) || (len <= 1))
buf[0] = '\0';
fp.Target = &(buf[0]);
fp.Win32Error = 0;
fp.Flags = 0;
/* a valid fixme -- but occurs too many times */
/* FIXME("Should set file date/time/attribs (and execute files?)\n"); */
err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT) &fp, 0);
if (sc_cb_close(pfdin->hf))
WARN("_close failed.\n");
if (err) {
SetLastError(err);
return FALSE;
} else
return TRUE;
case fdintNEXT_CABINET:
TRACE("Next cabinet notification\n");
/* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
TRACE(" Cabinet Set#: %d\n", pfdin->setID);
TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
/* remember the new cabinet name */
len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(phsc->most_recent_cabinet_name[0]), MAX_PATH);
if ((len > MAX_PATH) || (len <= 1))
phsc->most_recent_cabinet_name[0] = '\0';
ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]);
len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, &(buf[0]), MAX_PATH);
if ((len > MAX_PATH) || (len <= 1))
buf[0] = '\0';
ci.CabinetPath = &(buf[0]);
len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, &(buf2[0]), MAX_PATH);
if ((len > MAX_PATH) || (len <= 1))
buf2[0] = '\0';
ci.DiskName = &(buf2[0]);
ci.SetId = pfdin->setID;
ci.CabinetNumber = pfdin->iCabinet;
err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT) &ci, (UINT) &(mysterio[0]));
if (err) {
SetLastError(err);
return -1;
} else {
if (mysterio[0]) {
len = strlenW(&(mysterio[0])) + 1;
if ((len > 255) || (len <= 1))
return 0;
if (!WideCharToMultiByte(CP_ACP, 0, &(mysterio[0]), len, pfdin->psz3, 255, 0, 0))
return 0;
}
return 0;
}
default:
FIXME("Unknown notification type %d.\n", fdint);
return 0;
}
}
/***********************************************************************
* SetupIterateCabinetA (SETUPAPI.@)
*/
BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved,
PSP_FILE_CALLBACK_A MsgHandler, PVOID Context)
{
SC_HSC_A my_hsc;
ERF erf;
CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *p;
DWORD fpnsize;
BOOL ret;
TRACE("(CabinetFile == %s, Reserved == %lu, MsgHandler == ^%p, Context == ^%p)\n",
debugstr_a(CabinetFile), Reserved, MsgHandler, Context);
if (! LoadCABINETDll())
return FALSE;
memset(&my_hsc, 0, sizeof(SC_HSC_A));
pszCabinet[0] = '\0';
pszCabPath[0] = '\0';
fpnsize = strlen(CabinetFile);
if (fpnsize >= MAX_PATH) {
SetLastError(ERROR_BAD_PATHNAME);
return FALSE;
}
fpnsize = GetFullPathNameA(CabinetFile, MAX_PATH, &(pszCabPath[0]), &p);
if (fpnsize > MAX_PATH) {
SetLastError(ERROR_BAD_PATHNAME);
return FALSE;
}
if (p) {
strcpy(pszCabinet, p);
*p = '\0';
} else {
strcpy(pszCabinet, CabinetFile);
pszCabPath[0] = '\0';
}
TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet));
/* remember the cabinet name */
strcpy(&(my_hsc.most_recent_cabinet_name[0]), pszCabinet);
my_hsc.magic = SC_HSC_A_MAGIC;
my_hsc.msghandler = MsgHandler;
my_hsc.context = Context;
my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
if (!my_hsc.hfdi) return FALSE;
ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath,
0, sc_FNNOTIFY_A, NULL, &my_hsc) ) ? TRUE : FALSE;
sc_FDIDestroy(my_hsc.hfdi);
return ret;
}
/***********************************************************************
* SetupIterateCabinetW (SETUPAPI.@)
*/
BOOL WINAPI SetupIterateCabinetW(PCWSTR CabinetFile, DWORD Reserved,
PSP_FILE_CALLBACK_W MsgHandler, PVOID Context)
{
CHAR CabinetFile_A[MAX_PATH];
unsigned int len;
SC_HSC_W my_hsc;
ERF erf;
CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *p;
DWORD fpnsize;
BOOL ret;
TRACE("(CabinetFile == %s, Reserved == %lu, MsgHandler == ^%p, Context == ^%p)\n",
debugstr_w(CabinetFile), Reserved, MsgHandler, Context);
if (!LoadCABINETDll())
return FALSE;
if (!CabinetFile) return FALSE;
if (!WideCharToMultiByte(CP_ACP, 0, CabinetFile, -1, CabinetFile_A, MAX_PATH, 0, 0))
return FALSE;
memset(&my_hsc, 0, sizeof(SC_HSC_W));
pszCabinet[0] = '\0';
pszCabPath[0] = '\0';
fpnsize = GetFullPathNameA(CabinetFile_A, MAX_PATH, &(pszCabPath[0]), &p);
if (fpnsize > MAX_PATH) {
SetLastError(ERROR_BAD_PATHNAME);
return FALSE;
}
if (p) {
strcpy(pszCabinet, p);
*p = '\0';
} else {
strcpy(pszCabinet, CabinetFile_A);
pszCabPath[0] = '\0';
}
TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet));
/* remember the cabinet name */
len = 1 + MultiByteToWideChar(CP_ACP, 0, pszCabinet, -1,
&(my_hsc.most_recent_cabinet_name[0]), MAX_PATH);
if (len > MAX_PATH)
return FALSE;
else if (len <= 1)
my_hsc.most_recent_cabinet_name[0] = '\0';
my_hsc.magic = SC_HSC_W_MAGIC;
my_hsc.msghandler = MsgHandler;
my_hsc.context = Context;
my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
if (!my_hsc.hfdi) return FALSE;
ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath,
0, sc_FNNOTIFY_W, NULL, &my_hsc) ) ? TRUE : FALSE;
sc_FDIDestroy(my_hsc.hfdi);
return ret;
}
/***********************************************************************
* DllMain
*
* PARAMS
* hinstDLL [I] handle to the DLL's instance
* fdwReason [I]
* lpvReserved [I] reserved, must be NULL
*
* RETURNS
* Success: TRUE
* Failure: FALSE
*/
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
break;
case DLL_PROCESS_DETACH:
UnloadCABINETDll();
break;
}
return TRUE;
}

View file

@ -0,0 +1,562 @@
/*
* Copyright 2000 Andreas Mohr 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
*/
#ifndef __SETUPX16_H
#define __SETUPX16_H
#include "wine/windef16.h"
typedef UINT16 HINF16;
typedef UINT16 LOGDISKID16;
typedef UINT16 VHSTR;
#define LINE_LEN 256
/* error codes stuff */
typedef UINT16 RETERR16;
#define OK 0
#define IP_ERROR (UINT16)100
#define TP_ERROR (UINT16)200
#define VCP_ERROR (UINT16)300
#define GEN_ERROR (UINT16)400
#define DI_ERROR (UINT16)500
enum {
ERR_IP_INVALID_FILENAME = IP_ERROR+1,
ERR_IP_ALLOC_ERR,
ERR_IP_INVALID_SECT_NAME,
ERR_IP_OUT_OF_HANDLES,
ERR_IP_INF_NOT_FOUND,
ERR_IP_INVALID_INFFILE,
ERR_IP_INVALID_HINF,
ERR_IP_INVALID_FIELD,
ERR_IP_SECT_NOT_FOUND,
ERR_IP_END_OF_SECTION,
ERR_IP_PROFILE_NOT_FOUND,
ERR_IP_LINE_NOT_FOUND,
ERR_IP_FILEREAD,
ERR_IP_TOOMANYINFFILES,
ERR_IP_INVALID_SAVERESTORE,
ERR_IP_INVALID_INFTYPE
};
/****** virtual copy operations ******/
typedef DWORD LPEXPANDVTBL;
typedef struct {
DWORD dwSoFar;
DWORD dwTotal;
} VCPPROGRESS, *LPVCPPROGRESS;
typedef struct {
WORD cbSize;
LOGDISKID16 ldid;
VHSTR vhstrRoot;
VHSTR vhstrVolumeLabel;
VHSTR vhstrDiskName;
WORD wVolumeTime;
WORD wVolumeDate;
DWORD dwSerialNumber;
WORD fl;
LPARAM lparamRef;
VCPPROGRESS prgFileRead;
VCPPROGRESS prgByteRead;
VCPPROGRESS prgFileWrite;
VCPPROGRESS prgByteWrite;
} VCPDISKINFO, *LPVCPDISKINFO;
typedef struct {
LOGDISKID16 ldid;
VHSTR vhstrDir;
VHSTR vhstrFileName;
} VCPFILESPEC, *LPVCPFILESPEC;
typedef struct {
UINT16 uiMDate;
UINT16 uiMTime;
UINT16 uiADate;
UINT16 uiATime;
UINT16 uiAttr;
DWORD llenIn;
DWORD llenOut;
} VCPFATTR, *LPVCPFATTR;
typedef struct {
UINT16 uDate;
UINT16 uTime;
DWORD dwSize;
} VCPFILESTAT, *LPVCPFILESTAT;
typedef struct
{
HFILE16 hFileSrc;
HFILE16 hFileDst;
VCPFATTR fAttr;
WORD dosError;
VHSTR vhstrFileName;
WPARAM vcpm;
} VIRTNODEEX, *LPVIRTNODEEX;
typedef struct {
WORD cbSize;
VCPFILESPEC vfsSrc;
VCPFILESPEC vfsDst;
WORD fl;
LPARAM lParam;
LPEXPANDVTBL lpExpandVtbl;
LPVIRTNODEEX lpvnex;
VHSTR vhstrDstFinalName;
VCPFILESTAT vFileStat;
} VIRTNODE, *LPVIRTNODE;
typedef struct {
WORD cbSize;
VCPPROGRESS prgDiskRead;
VCPPROGRESS prgFileRead;
VCPPROGRESS prgByteRead;
VCPPROGRESS prgDiskWrite;
VCPPROGRESS prgFileWrite;
VCPPROGRESS prgByteWrite;
LPVCPDISKINFO lpvdiIn;
LPVCPDISKINFO lpvdiOut;
LPVIRTNODE lpvn;
} VCPSTATUS, *LPVCPSTATUS;
#define CNFL_BACKUP 0x0001
#define CNFL_DELETEONFAILURE 0x0002
#define CNFL_RENAMEONSUCCESS 0x0004
#define CNFL_CONTINUATION 0x0008
#define CNFL_SKIPPED 0x0010
#define CNFL_IGNOREERRORS 0x0020
#define CNFL_RETRYFILE 0x0040
#define CNFL_COPIED 0x0080
#define VNFL_UNIQUE 0x0000
#define VNFL_MULTIPLEOK 0x0100
#define VNFL_DESTROYOLD 0x0200
#define VNFL_COPY 0x0000
#define VNFL_DELETE 0x0800
#define VNFL_RENAME 0x1000
#define VNFL_NODE_TYPE (VNFL_RENAME|VNFL_DELETE|VNFL_COPY)
#define VNFL_CREATED 0x2000
#define VNFL_REJECTED 0x4000
#define VNFL_DEVICEINSTALLER 0x8000
enum {
ERR_VCP_IOFAIL = VCP_ERROR+1,
ERR_VCP_STRINGTOOLONG,
ERR_VCP_NOMEM,
ERR_VCP_QUEUEFULL,
ERR_VCP_NOVHSTR,
ERR_VCP_OVERFLOW,
ERR_VCP_BADARG,
ERR_VCP_UNINIT,
ERR_VCP_NOTFOUND,
ERR_VCP_BUSY,
ERR_VCP_INTERRUPTED,
ERR_VCP_BADDEST,
ERR_VCP_SKIPPED,
ERR_VCP_IO,
ERR_VCP_LOCKED,
ERR_VCP_WRONGDISK,
ERR_VCP_CHANGEMODE,
ERR_VCP_LDDINVALID,
ERR_VCP_LDDFIND,
ERR_VCP_LDDUNINIT,
ERR_VCP_LDDPATH_INVALID,
ERR_VCP_NOEXPANSION,
ERR_VCP_NOTOPEN,
ERR_VCP_NO_DIGITAL_SIGNATURE_CATALOG,
ERR_VCP_NO_DIGITAL_SIGNATURE_FILE
};
#define VCPN_OK 0
#define VCPN_PROCEED 0
#define VCPN_ABORT -1
#define VCPN_RETRY -2
#define VCPN_IGNORE -3
#define VCPN_SKIP -4
#define VCPN_FORCE -5
#define VCPN_DEFER -6
#define VCPN_FAIL -7
#define VCPN_RETRYFILE -8
#define VCPFL_ABANDON 0x00
#define VCPFL_BACKUP 0x01
#define VCPFL_COPY 0x02
#define VCPFL_BACKUPANDCOPY (VCPFL_BACKUP|VCPFL_COPY)
#define VCPFL_INSPECIFIEDORDER 0x04
#define VCPFL_DELETE 0x08
#define VCPFL_RENAME 0x10
#define VCPFL_ALL (VCPFL_COPY|VCPFL_DELETE|VCPFL_RENAME)
#define CFNL_BACKUP 0x0001
#define CFNL_DELETEONFAILURE 0x0002
#define CFNL_RENAMEONSUCCESS 0x0004
#define CFNL_CONTINUATION 0x0008
#define CFNL_SKIPPED 0x0010
#define CFNL_IGNOREERRORS 0x0020
#define CFNL_RETRYFILE 0x0040
#define CFNL_COPIED 0x0080
#define VFNL_MULTIPLEOK 0x0100
#define VFNL_DESTROYOLD 0x0200
#define VFNL_NOW 0x0400
#define VFNL_COPY 0x0000
#define VFNL_DELETE 0x0800
#define VFNL_RENAME 0x1000
#define VFNL_CREATED 0x2000
#define VFNL_REJECTED 0x4000
#define VCPM_DISKCLASS 0x01
#define VCPM_DISKFIRST 0x0100
#define VCPM_DISKLAST 0x01ff
enum {
VCPM_DISKCREATEINFO = VCPM_DISKFIRST,
VCPM_DISKGETINFO,
VCPM_DISKDESTROYINFO,
VCPM_DISKPREPINFO,
VCPM_DISKENSURE,
VCPM_DISKPROMPT,
VCPM_DISKFORMATBEGIN,
VCPM_DISKFORMATTING,
VCPM_DISKFORMATEND
};
#define VCPM_FILEINCLASS 0x02
#define VCPM_FILEOUTCLASS 0x03
#define VCPM_FILEFIRSTIN 0x0200
#define VCPM_FILEFIRSTOUT 0x0300
#define VCPM_FILELAST 0x03ff
enum {
VCPM_FILEOPENIN = VCPM_FILEFIRSTIN,
VCPM_FILEGETFATTR,
VCPM_FILECLOSEIN,
VCPM_FILECOPY,
VCPM_FILENEEDED,
VCPM_FILEOPENOUT = VCPM_FILEFIRSTOUT,
VCPM_FILESETFATTR,
VCPM_FILECLOSEOUT,
VCPM_FILEFINALIZE,
VCPM_FILEDELETE,
VCPM_FILERENAME
};
#define VCPM_NODECLASS 0x04
#define VCPM_NODEFIRST 0x0400
#define VCPM_NODELAST 0x04ff
enum {
VCPM_NODECREATE = VCPM_NODEFIRST,
VCPM_NODEACCEPT,
VCPM_NODEREJECT,
VCPM_NODEDESTROY,
VCPM_NODECHANGEDESTDIR,
VCPM_NODECOMPARE
};
#define VCPM_TALLYCLASS 0x05
#define VCPM_TALLYFIRST 0x0500
#define VCPM_TALLYLAST 0x05ff
enum {
VCPM_TALLYSTART = VCPM_TALLYFIRST,
VCPM_TALLYEND,
VCPM_TALLYFILE,
VCPM_TALLYDISK
};
#define VCPM_VERCLASS 0x06
#define VCPM_VERFIRST 0x0600
#define VCPM_VERLAST 0x06ff
enum {
VCPM_VERCHECK = VCPM_VERFIRST,
VCPM_VERCHECKDONE,
VCPM_VERRESOLVECONFLICT
};
#define VCPM_VSTATCLASS 0x07
#define VCPM_VSTATFIRST 0x0700
#define VCPM_VSTATLAST 0x07ff
enum {
VCPM_VSTATSTART = VCPM_VSTATFIRST,
VCPM_VSTATEND,
VCPM_VSTATREAD,
VCPM_VSTATWRITE,
VCPM_VSTATNEWDISK,
VCPM_VSTATCLOSESTART,
VCPM_VSTATCLOSEEND,
VCPM_VSTATBACKUPSTART,
VCPM_VSTATBACKUPEND,
VCPM_VSTATRENAMESTART,
VCPM_VSTATRENAMEEND,
VCPM_VSTATCOPYSTART,
VCPM_VSTATCOPYEND,
VCPM_VSTATDELETESTART,
VCPM_VSTATDELETEEND,
VCPM_VSTATPATHCHECKSTART,
VCPM_VSTATPATHCHECKEND,
VCPM_VSTATCERTIFYSTART,
VCPM_VSTATCERTIFYEND,
VCPM_VSTATUSERABORT,
VCPM_VSTATYIELD
};
#define VCPM_PATHCLASS 0x08
#define VCPM_PATHFIRST 0x0800
#define VCPM_PATHLAST 0x08ff
enum {
VCPM_BUILDPATH = VCPM_PATHFIRST,
VCPM_UNIQUEPATH,
VCPM_CHECKPATH
};
#define VCPM_PATCHCLASS 0x09
#define VCPM_PATCHFIRST 0x0900
#define VCPM_PATCHLAST 0x09ff
enum {
VCPM_FILEPATCHBEFORECPY = VCPM_PATCHFIRST,
VCPM_FILEPATCHAFTERCPY,
VCPM_FILEPATCHINFOPEN,
VCPM_FILEPATCHINFCLOSE
};
#define VCPM_CERTCLASS 0x0a
#define VCPM_CERTFIRST 0x0a00
#define VCPM_CERTLAST 0x0aff
enum {
VCPM_FILECERTIFY = VCPM_CERTFIRST,
VCPM_FILECERTIFYWARN
};
typedef LRESULT (CALLBACK *VIFPROC)(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam, LPARAM lParam, LPARAM lparamRef);
typedef int (CALLBACK *VCPENUMPROC)(LPVIRTNODE lpvn, LPARAM lparamRef);
RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef);
/* VcpQueueCopy flags */
#define VNLP_SYSCRITICAL 0x0001
#define VNLP_SETUPCRITICAL 0x0002
#define VNLP_NOVERCHECK 0x0004
#define VNLP_FORCETEMP 0x0008
#define VNLP_IFEXISTS 0x0010
#define VNLP_KEEPNEWER 0x0020
#define VNLP_PATCHIFEXIST 0x0040
#define VNLP_NOPATCH 0x0080
#define VNLP_CATALOGCERT 0x0100
#define VNLP_NEEDCERTIFY 0x0200
#define VNLP_COPYIFEXISTS 0x0400
RETERR16 WINAPI VcpQueueCopy16(
LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
LPEXPANDVTBL lpExpandVtbl,
WORD fl, LPARAM lParam
);
RETERR16 VcpFlush16(WORD fl, LPCSTR lpszBackupDest);
RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest);
/* VcpExplain flags */
enum {
VCPEX_SRC_DISK,
VCPEX_SRC_CABINET,
VCPEX_SRC_LOCN,
VCPEX_DST_LOCN,
VCPEX_SRC_FILE,
VCPEX_DST_FILE,
VCPEX_DST_FILE_FINAL,
VCPEX_DOS_ERROR,
VCPEX_MESSAGE,
VCPEX_DOS_SOLUTION,
VCPEX_SRC_FULL,
VCPEX_DST_FULL,
VCPEX_DST_FULL_FINAL
};
LPCSTR WINAPI VcpExplain16(LPVIRTNODE lpVn, DWORD dwWhat);
/****** logical disk management ******/
typedef struct _LOGDISKDESC_S { /* ldd */
WORD cbSize; /* struct size */
LOGDISKID16 ldid; /* logical disk ID */
LPSTR pszPath; /* path this descriptor points to */
LPSTR pszVolLabel; /* volume label of the disk related to it */
LPSTR pszDiskName; /* name of this disk */
WORD wVolTime; /* modification time of volume label */
WORD wVolDate; /* modification date */
DWORD dwSerNum; /* serial number of disk */
WORD wFlags;
} LOGDISKDESC_S, *LPLOGDISKDESC;
/** logical disk identifiers (LDID) **/
/* predefined LDIDs */
#define LDID_PREDEF_START 0x0001
#define LDID_PREDEF_END 0x7fff
/* registry-assigned LDIDs */
#define LDID_VAR_START 0x7000
#define LDID_VAR_END 0x7fff
/* dynamically assigned LDIDs */
#define LDID_ASSIGN_START 0x8000
#define LDID_ASSIGN_END 0xbfff
#define LDID_NULL 0
#define LDID_ABSOLUTE ((UINT)-1)
#define LDID_SRCPATH 1 /* setup source path */
#define LDID_SETUPTEMP 2 /* setup temp dir */
#define LDID_UNINSTALL 3 /* uninstall dir */
#define LDID_BACKUP 4 /* backup dir */
#define LDID_SETUPSCRATCH 5 /* setup scratch dir */
#define LDID_WIN 10 /* win dir */
#define LDID_SYS 11 /* win system dir */
#define LDID_IOS 12 /* win Iosubsys dir */
#define LDID_CMD 13 /* win command dir */
#define LDID_CPL 14 /* win control panel dir */
#define LDID_PRINT 15 /* win printer dir */
#define LDID_MAIL 16 /* win mail dir */
#define LDID_INF 17 /* win inf dir */
#define LDID_HELP 18 /* win help dir */
#define LDID_WINADMIN 19 /* admin dir */
#define LDID_FONTS 20 /* win fonts dir */
#define LDID_VIEWERS 21 /* win viewers dir */
#define LDID_VMM32 22 /* win VMM32 dir */
#define LDID_COLOR 23 /* win color mngment dir */
#define LDID_APPS 24 /* win apps dir */
#define LDID_SHARED 25 /* win shared dir */
#define LDID_WINBOOT 26 /* guaranteed win boot drive */
#define LDID_MACHINE 27 /* machine specific files */
#define LDID_HOST_WINBOOT 28
#define LDID_BOOT 30 /* boot drive root dir */
#define LDID_BOOT_HOST 31 /* boot drive host root dir */
#define LDID_OLD_WINBOOT 32 /* root subdir */
#define LDID_OLD_WIN 33 /* old windows dir */
/* flags for GenInstall() */
#define GENINSTALL_DO_FILES 1
#define GENINSTALL_DO_INI 2
#define GENINSTALL_DO_REG 4
#define GENINSTALL_DO_INI2REG 8
#define GENINSTALL_DO_CFGAUTO 16
#define GENINSTALL_DO_LOGCONFIG 32
#define GENINSTALL_DO_REGSRCPATH 64
#define GENINSTALL_DO_PERUSER 128
#define GEINISTALL_DO_INIREG 14
#define GENINSTALL_DO_ALL 255
/*
* flags for InstallHinfSection()
* 128 can be added, too. This means that the .inf file is provided by you
* instead of being a 32 bit file (i.e. Windows .inf file).
* In this case all files you install must be in the same dir
* as your .inf file on the install disk.
*/
#define HOW_NEVER_REBOOT 0
#define HOW_ALWAYS_SILENT_REBOOT 1
#define HOW_ALWAYS_PROMPT_REBOOT 2
#define HOW_SILENT_REBOOT 3
#define HOW_PROMPT_REBOOT 4
/****** device installation stuff ******/
#define MAX_CLASS_NAME_LEN 32
#define MAX_DEVNODE_ID_LEN 256
#define MAX_GUID_STR 50
typedef struct _DEVICE_INFO
{
UINT16 cbSize;
struct _DEVICE_INFO *lpNextDi;
char szDescription[LINE_LEN];
DWORD dnDevnode;
HKEY hRegKey;
char szRegSubkey[MAX_DEVNODE_ID_LEN];
char szClassName[MAX_CLASS_NAME_LEN];
DWORD Flags;
HWND16 hwndParent;
/*LPDRIVER_NODE*/ LPVOID lpCompatDrvList;
/*LPDRIVER_NODE*/ LPVOID lpClassDrvList;
/*LPDRIVER_NODE*/ LPVOID lpSelectedDriver;
ATOM atDriverPath;
ATOM atTempInfFile;
HINSTANCE16 hinstClassInstaller;
HINSTANCE16 hinstClassPropProvidor;
HINSTANCE16 hinstDevicePropProvidor;
HINSTANCE16 hinstBasicPropProvidor;
FARPROC16 fpClassInstaller;
FARPROC16 fpClassEnumPropPages;
FARPROC16 fpDeviceEnumPropPages;
FARPROC16 fpEnumBasicProperties;
DWORD dwSetupReserved;
DWORD dwClassInstallReserved;
/*GENCALLBACKPROC*/ LPVOID gicpGenInstallCallBack;
LPARAM gicplParam;
UINT16 InfType;
HINSTANCE16 hinstPrivateProblemHandler;
FARPROC16 fpPrivateProblemHandler;
LPARAM lpClassInstallParams;
struct _DEVICE_INFO *lpdiChildList;
DWORD dwFlagsEx;
/*LPDRIVER_INFO*/ LPVOID lpCompatDrvInfoList;
/*LPDRIVER_INFO*/ LPVOID lpClassDrvInfoList;
char szClassGUID[MAX_GUID_STR];
} DEVICE_INFO16, *LPDEVICE_INFO16, **LPLPDEVICE_INFO16;
extern void WINAPI GenFormStrWithoutPlaceHolders16(LPSTR,LPCSTR,HINF16);
extern RETERR16 WINAPI IpOpen16(LPCSTR,HINF16 *);
extern RETERR16 WINAPI IpClose16(HINF16);
extern RETERR16 WINAPI CtlSetLdd16(LPLOGDISKDESC);
extern RETERR16 WINAPI CtlGetLdd16(LPLOGDISKDESC);
extern RETERR16 WINAPI CtlFindLdd16(LPLOGDISKDESC);
extern RETERR16 WINAPI CtlAddLdd16(LPLOGDISKDESC);
extern RETERR16 WINAPI CtlDelLdd16(LOGDISKID16);
extern RETERR16 WINAPI CtlGetLddPath16(LOGDISKID16 ldid, LPSTR szPath);
extern RETERR16 WINAPI GenInstall16(HINF16,LPCSTR,WORD);
typedef struct tagLDD_LIST {
LPLOGDISKDESC pldd;
struct tagLDD_LIST *next;
} LDD_LIST;
#define INIT_LDD(ldd, LDID) \
do { \
memset(&(ldd), 0, sizeof(LOGDISKDESC_S)); \
(ldd).cbSize = sizeof(LOGDISKDESC_S); \
ldd.ldid = LDID; \
} while(0)
#endif /* __SETUPX16_H */

View file

@ -0,0 +1,736 @@
/*
* SETUPX library
*
* Copyright 1998,2000 Andreas Mohr
*
* 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
*
* FIXME: Rather non-functional functions for now.
*
* See:
* http://www.geocities.com/SiliconValley/Network/5317/drivers.html
* http://willemer.de/informatik/windows/inf_info.htm (German)
* http://www.microsoft.com/ddk/ddkdocs/win98ddk/devinst_12uw.htm
* DDK: setupx.h
* http://mmatrix.tripod.com/customsystemfolder/infsysntaxfull.html
* http://www.rdrop.com/~cary/html/inf_faq.html
* http://support.microsoft.com/support/kb/articles/q194/6/40.asp
*
* Stuff tested with:
* - rs405deu.exe (German Acroread 4.05 setup)
* - ie5setup.exe
* - Netmeeting
*
* FIXME:
* - string handling is... weird ;) (buflen etc.)
* - memory leaks ?
* - separate that mess (but probably only when it's done completely)
*
* SETUPX consists of several parts with the following acronyms/prefixes:
* Di device installer (devinst.c ?)
* Gen generic installer (geninst.c ?)
* Ip .INF parsing (infparse.c)
* LDD logical device descriptor (ldd.c ?)
* LDID logical device ID
* SU setup (setup.c ?)
* Tp text processing (textproc.c ?)
* Vcp virtual copy module (vcp.c ?)
* ...
*
* The SETUPX DLL is NOT thread-safe. That's why many installers urge you to
* "close all open applications".
* All in all the design of it seems to be a bit weak.
* Not sure whether my implementation of it is better, though ;-)
*/
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winerror.h"
#include "wine/winuser16.h"
#include "wownt32.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "setupapi.h"
#include "setupx16.h"
#include "setupapi_private.h"
#include "winerror.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
/***********************************************************************
* SURegOpenKey (SETUPX.47)
*/
DWORD WINAPI SURegOpenKey( HKEY hkey, LPCSTR lpszSubKey, PHKEY retkey )
{
FIXME("(%p,%s,%p), semi-stub.\n",hkey,debugstr_a(lpszSubKey),retkey);
return RegOpenKeyA( hkey, lpszSubKey, retkey );
}
/***********************************************************************
* SURegQueryValueEx (SETUPX.50)
*/
DWORD WINAPI SURegQueryValueEx( HKEY hkey, LPSTR lpszValueName,
LPDWORD lpdwReserved, LPDWORD lpdwType,
LPBYTE lpbData, LPDWORD lpcbData )
{
FIXME("(%p,%s,%p,%p,%p,%ld), semi-stub.\n",hkey,debugstr_a(lpszValueName),
lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
lpbData, lpcbData );
}
/*
* Returns pointer to a string list with the first entry being number
* of strings.
*
* Hmm. Should this be InitSubstrData(), GetFirstSubstr() and GetNextSubstr()
* instead?
*/
static LPSTR *SETUPX_GetSubStrings(LPSTR start, char delimiter)
{
LPSTR p, q;
LPSTR *res = NULL;
DWORD count = 0;
int len;
p = start;
while (1)
{
/* find beginning of real substring */
while ( (*p == ' ') || (*p == '\t') || (*p == '"') ) p++;
/* find end of real substring */
q = p;
while ( (*q)
&& (*q != ' ') && (*q != '\t') && (*q != '"')
&& (*q != ';') && (*q != delimiter) ) q++;
if (q == p)
break;
len = (int)q - (int)p;
/* alloc entry for new substring in steps of 32 units and copy over */
if (count % 32 == 0)
{ /* 1 for count field + current count + 32 */
if (res)
res = HeapReAlloc(GetProcessHeap(), 0, res, (1+count+32)*sizeof(LPSTR));
else
res = HeapAlloc(GetProcessHeap(), 0, (1+count+32)*sizeof(LPSTR));
}
*(res+1+count) = HeapAlloc(GetProcessHeap(), 0, len+1);
strncpy(*(res+1+count), p, len);
(*(res+1+count))[len] = '\0';
count++;
/* we are still within last substring (before delimiter),
* so get out of it */
while ((*q) && (*q != ';') && (*q != delimiter)) q++;
if ((!*q) || (*q == ';'))
break;
p = q+1;
}
/* put number of entries at beginning of list */
*(DWORD *)res = count;
return res;
}
static void SETUPX_FreeSubStrings(LPSTR *substr)
{
DWORD count = *(DWORD *)substr;
LPSTR *pStrings = substr+1;
DWORD n;
for (n=0; n < count; n++)
HeapFree(GetProcessHeap(), 0, *pStrings++);
HeapFree(GetProcessHeap(), 0, substr);
}
/***********************************************************************
* InstallHinfSection (SETUPX.527)
*
* hwnd = parent window
* hinst = instance of SETUPX.DLL
* lpszCmdLine = e.g. "DefaultInstall 132 C:\MYINSTALL\MYDEV.INF"
* Here "DefaultInstall" is the .inf file section to be installed (optional).
* The 132 value is made of the HOW_xxx flags and sometimes 128 (-> setupx16.h).
*
* nCmdShow = nCmdShow of CreateProcess
*/
RETERR16 WINAPI InstallHinfSection16( HWND16 hwnd, HINSTANCE16 hinst, LPCSTR lpszCmdLine, INT16 nCmdShow)
{
LPSTR *pSub;
DWORD count;
HINF16 hInf = 0;
RETERR16 res = OK, tmp;
WORD wFlags;
BOOL reboot = FALSE;
TRACE("(%04x, %04x, %s, %d);\n", hwnd, hinst, lpszCmdLine, nCmdShow);
pSub = SETUPX_GetSubStrings((LPSTR)lpszCmdLine, ' ');
count = *(DWORD *)pSub;
if (count < 2) /* invalid number of arguments ? */
goto end;
if (IpOpen16(*(pSub+count), &hInf) != OK)
{
res = ERROR_FILE_NOT_FOUND; /* yes, correct */
goto end;
}
if (VcpOpen16(NULL, 0))
goto end;
if (GenInstall16(hInf, *(pSub+count-2), GENINSTALL_DO_ALL) != OK)
goto end;
wFlags = atoi(*(pSub+count-1)) & ~128;
switch (wFlags)
{
case HOW_ALWAYS_SILENT_REBOOT:
case HOW_SILENT_REBOOT:
reboot = TRUE;
break;
case HOW_ALWAYS_PROMPT_REBOOT:
case HOW_PROMPT_REBOOT:
if (MessageBoxA(HWND_32(hwnd), "You must restart Wine before the new settings will take effect.\n\nDo you want to exit Wine now ?", "Systems Settings Change", MB_YESNO|MB_ICONQUESTION) == IDYES)
reboot = TRUE;
break;
default:
ERR("invalid flags %d !\n", wFlags);
goto end;
}
res = OK;
end:
tmp = VcpClose16(VCPFL_ALL, NULL);
if (tmp != OK)
res = tmp;
tmp = IpClose16(hInf);
if (tmp != OK)
res = tmp;
SETUPX_FreeSubStrings(pSub);
if (reboot)
{
/* FIXME: we should have a means of terminating all wine + wineserver */
MESSAGE("Program or user told me to restart. Exiting Wine...\n");
ExitProcess(1);
}
return res;
}
typedef struct
{
LPCSTR RegValName;
LPCSTR StdString; /* fallback string; sub dir of windows directory */
} LDID_DATA;
static const LDID_DATA LDID_Data[34] =
{
{ /* 0 (LDID_NULL) -- not defined */
NULL,
NULL
},
{ /* 1 (LDID_SRCPATH) = source of installation. hmm, what to do here ? */
"SourcePath", /* hmm, does SETUPX have to care about updating it ?? */
NULL
},
{ /* 2 (LDID_SETUPTEMP) = setup temp dir */
"SetupTempDir",
NULL
},
{ /* 3 (LDID_UNINSTALL) = uninstall backup dir */
"UninstallDir",
NULL
},
{ /* 4 (LDID_BACKUP) = backup dir */
"BackupDir",
NULL
},
{ /* 5 (LDID_SETUPSCRATCH) = setup scratch dir */
"SetupScratchDir",
NULL
},
{ /* 6 -- not defined */
NULL,
NULL
},
{ /* 7 -- not defined */
NULL,
NULL
},
{ /* 8 -- not defined */
NULL,
NULL
},
{ /* 9 -- not defined */
NULL,
NULL
},
{ /* 10 (LDID_WIN) = windows dir */
"WinDir",
""
},
{ /* 11 (LDID_SYS) = system dir */
"SysDir",
NULL /* call GetSystemDirectory() instead */
},
{ /* 12 (LDID_IOS) = IOSubSys dir */
NULL, /* FIXME: registry string ? */
"SYSTEM\\IOSUBSYS"
},
{ /* 13 (LDID_CMD) = COMMAND dir */
NULL, /* FIXME: registry string ? */
"COMMAND"
},
{ /* 14 (LDID_CPL) = control panel dir */
NULL,
""
},
{ /* 15 (LDID_PRINT) = windows printer dir */
NULL,
"SYSTEM" /* correct ?? */
},
{ /* 16 (LDID_MAIL) = destination mail dir */
NULL,
""
},
{ /* 17 (LDID_INF) = INF dir */
"SetupScratchDir", /* correct ? */
"INF"
},
{ /* 18 (LDID_HELP) = HELP dir */
NULL, /* ??? */
"HELP"
},
{ /* 19 (LDID_WINADMIN) = Admin dir */
"WinAdminDir",
""
},
{ /* 20 (LDID_FONTS) = Fonts dir */
NULL, /* ??? */
"FONTS"
},
{ /* 21 (LDID_VIEWERS) = Viewers */
NULL, /* ??? */
"SYSTEM\\VIEWERS"
},
{ /* 22 (LDID_VMM32) = VMM32 dir */
NULL, /* ??? */
"SYSTEM\\VMM32"
},
{ /* 23 (LDID_COLOR) = ICM dir */
"ICMPath",
"SYSTEM\\COLOR"
},
{ /* 24 (LDID_APPS) = root of boot drive ? */
"AppsDir",
"C:\\"
},
{ /* 25 (LDID_SHARED) = shared dir */
"SharedDir",
""
},
{ /* 26 (LDID_WINBOOT) = Windows boot dir */
"WinBootDir",
""
},
{ /* 27 (LDID_MACHINE) = machine specific files */
"MachineDir",
NULL
},
{ /* 28 (LDID_HOST_WINBOOT) = Host Windows boot dir */
"HostWinBootDir",
NULL
},
{ /* 29 -- not defined */
NULL,
NULL
},
{ /* 30 (LDID_BOOT) = Root of boot drive */
"BootDir",
NULL
},
{ /* 31 (LDID_BOOT_HOST) = Root of boot drive host */
"BootHost",
NULL
},
{ /* 32 (LDID_OLD_WINBOOT) = subdir of root */
"OldWinBootDir",
NULL
},
{ /* 33 (LDID_OLD_WIN) = old win dir */
"OldWinDir",
NULL
}
/* the rest (34-38) isn't too interesting, so I'll forget about it */
};
/*
* LDD == Logical Device Descriptor
* LDID == Logical Device ID
*
* The whole LDD/LDID business might go into a separate file named
* ldd.c.
* At the moment I don't know what the hell these functions are really doing.
* That's why I added reporting stubs.
* The only thing I do know is that I need them for the LDD/LDID infrastructure.
* That's why I implemented them in a way that's suitable for my purpose.
*/
static LDD_LIST *pFirstLDD = NULL;
static BOOL std_LDDs_done = FALSE;
void SETUPX_CreateStandardLDDs(void)
{
HKEY hKey = 0;
WORD n;
DWORD type, len;
LOGDISKDESC_S ldd;
char buffer[MAX_PATH];
/* has to be here, otherwise loop */
std_LDDs_done = TRUE;
RegOpenKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup", &hKey);
for (n=0; n < sizeof(LDID_Data)/sizeof(LDID_DATA); n++)
{
buffer[0] = '\0';
len = MAX_PATH;
if ( (hKey) && (LDID_Data[n].RegValName)
&& (RegQueryValueExA(hKey, LDID_Data[n].RegValName,
NULL, &type, buffer, &len) == ERROR_SUCCESS)
&& (type == REG_SZ) )
{
TRACE("found value '%s' for LDID %d\n", buffer, n);
}
else
switch(n)
{
case LDID_SRCPATH:
FIXME("LDID_SRCPATH: what exactly do we have to do here ?\n");
strcpy(buffer, "X:\\FIXME");
break;
case LDID_SYS:
GetSystemDirectoryA(buffer, MAX_PATH);
break;
case LDID_APPS:
case LDID_MACHINE:
case LDID_HOST_WINBOOT:
case LDID_BOOT:
case LDID_BOOT_HOST:
strcpy(buffer, "C:\\");
break;
default:
if (LDID_Data[n].StdString)
{
DWORD len = GetWindowsDirectoryA(buffer, MAX_PATH);
LPSTR p;
p = buffer + len;
*p++ = '\\';
strcpy(p, LDID_Data[n].StdString);
}
break;
}
if (buffer[0])
{
INIT_LDD(ldd, n);
ldd.pszPath = buffer;
TRACE("LDID %d -> '%s'\n", ldd.ldid, ldd.pszPath);
CtlSetLdd16(&ldd);
}
}
if (hKey) RegCloseKey(hKey);
}
/***********************************************************************
* CtlDelLdd (SETUPX.37)
*
* RETURN
* ERR_VCP_LDDINVALID if ldid < LDID_ASSIGN_START.
*/
RETERR16 SETUPX_DelLdd(LOGDISKID16 ldid)
{
LDD_LIST *pCurr, *pPrev = NULL;
TRACE("(%d)\n", ldid);
if (!std_LDDs_done)
SETUPX_CreateStandardLDDs();
if (ldid < LDID_ASSIGN_START)
return ERR_VCP_LDDINVALID;
pCurr = pFirstLDD;
/* search until we find the appropriate LDD or hit the end */
while ((pCurr != NULL) && (ldid > pCurr->pldd->ldid))
{
pPrev = pCurr;
pCurr = pCurr->next;
}
if ( (pCurr == NULL) /* hit end of list */
|| (ldid != pCurr->pldd->ldid) )
return ERR_VCP_LDDFIND; /* correct ? */
/* ok, found our victim: eliminate it */
if (pPrev)
pPrev->next = pCurr->next;
if (pCurr == pFirstLDD)
pFirstLDD = NULL;
HeapFree(GetProcessHeap(), 0, pCurr);
return OK;
}
/***********************************************************************
* CtlDelLdd (SETUPX.37)
*/
RETERR16 WINAPI CtlDelLdd16(LOGDISKID16 ldid)
{
FIXME("(%d); - please report this!\n", ldid);
return SETUPX_DelLdd(ldid);
}
/***********************************************************************
* CtlFindLdd (SETUPX.35)
*
* doesn't check pldd ptr validity: crash (W98SE)
*
* RETURN
* ERR_VCP_LDDINVALID if pldd->cbSize != structsize
* 1 in all other cases ??
*
*/
RETERR16 WINAPI CtlFindLdd16(LPLOGDISKDESC pldd)
{
LDD_LIST *pCurr, *pPrev = NULL;
TRACE("(%p)\n", pldd);
if (!std_LDDs_done)
SETUPX_CreateStandardLDDs();
if (pldd->cbSize != sizeof(LOGDISKDESC_S))
return ERR_VCP_LDDINVALID;
pCurr = pFirstLDD;
/* search until we find the appropriate LDD or hit the end */
while ((pCurr != NULL) && (pldd->ldid > pCurr->pldd->ldid))
{
pPrev = pCurr;
pCurr = pCurr->next;
}
if ( (pCurr == NULL) /* hit end of list */
|| (pldd->ldid != pCurr->pldd->ldid) )
return ERR_VCP_LDDFIND; /* correct ? */
memcpy(pldd, pCurr->pldd, pldd->cbSize);
/* hmm, we probably ought to strcpy() the string ptrs here */
return 1; /* what is this ?? */
}
/***********************************************************************
* CtlSetLdd (SETUPX.33)
*
* Set an LDD entry.
*
* RETURN
* ERR_VCP_LDDINVALID if pldd.cbSize != sizeof(LOGDISKDESC_S)
*
*/
RETERR16 WINAPI CtlSetLdd16(LPLOGDISKDESC pldd)
{
LDD_LIST *pCurr, *pPrev = NULL;
LPLOGDISKDESC pCurrLDD;
HANDLE heap;
BOOL is_new = FALSE;
TRACE("(%p)\n", pldd);
if (!std_LDDs_done)
SETUPX_CreateStandardLDDs();
if (pldd->cbSize != sizeof(LOGDISKDESC_S))
return ERR_VCP_LDDINVALID;
heap = GetProcessHeap();
pCurr = pFirstLDD;
/* search until we find the appropriate LDD or hit the end */
while ((pCurr != NULL) && (pldd->ldid > pCurr->pldd->ldid))
{
pPrev = pCurr;
pCurr = pCurr->next;
}
if (!pCurr || pldd->ldid != pCurr->pldd->ldid)
{
is_new = TRUE;
pCurr = HeapAlloc(heap, 0, sizeof(LDD_LIST));
pCurr->pldd = HeapAlloc(heap, 0, sizeof(LOGDISKDESC_S));
pCurr->next = NULL;
pCurrLDD = pCurr->pldd;
}
else
{
pCurrLDD = pCurr->pldd;
if (pCurrLDD->pszPath) HeapFree(heap, 0, pCurrLDD->pszPath);
if (pCurrLDD->pszVolLabel) HeapFree(heap, 0, pCurrLDD->pszVolLabel);
if (pCurrLDD->pszDiskName) HeapFree(heap, 0, pCurrLDD->pszDiskName);
}
memcpy(pCurrLDD, pldd, sizeof(LOGDISKDESC_S));
if (pldd->pszPath)
{
pCurrLDD->pszPath = HeapAlloc( heap, 0, strlen(pldd->pszPath)+1 );
strcpy( pCurrLDD->pszPath, pldd->pszPath );
}
if (pldd->pszVolLabel)
{
pCurrLDD->pszVolLabel = HeapAlloc( heap, 0, strlen(pldd->pszVolLabel)+1 );
strcpy( pCurrLDD->pszVolLabel, pldd->pszVolLabel );
}
if (pldd->pszDiskName)
{
pCurrLDD->pszDiskName = HeapAlloc( heap, 0, strlen(pldd->pszDiskName)+1 );
strcpy( pCurrLDD->pszDiskName, pldd->pszDiskName );
}
if (is_new) /* link into list */
{
if (pPrev)
{
pCurr->next = pPrev->next;
pPrev->next = pCurr;
}
if (!pFirstLDD)
pFirstLDD = pCurr;
}
return OK;
}
/***********************************************************************
* CtlAddLdd (SETUPX.36)
*
* doesn't check pldd ptr validity: crash (W98SE)
*
*/
static LOGDISKID16 ldid_to_add = LDID_ASSIGN_START;
RETERR16 WINAPI CtlAddLdd16(LPLOGDISKDESC pldd)
{
pldd->ldid = ldid_to_add++;
return CtlSetLdd16(pldd);
}
/***********************************************************************
* CtlGetLdd (SETUPX.34)
*
* doesn't check pldd ptr validity: crash (W98SE)
* What the !@#$%&*( is the difference between CtlFindLdd() and CtlGetLdd() ??
*
* RETURN
* ERR_VCP_LDDINVALID if pldd->cbSize != structsize
*
*/
static RETERR16 SETUPX_GetLdd(LPLOGDISKDESC pldd)
{
LDD_LIST *pCurr, *pPrev = NULL;
if (!std_LDDs_done)
SETUPX_CreateStandardLDDs();
if (pldd->cbSize != sizeof(LOGDISKDESC_S))
return ERR_VCP_LDDINVALID;
pCurr = pFirstLDD;
/* search until we find the appropriate LDD or hit the end */
while ((pCurr != NULL) && (pldd->ldid > pCurr->pldd->ldid))
{
pPrev = pCurr;
pCurr = pCurr->next;
}
if (pCurr == NULL) /* hit end of list */
return ERR_VCP_LDDFIND; /* correct ? */
memcpy(pldd, pCurr->pldd, pldd->cbSize);
/* hmm, we probably ought to strcpy() the string ptrs here */
return OK;
}
/**********************************************************************/
RETERR16 WINAPI CtlGetLdd16(LPLOGDISKDESC pldd)
{
FIXME("(%p); - please report this!\n", pldd);
return SETUPX_GetLdd(pldd);
}
/***********************************************************************
* CtlGetLddPath (SETUPX.38)
*
* Gets the path of an LDD.
* No crash if szPath == NULL.
* szPath has to be at least MAX_PATH_LEN bytes long.
* RETURN
* ERR_VCP_LDDUNINIT if LDD for LDID not found.
*/
RETERR16 WINAPI CtlGetLddPath16(LOGDISKID16 ldid, LPSTR szPath)
{
TRACE("(%d, %p);\n", ldid, szPath);
if (szPath)
{
LOGDISKDESC_S ldd;
INIT_LDD(ldd, ldid);
if (CtlFindLdd16(&ldd) == ERR_VCP_LDDFIND)
return ERR_VCP_LDDUNINIT;
SETUPX_GetLdd(&ldd);
strcpy(szPath, ldd.pszPath);
TRACE("ret '%s' for LDID %d\n", szPath, ldid);
}
return OK;
}
/***********************************************************************
* CtlSetLddPath (SETUPX.508)
*
* Sets the path of an LDD.
* Creates LDD for LDID if not existing yet.
*/
RETERR16 WINAPI CtlSetLddPath16(LOGDISKID16 ldid, LPSTR szPath)
{
LOGDISKDESC_S ldd;
TRACE("(%d, '%s');\n", ldid, szPath);
SetupSetDirectoryIdA( 0, ldid, szPath );
INIT_LDD(ldd, ldid);
ldd.pszPath = szPath;
return CtlSetLdd16(&ldd);
}

View file

@ -0,0 +1,197 @@
/*
* SetupAPI stubs
*
* Copyright 2000 James Hatheway
*
* 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 <stdarg.h>
#include "wine/debug.h"
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "winreg.h"
#include "setupapi.h"
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
/***********************************************************************
* TPWriteProfileString (SETUPX.62)
*/
BOOL WINAPI TPWriteProfileString16( LPCSTR section, LPCSTR entry, LPCSTR string )
{
FIXME( "%s %s %s: stub\n", debugstr_a(section), debugstr_a(entry), debugstr_a(string) );
return TRUE;
}
/***********************************************************************
* suErrorToIds (SETUPX.61)
*/
DWORD WINAPI suErrorToIds16( WORD w1, WORD w2 )
{
FIXME( "%x %x: stub\n", w1, w2 );
return 0;
}
/***********************************************************************
* SetupDiOpenClassRegKeyExW (SETUPAPI.@)
*
* WINAPI in description not given
*/
HKEY WINAPI SetupDiOpenClassRegKeyExW(const GUID* class, REGSAM access, DWORD flags, PCWSTR machine, PVOID reserved)
{
FIXME("\n");
return INVALID_HANDLE_VALUE;
}
/***********************************************************************
* SetupDiGetClassDescriptionExW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetClassDescriptionExW (const GUID* class, PWSTR desc, DWORD size, PDWORD required, PCWSTR machine, PVOID reserved)
{
FIXME("\n");
return FALSE;
}
/***********************************************************************
* SetupDiClassNameFromGuidExW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiClassNameFromGuidExW (const GUID* class, PWSTR desc, DWORD size, PDWORD required, PCWSTR machine, PVOID reserved)
{
FIXME("\n");
return FALSE;
}
/***********************************************************************
* SetupDiBuildClassInfoListExW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiBuildClassInfoListExW(DWORD flags, LPGUID list, DWORD size, PDWORD required, LPCWSTR machine, PVOID reserved)
{
FIXME("\n");
return FALSE;
}
/***********************************************************************
* SetupDiGetDeviceInfoListDetailA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetDeviceInfoListDetailA(HDEVINFO devinfo, PSP_DEVINFO_LIST_DETAIL_DATA_A devinfo_data )
{
FIXME("\n");
return FALSE;
}
/***********************************************************************
* SetupDiGetDeviceInfoListDetailW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetDeviceInfoListDetailW(HDEVINFO devinfo, PSP_DEVINFO_LIST_DETAIL_DATA_W devinfo_data )
{
FIXME("\n");
return FALSE;
}
/***********************************************************************
* SetupDiCreateDeviceInfoListA (SETUPAPI.@)
*/
HDEVINFO WINAPI SetupDiCreateDeviceInfoList(const GUID *class, HWND parend)
{
FIXME("\n");
return FALSE;
}
/***********************************************************************
* SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
*/
HDEVINFO WINAPI SetupDiCreateDeviceInfoListExW(const GUID *class, HWND parend , PCWSTR machine, PVOID reserved)
{
FIXME("\n");
return FALSE;
}
/***********************************************************************
* (SETUPAPI.@)
*
* NO WINAPI in description given
*/
HDEVINFO WINAPI SetupDiGetClassDevsExA(const GUID *class, PCSTR filter, HWND parent, DWORD flags, HDEVINFO deviceset, PCSTR machine, PVOID reserved)
{
FIXME("filter %s machine %s\n",debugstr_a(filter),debugstr_a(machine));
return FALSE;
}
/***********************************************************************
* (SETUPAPI.@)
*
* NO WINAPI in description given
*/
HDEVINFO WINAPI SetupDiGetClassDevsExW(const GUID *class, PCWSTR filter, HWND parent, DWORD flags, HDEVINFO deviceset, PCWSTR machine, PVOID reserved)
{
FIXME("\n");
return FALSE;
}
/***********************************************************************
* SetupDiClassGuidsFromNameExW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiClassGuidsFromNameExW(LPCWSTR class, LPGUID list, DWORD size, PDWORD required, LPCWSTR machine, PVOID reserved)
{
FIXME("\n");
return FALSE;
}
/***********************************************************************
* CM_Connect_MachineW (SETUPAPI.@)
*/
DWORD WINAPI CM_Connect_MachineW(LPCWSTR name, void * machine)
{
#define CR_SUCCESS 0x00000000
#define CR_ACCESS_DENIED 0x00000033
FIXME("\n");
return CR_ACCESS_DENIED;
}
/***********************************************************************
* CM_Disconnect_Machine (SETUPAPI.@)
*/
DWORD WINAPI CM_Disconnect_Machine(DWORD handle)
{
FIXME("\n");
return CR_SUCCESS;
}
/***********************************************************************
* SetupCopyOEMInfA (SETUPAPI.@)
*/
BOOL WINAPI SetupCopyOEMInfA(PCSTR sourceinffile, PCSTR sourcemedialoc,
DWORD mediatype, DWORD copystyle, PSTR destinfname,
DWORD destnamesize, PDWORD required,
PSTR *destinfnamecomponent)
{
FIXME("stub: source %s location %s ...\n",sourceinffile, sourcemedialoc);
return FALSE;
}
/***********************************************************************
* InstallHinfSection (SETUPAPI.@)
*/
void WINAPI InstallHinfSection(HWND hwnd, HINSTANCE handle, LPCSTR cmdline, INT show)
{
FIXME("stub, hwnd %p, handle %p, cmdline %s\n", hwnd, handle, debugstr_a(cmdline));
}

View file

@ -0,0 +1,789 @@
/*
* SetupAPI virtual copy operations
*
* Copyright 2001 Andreas Mohr
*
* 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
*
* FIXME: we now rely on builtin setupapi.dll for dialog resources.
* This is bad ! We ought to have 16bit resource handling working.
*/
#include <stdarg.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winreg.h"
#include "wownt32.h"
#include "wingdi.h"
#include "winnls.h"
#include "setupapi.h"
#include "setupx16.h"
#include "setupapi_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
static FARPROC16 VCP_Proc = NULL;
static LPARAM VCP_MsgRef = 0;
static BOOL VCP_opened = FALSE;
static VCPSTATUS vcp_status;
static HINSTANCE SETUPAPI_hInstance;
static WORD VCP_Callback( LPVOID obj, UINT16 msg, WPARAM16 wParam, LPARAM lParam, LPARAM lParamRef )
{
WORD args[8];
DWORD ret = OK;
if (VCP_Proc)
{
args[7] = HIWORD(obj);
args[6] = LOWORD(obj);
args[5] = msg;
args[4] = wParam;
args[3] = HIWORD(lParam);
args[2] = LOWORD(lParam);
args[1] = HIWORD(lParamRef);
args[0] = LOWORD(lParamRef);
WOWCallback16Ex( (DWORD)VCP_Proc, WCB16_PASCAL, sizeof(args), args, &ret );
}
return (WORD)ret;
}
/****************************** VHSTR management ******************************/
/*
* This is a totally braindead implementation for now;
* I don't care about speed at all ! Size and implementation time
* is much more important IMHO. I could have created some sophisticated
* tree structure, but... what the hell ! :-)
*/
typedef struct {
DWORD refcount;
LPCSTR pStr;
} VHSTR_STRUCT;
static VHSTR_STRUCT **vhstrlist = NULL;
static VHSTR vhstr_alloc = 0;
#define VALID_VHSTR(x) ((x < vhstr_alloc) && (vhstrlist[x]) && (vhstrlist[x]->refcount))
/***********************************************************************
* vsmStringAdd (SETUPX.207)
*/
VHSTR WINAPI vsmStringAdd16(LPCSTR lpszName)
{
VHSTR n;
VHSTR index = 0xffff;
HANDLE heap;
TRACE("add string '%s'\n", lpszName);
/* search whether string already inserted */
TRACE("searching for existing string...\n");
for (n = 0; n < vhstr_alloc; n++)
{
if ((vhstrlist[n]) && (vhstrlist[n]->refcount))
{
TRACE("checking item: %d\n", n);
if (!strcmp(vhstrlist[n]->pStr, lpszName))
{
TRACE("found\n");
vhstrlist[n]->refcount++;
return n;
}
}
}
/* hmm, not found yet, let's insert it */
TRACE("inserting item\n");
for (n = 0; n < vhstr_alloc; n++)
{
if ((!(vhstrlist[n])) || (!(vhstrlist[n]->refcount)))
{
index = n;
break;
}
}
heap = GetProcessHeap();
if (n == vhstr_alloc) /* hmm, no free index found yet */
{
index = vhstr_alloc;
vhstr_alloc += 20;
if (vhstrlist)
vhstrlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, vhstrlist,
sizeof(VHSTR_STRUCT *) * vhstr_alloc);
else
vhstrlist = HeapAlloc(heap, HEAP_ZERO_MEMORY,
sizeof(VHSTR_STRUCT *) * vhstr_alloc);
}
if (index == 0xffff)
return 0xffff; /* failure */
if (!vhstrlist[index])
vhstrlist[index] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VHSTR_STRUCT));
vhstrlist[index]->refcount = 1;
vhstrlist[index]->pStr = HeapAlloc(heap, 0, strlen(lpszName)+1);
strcpy((LPSTR)vhstrlist[index]->pStr, lpszName);
return index;
}
/***********************************************************************
* vsmStringDelete (SETUPX.206)
*/
INT16 WINAPI vsmStringDelete16(VHSTR vhstr)
{
if (VALID_VHSTR(vhstr))
{
vhstrlist[vhstr]->refcount--;
if (!vhstrlist[vhstr]->refcount)
{
HeapFree(GetProcessHeap(), 0, (LPSTR)vhstrlist[vhstr]->pStr);
vhstrlist[vhstr]->pStr = NULL;
}
return VCPN_OK;
}
/* string not found */
return VCPN_FAIL;
}
/*
* vsmStringFind() - not exported from a standard SETUPX.DLL, it seems
*/
VHSTR WINAPI vsmStringFind16(LPCSTR lpszName)
{
WORD n;
for (n = 0; n < vhstr_alloc; n++)
if ((vhstrlist[n]) && (vhstrlist[n]->refcount) && (!strcmp(vhstrlist[n]->pStr, lpszName)))
return n;
return 0xffff;
}
/***********************************************************************
* vsmGetStringName (SETUPX.205)
*
* Pretty correct, I guess
*/
INT16 WINAPI vsmGetStringName16(VHSTR vhstr, LPSTR lpszBuffer, int cbBuffer)
{
if (VALID_VHSTR(vhstr))
{
int len = strlen(vhstrlist[vhstr]->pStr)+1;
if (cbBuffer >= len)
{
if (lpszBuffer)
strcpy(lpszBuffer, vhstrlist[vhstr]->pStr);
return len;
}
}
return VCPN_FAIL;
}
/***********************************************************************
* vsmStringCompare (not exported from a standard SETUPX.DLL, it seems)
*/
INT16 WINAPI vsmStringCompare16(VHSTR vhstrA, VHSTR vhstrB)
{
if ((!VALID_VHSTR(vhstrA)) || (!VALID_VHSTR(vhstrB)))
return VCPN_FAIL; /* correct ? */
return strcmp(vhstrlist[vhstrA]->pStr, vhstrlist[vhstrB]->pStr);
}
/***********************************************************************
* vsmGetStringRawName (SETUPX.208)
*/
LPCSTR WINAPI vsmGetStringRawName16(VHSTR vhstr)
{
return (VALID_VHSTR(vhstr)) ? vhstrlist[vhstr]->pStr : NULL;
}
/***************************** VIRTNODE management ****************************/
static LPVIRTNODE *pvnlist = NULL;
static DWORD vn_num = 0;
static DWORD vn_last = 0;
RETERR16 VCP_VirtnodeCreate(LPVCPFILESPEC vfsSrc, LPVCPFILESPEC vfsDst, WORD fl, LPARAM lParam, LPEXPANDVTBL lpExpandVtbl)
{
HANDLE heap;
LPVIRTNODE lpvn;
RETERR16 cbres;
while (vn_last < vn_num)
{
if (pvnlist[vn_last] == NULL)
break;
vn_last++;
}
heap = GetProcessHeap();
if (vn_last == vn_num)
{
vn_num += 20;
if (pvnlist)
pvnlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, pvnlist,
sizeof(LPVIRTNODE *) * vn_num);
else
pvnlist = HeapAlloc(heap, HEAP_ZERO_MEMORY,
sizeof(LPVIRTNODE *) * vn_num);
}
pvnlist[vn_last] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VIRTNODE));
lpvn = pvnlist[vn_last];
vn_last++;
lpvn->cbSize = sizeof(VIRTNODE);
if (vfsSrc)
memcpy(&lpvn->vfsSrc, vfsSrc, sizeof(VCPFILESPEC));
if (vfsDst)
memcpy(&lpvn->vfsDst, vfsDst, sizeof(VCPFILESPEC));
lpvn->fl = fl;
lpvn->lParam = lParam;
lpvn->lpExpandVtbl = lpExpandVtbl;
lpvn->vhstrDstFinalName = 0xffff; /* FIXME: what is this ? */
cbres = VCP_Callback(lpvn, VCPM_NODECREATE, 0, 0, VCP_MsgRef);
lpvn->fl |= VFNL_CREATED;
cbres = VCP_Callback(lpvn, VCPM_NODEACCEPT, 0, 0, VCP_MsgRef);
return OK;
}
BOOL VCP_VirtnodeDelete(LPVIRTNODE lpvnDel)
{
DWORD n;
RETERR16 cbres;
for (n = 0; n < vn_last; n++)
{
if (pvnlist[n] == lpvnDel)
{
cbres = VCP_Callback(lpvnDel, VCPM_NODEDESTROY, 0, 0, VCP_MsgRef);
HeapFree(GetProcessHeap(), 0, lpvnDel);
pvnlist[n] = NULL;
return TRUE;
}
}
return FALSE;
}
/***********************************************************************
* VcpOpen (SETUPX.200)
*
* Sets up a virtual copy operation.
* This means that functions such as GenInstall()
* create a VIRTNODE struct for every file to be touched in a .INF file
* instead of actually touching the file.
* The actual copy/move/rename gets started when VcpClose or
* VcpFlush is called; several different callbacks are made
* (copy, rename, open, close, version conflicts, ...) on every file copied.
*/
RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef)
{
TRACE("(%p, %08lx)\n", vifproc, lparamMsgRef);
if (VCP_opened)
return ERR_VCP_BUSY;
VCP_Proc = (FARPROC16)vifproc;
VCP_MsgRef = lparamMsgRef;
/* load SETUPAPI needed for dialog resources etc. */
SETUPAPI_hInstance = LoadLibraryA("setupapi.dll");
if (!SETUPAPI_hInstance)
{
ERR("Could not load sibling setupapi.dll\n");
return ERR_VCP_NOMEM;
}
VCP_opened = TRUE;
return OK;
}
/***********************************************************************
* VcpQueueCopy [SETUPX.13]
*
* lpExpandVtbl seems to be deprecated.
* fl are the CNFL_xxx and VNFL_xxx flags.
* lParam are the VNLP_xxx flags.
*/
RETERR16 WINAPI VcpQueueCopy16(
LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
LPEXPANDVTBL lpExpandVtbl,
WORD fl, LPARAM lParam
)
{
VCPFILESPEC vfsSrc, vfsDst;
if (!VCP_opened)
return ERR_VCP_NOTOPEN;
TRACE("srcdir: %s, srcfile: %s, dstdir: %s, dstfile: %s\n",
lpszSrcDir, lpszSrcFileName, lpszDstDir, lpszDstFileName);
TRACE("ldidSrc == %d, ldidDst == %d\n", ldidSrc, ldidDst);
vfsSrc.ldid = ldidSrc;
vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
vfsDst.ldid = ldidDst;
vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, fl, lParam,
lpExpandVtbl);
}
/***********************************************************************
* VcpQueueDelete [SETUPX.17]
*
* Is lParamRef the same as lParam in VcpQueueCopy ?
* Damn docu !! Err... which docu ?
*/
RETERR16 WINAPI VcpQueueDelete16(
LPCSTR lpszDstFileName,
LPCSTR lpszDstDir,
LOGDISKID16 ldidDst,
LPARAM lParamRef
)
{
VCPFILESPEC vfsDst;
if (!VCP_opened)
return ERR_VCP_NOTOPEN;
vfsDst.ldid = ldidDst;
vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
return VCP_VirtnodeCreate(NULL, &vfsDst, VNFL_DELETE, lParamRef, 0);
}
/***********************************************************************
* VcpQueueRename [SETUPX.204]
*
*/
RETERR16 WINAPI VcpQueueRename16(
LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName,
LPCSTR lpszSrcDir, LPCSTR lpszDstDir,
LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst,
LPARAM lParam
)
{
VCPFILESPEC vfsSrc, vfsDst;
if (!VCP_opened)
return ERR_VCP_NOTOPEN;
vfsSrc.ldid = ldidSrc;
vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir);
vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName);
vfsDst.ldid = ldidDst;
vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir);
vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName);
return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, VNFL_RENAME, lParam,
0);
}
/***********************************************************************
* VcpEnumFiles (SETUPX.@)
*/
INT16 WINAPI VcpEnumFiles(VCPENUMPROC vep, LPARAM lParamRef)
{
WORD n;
for (n = 0; n < vn_last; n++)
vep(pvnlist[n], lParamRef);
return 0; /* FIXME: return value ? */
}
/***********************************************************************
* VcpExplain (SETUPX.411)
*/
LPCSTR WINAPI VcpExplain16(LPVIRTNODE lpVn, DWORD dwWhat)
{
static char buffer[MAX_PATH]; /* FIXME: is this how it's done ? */
buffer[0] = '\0';
switch (dwWhat)
{
case VCPEX_SRC_FULL:
case VCPEX_DST_FULL:
{
LPVCPFILESPEC lpvfs =
(dwWhat == VCPEX_SRC_FULL) ? &lpVn->vfsSrc : &lpVn->vfsDst;
/* if we have an ldid, use it, otherwise use the string */
/* from the vhstrlist array */
if (lpvfs->ldid != 0xffff)
CtlGetLddPath16(lpvfs->ldid, buffer);
else
strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrDir));
strcat(buffer, "\\");
strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrFileName));
}
break;
default:
FIXME("%ld unimplemented !\n", dwWhat);
strcpy(buffer, "Unknown error");
break;
}
return buffer;
}
RETERR16 VCP_CheckPaths(void)
{
DWORD n;
LPVIRTNODE lpvn;
RETERR16 cbres;
cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKSTART, 0, 0, VCP_MsgRef);
for (n = 0; n < vn_num; n++)
{
lpvn = pvnlist[n];
if (!lpvn) continue;
/* FIXME: check paths of all VIRTNODEs here ! */
cbres = VCP_Callback(&lpvn->vfsDst, VCPM_CHECKPATH, 0, (DWORD)lpvn, VCP_MsgRef);
}
cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKEND, 0, 0, VCP_MsgRef);
return OK;
}
RETERR16 VCP_CopyFiles(void)
{
char fn_src[MAX_PATH], fn_dst[MAX_PATH];
RETERR16 res = OK, cbres;
DWORD n;
LPVIRTNODE lpvn;
cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYSTART, 0, 0, VCP_MsgRef);
for (n = 0; n < vn_num; n++)
{
lpvn = pvnlist[n];
if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_COPY)) continue;
/* FIXME: need to send VCPM_VSTATNEWDISK notification sometimes */
strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
/* FIXME: what is this VCPM_VSTATWRITE here for ?
* I guess it's to signal successful destination file creation */
cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
/* FIXME: need to do the file copy in small chunks for notifications */
TRACE("copying '%s' to '%s'\n", fn_src, fn_dst);
/* perform the file copy */
if (!(CopyFileA(fn_src, fn_dst,
(lpvn->fl & VNLP_COPYIFEXISTS) ? FALSE : TRUE )))
{
ERR("error copying, src: %s -> dst: %s\n", fn_src, fn_dst);
res = ERR_VCP_IOFAIL;
}
vcp_status.prgFileRead.dwSoFar++;
cbres = VCP_Callback(&vcp_status, VCPM_VSTATREAD, 0, 0, VCP_MsgRef);
vcp_status.prgFileWrite.dwSoFar++;
cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef);
}
cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYEND, 0, 0, VCP_MsgRef);
return res;
}
/***********************************************************************
* VcpFlush - internal (not exported), but documented
*
* VNFL_NOW is used for VcpFlush.
*/
RETERR16 VcpFlush16(WORD fl, LPCSTR lpszBackupDest)
{
return OK;
}
/***********************************************************************
* VcpClose (SETUPX.201)
*
* Does callbacks (-> vifproc) with VCPM_VSTATCLOSESTART,
* VCPM_VSTATCLOSEEND.
*
* fl gets VCPFL_xxx flags to indicate what to do with the
* VIRTNODEs (files to mess with) created by e.g. GenInstall()
*/
RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest)
{
RETERR16 res = OK;
WORD cbres = VCPN_PROCEED;
TRACE("(%04x, '%s')\n", fl, lpszBackupDest);
/* FIXME: needs to sort virtnodes in case VCPFL_INSPECIFIEDORDER
* is not set. This is done by VCP_Callback(VCPM_NODECOMPARE) */
TRACE("#1\n");
memset(&vcp_status, 0, sizeof(VCPSTATUS));
/* yes, vcp_status.cbSize is 0 ! */
TRACE("#2\n");
cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSESTART, 0, 0, VCP_MsgRef);
TRACE("#3\n");
res = VCP_CheckPaths();
TRACE("#4\n");
if (res != OK)
return res; /* is this ok ? */
VCP_CopyFiles();
TRACE("#5\n");
cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSEEND, 0, 0, VCP_MsgRef);
TRACE("#6\n");
VCP_Proc = NULL;
FreeLibrary(SETUPAPI_hInstance);
VCP_opened = FALSE;
return OK;
}
RETERR16 VCP_RenameFiles(void)
{
char fn_src[MAX_PATH], fn_dst[MAX_PATH];
RETERR16 res = OK, cbres;
DWORD n;
LPVIRTNODE lpvn;
cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMESTART, 0, 0, VCP_MsgRef);
for (n = 0; n < vn_num; n++)
{
lpvn = pvnlist[n];
if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_RENAME)) continue;
strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL));
strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL));
cbres = VCP_Callback(&lpvn->vfsDst, VCPM_FILEOPENOUT, 0, (LPARAM)lpvn, VCP_MsgRef);
if (!(MoveFileExA(fn_src, fn_dst, MOVEFILE_REPLACE_EXISTING)))
res = ERR_VCP_IOFAIL;
else
VCP_VirtnodeDelete(lpvn);
}
cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMEEND, 0, 0, VCP_MsgRef);
return res;
}
/***********************************************************************
* vcpDefCallbackProc (SETUPX.202)
*/
RETERR16 WINAPI vcpDefCallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
LPARAM lParam, LPARAM lParamRef)
{
static int count = 0;
if (count < 10)
FIXME("(%p, %04x, %04x, %08lx, %08lx) - what to do here ?\n",
lpvObj, uMsg, wParam, lParam, lParamRef);
count++;
return OK;
}
/********************* point-and-click stuff from here ***********************/
static HWND hDlgCopy = 0;
static HKEY hKeyFiles = 0, hKeyRename = 0, hKeyConflict = 0;
static char BackupDir[12];
static INT_PTR CALLBACK VCP_UI_FileCopyDlgProc(HWND hWndDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
INT_PTR retval = FALSE;
if (iMsg == WM_INITDIALOG)
{
ShowWindow(hWndDlg, SW_SHOWNORMAL);
UpdateWindow(hWndDlg);
retval = TRUE;
}
return retval;
}
BOOL VCP_UI_GetDialogTemplate(LPCVOID *template32)
{
HRSRC hResInfo;
HGLOBAL hDlgTmpl32;
if (!(hResInfo = FindResourceA(SETUPAPI_hInstance, MAKEINTRESOURCEA(COPYFILEDLGORD), (LPSTR)RT_DIALOG)))
return FALSE;
if (!(hDlgTmpl32 = LoadResource(SETUPAPI_hInstance, hResInfo )) ||
!(*template32 = LockResource( hDlgTmpl32 )))
return FALSE;
return TRUE;
}
static LRESULT WINAPI
VCP_UI_FileCopyWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg != WM_CREATE)
return DefWindowProcA (hwnd, uMsg, wParam, lParam);
switch (uMsg)
{
case WM_CREATE:
return 0;
default:
FIXME("%04x: unhandled.\n", uMsg);
}
return 0;
}
void VCP_UI_RegisterProgressClass(void)
{
static BOOL registered = FALSE;
WNDCLASSA wndClass;
if (registered)
return;
registered = TRUE;
ZeroMemory (&wndClass, sizeof(WNDCLASSA));
wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = (WNDPROC)VCP_UI_FileCopyWndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hCursor = LoadCursorA (0, (LPSTR)IDC_ARROW);
wndClass.hbrBackground = NULL;
wndClass.lpszClassName = "setupx_progress";
RegisterClassA (&wndClass);
}
RETERR16 VCP_UI_NodeCompare(LPVIRTNODE vn1, LPVIRTNODE vn2)
{
LPCSTR file1, file2;
file1 = vsmGetStringRawName16(vn1->vfsSrc.vhstrFileName);
file2 = vsmGetStringRawName16(vn2->vfsSrc.vhstrFileName);
return (RETERR16)strcmp(file1, file2);
}
RETERR16 VCP_UI_CopyStart(void)
{
LPCVOID template32;
char buf[256]; /* plenty */
BOOL dirty;
DWORD len;
/* FIXME: should be registered at DLL startup instead */
VCP_UI_RegisterProgressClass();
if (!(VCP_UI_GetDialogTemplate(&template32)))
return VCPN_FAIL;
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;
strcat(buf, REGPART_RENAME);
if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyRename))
return VCPN_FAIL;
if (RegCreateKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT, &hKeyConflict))
return VCPN_FAIL;
len = 1;
if (!(RegQueryValueExA(hKeyConflict, "Dirty", NULL, 0, (LPBYTE)&dirty, &len)))
{
/* FIXME: what does SETUPX.DLL do in this case ? */
MESSAGE("Warning: another program using SETUPX is already running ! Failed.\n");
return VCPN_FAIL;
}
dirty = TRUE;
if (RegSetValueExA(hKeyConflict, "Dirty", 0, REG_BINARY, (LPBYTE)&dirty, 1))
return VCPN_FAIL;
len = 12;
if (!(RegQueryValueExA(hKeyConflict, "BackupDirectory", NULL, 0, BackupDir, &len)))
strcpy(BackupDir, "VCM");
/* create C:\WINDOWS\[BackupDir] and set registry key to it */
GetWindowsDirectoryA(buf, 256);
strcat(buf, "\\");
strcat(buf, BackupDir);
if (!(CreateDirectoryA(buf, NULL)))
return VCPN_FAIL;
if (RegSetValueExA(hKeyConflict, "BackupDirectory", 0, REG_SZ, (LPBYTE)buf, strlen(buf)+1))
return VCPN_FAIL;
RegCloseKey(hKeyConflict);
return VCPN_OK;
}
/***********************************************************************
* vcpUICallbackProc (SETUPX.213)
*/
RETERR16 WINAPI vcpUICallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam,
LPARAM lParam, LPARAM lParamRef)
{
static int count = 0;
RETERR16 res = VCPN_OK, cbres;
if (count < 5)
FIXME("(%p, %04x, %04x, %08lx, %08lx) - semi-stub\n",
lpvObj, uMsg, wParam, lParam, lParamRef);
count++;
switch (uMsg)
{
/* unused messages, it seems */
case VCPM_DISKPREPINFO:
case VCPM_FILENEEDED:
case VCPM_NODECREATE:
case VCPM_NODEACCEPT:
case VCPM_VSTATCLOSESTART:
case VCPM_VSTATPATHCHECKSTART:
case VCPM_VSTATPATHCHECKEND:
case VCPM_CHECKPATH:
break;
/* the real stuff */
case VCPM_NODECOMPARE:
res = VCP_UI_NodeCompare((LPVIRTNODE)lpvObj, (LPVIRTNODE)lParam);
break;
case VCPM_VSTATREAD:
break;
case VCPM_VSTATWRITE:
cbres = VCP_Callback(&vcp_status, VCPM_DISKPREPINFO, 0, 0, VCP_MsgRef);
break;
case VCPM_VSTATCLOSEEND:
RegCloseKey(hKeyFiles);
RegCloseKey(hKeyRename);
RegDeleteKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT);
break;
case VCPM_VSTATCOPYSTART:
res = VCP_UI_CopyStart();
break;
case VCPM_VSTATCOPYEND:
if (hDlgCopy) DestroyWindow(hDlgCopy);
break;
default:
FIXME("unhandled msg 0x%04x\n", uMsg);
}
return res;
}