Commit cb283489 authored by Alexandre Julliard's avatar Alexandre Julliard

Added support for the RegisterDlls section (partly based on a patch by

Chris Morgan).
parent 67e2d6cb
......@@ -51,6 +51,14 @@ struct registry_callback_info
BOOL delete;
};
/* info passed to callback functions dealing with registering dlls */
struct register_dll_info
{
PSP_FILE_CALLBACK_W callback;
PVOID callback_context;
BOOL unregister;
};
typedef BOOL (*iterate_fields_func)( HINF hinf, PCWSTR field, void *arg );
/* Unicode constants */
......@@ -63,6 +71,7 @@ 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};
static const WCHAR RegisterDlls[] = {'R','e','g','i','s','t','e','r','D','l','l','s',0};
/***********************************************************************
......@@ -420,6 +429,153 @@ static BOOL registry_callback( HINF hinf, PCWSTR field, void *arg )
}
/***********************************************************************
* do_register_dll
*
* Register or unregister a dll.
*/
static BOOL do_register_dll( const struct register_dll_info *info, const WCHAR *path,
INT flags, INT timeout, const WCHAR *args )
{
HMODULE module;
HRESULT res;
SP_REGISTER_CONTROL_STATUSW status;
status.cbSize = sizeof(status);
status.FileName = path;
status.FailureCode = SPREG_SUCCESS;
status.Win32Error = ERROR_SUCCESS;
if (info->callback)
{
switch(info->callback( info->callback_context, SPFILENOTIFY_STARTREGISTRATION,
(UINT_PTR)&status, !info->unregister ))
{
case FILEOP_ABORT:
SetLastError( ERROR_OPERATION_ABORTED );
return FALSE;
case FILEOP_SKIP:
return TRUE;
case FILEOP_DOIT:
break;
}
}
if (!(module = LoadLibraryExW( path, 0, LOAD_WITH_ALTERED_SEARCH_PATH )))
{
WARN( "could not load %s\n", debugstr_w(path) );
status.FailureCode = SPREG_LOADLIBRARY;
status.Win32Error = GetLastError();
goto done;
}
if (flags & FLG_REGSVR_DLLREGISTER)
{
const char *entry_point = info->unregister ? "DllUnregisterServer" : "DllRegisterServer";
HRESULT (WINAPI *func)(void) = (void *)GetProcAddress( module, entry_point );
if (!func)
{
status.FailureCode = SPREG_GETPROCADDR;
status.Win32Error = GetLastError();
goto done;
}
TRACE( "calling %s in %s\n", entry_point, debugstr_w(path) );
res = func();
if (FAILED(res))
{
WARN( "calling %s in %s returned error %lx\n", entry_point, debugstr_w(path), res );
status.FailureCode = SPREG_REGSVR;
status.Win32Error = res;
goto done;
}
}
if (flags & FLG_REGSVR_DLLINSTALL)
{
HRESULT (WINAPI *func)(BOOL,LPCWSTR) = (void *)GetProcAddress( module, "DllInstall" );
if (!func)
{
status.FailureCode = SPREG_GETPROCADDR;
status.Win32Error = GetLastError();
goto done;
}
TRACE( "calling DllInstall(%d,%s) in %s\n",
!info->unregister, debugstr_w(args), debugstr_w(path) );
res = func( !info->unregister, args );
if (FAILED(res))
{
WARN( "calling DllInstall in %s returned error %lx\n", debugstr_w(path), res );
status.FailureCode = SPREG_REGSVR;
status.Win32Error = res;
goto done;
}
}
done:
if (module) FreeLibrary( module );
if (info->callback) info->callback( info->callback_context, SPFILENOTIFY_ENDREGISTRATION,
(UINT_PTR)&status, !info->unregister );
return TRUE;
}
/***********************************************************************
* register_dlls_callback
*
* Called once for each RegisterDlls entry in a given section.
*/
static BOOL register_dlls_callback( HINF hinf, PCWSTR field, void *arg )
{
struct register_dll_info *info = arg;
INFCONTEXT context;
BOOL ret = TRUE;
BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
for (; ok; ok = SetupFindNextLine( &context, &context ))
{
WCHAR *path, *args, *p;
WCHAR buffer[MAX_INF_STRING_LENGTH];
INT flags, timeout;
/* get directory */
if (!(path = PARSER_get_dest_dir( &context ))) continue;
/* get dll name */
if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
goto done;
if (!(p = HeapReAlloc( GetProcessHeap(), 0, path,
(strlenW(path) + strlenW(buffer) + 2) * sizeof(WCHAR) ))) goto done;
path = p;
p += strlenW(p);
if (p == path || p[-1] != '\\') *p++ = '\\';
strcpyW( p, buffer );
/* get flags */
if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
/* get timeout */
if (!SetupGetIntField( &context, 5, &timeout )) timeout = 60;
/* get command line */
args = NULL;
if (SetupGetStringFieldW( &context, 6, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
args = buffer;
ret = do_register_dll( info, path, flags, timeout, args );
done:
HeapFree( GetProcessHeap(), 0, path );
if (!ret) break;
}
return ret;
}
static BOOL update_ini_callback( HINF hinf, PCWSTR field, void *arg )
{
INFCONTEXT context;
......@@ -512,7 +668,8 @@ static BOOL iterate_section_fields( HINF hinf, PCWSTR section, PCWSTR key,
goto done;
if (!callback( hinf, buffer, arg ))
{
ERR("callback failed for %s %s\n", debugstr_w(section), debugstr_w(buffer) );
WARN("callback failed for %s %s err %ld\n",
debugstr_w(section), debugstr_w(buffer), GetLastError() );
goto done;
}
}
......@@ -654,6 +811,38 @@ BOOL WINAPI SetupInstallFromInfSectionW( HWND owner, HINF hinf, PCWSTR section,
return FALSE;
}
if (flags & SPINST_REGSVR)
{
struct register_dll_info info;
info.unregister = FALSE;
if (flags & SPINST_REGISTERCALLBACKAWARE)
{
info.callback = callback;
info.callback_context = context;
}
else info.callback = NULL;
if (!iterate_section_fields( hinf, section, RegisterDlls, register_dlls_callback, &info ))
return FALSE;
}
if (flags & SPINST_UNREGSVR)
{
struct register_dll_info info;
info.unregister = TRUE;
if (flags & SPINST_REGISTERCALLBACKAWARE)
{
info.callback = callback;
info.callback_context = context;
}
else info.callback = NULL;
if (!iterate_section_fields( hinf, section, RegisterDlls, register_dlls_callback, &info ))
return FALSE;
}
if (flags & SPINST_REGISTRY)
{
struct registry_callback_info info;
......@@ -666,7 +855,8 @@ BOOL WINAPI SetupInstallFromInfSectionW( HWND owner, HINF hinf, PCWSTR section,
if (!iterate_section_fields( hinf, section, AddReg, registry_callback, &info ))
return FALSE;
}
if (flags & (SPINST_BITREG|SPINST_REGSVR|SPINST_UNREGSVR|SPINST_PROFILEITEMS|SPINST_COPYINF))
if (flags & (SPINST_BITREG|SPINST_PROFILEITEMS|SPINST_COPYINF))
FIXME( "unsupported flags %x\n", flags );
return TRUE;
}
......@@ -36,6 +36,7 @@
#include "winternl.h"
#include "winerror.h"
#include "setupapi.h"
#include "setupapi_private.h"
#include "wine/unicode.h"
#include "wine/debug.h"
......@@ -1000,6 +1001,32 @@ const WCHAR *PARSER_get_src_root( HINF hinf )
/***********************************************************************
* PARSER_get_dest_dir
*
* retrieve a destination dir of the form "dirid,relative_path" in the given entry.
* returned buffer must be freed by caller.
*/
WCHAR *PARSER_get_dest_dir( INFCONTEXT *context )
{
const WCHAR *dir;
WCHAR *ptr, *ret;
INT dirid;
DWORD len1, len2;
if (!SetupGetIntField( context, 1, &dirid )) return NULL;
if (!(dir = DIRID_get_string( context->Inf, dirid ))) return NULL;
len1 = strlenW(dir) + 1;
if (!SetupGetStringFieldW( context, 2, NULL, 0, &len2 )) len2 = 0;
if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len1+len2) * sizeof(WCHAR) ))) return NULL;
strcpyW( ret, dir );
ptr = ret + strlenW(ret);
if (len2 && ptr > ret && ptr[-1] != '\\') *ptr++ = '\\';
if (!SetupGetStringFieldW( context, 2, ptr, len2, NULL )) *ptr = 0;
return ret;
}
/***********************************************************************
* SetupOpenInfFileA (SETUPAPI.@)
*/
HINF WINAPI SetupOpenInfFileA( PCSTR name, PCSTR class, DWORD style, UINT *error )
......
......@@ -246,6 +246,22 @@ UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
break;
case SPFILENOTIFY_STARTREGISTRATION:
case SPFILENOTIFY_ENDREGISTRATION:
{
SP_REGISTER_CONTROL_STATUSW *statusW = (SP_REGISTER_CONTROL_STATUSW *)param1;
SP_REGISTER_CONTROL_STATUSA statusA;
statusA.cbSize = sizeof(statusA);
statusA.FileName = strdupWtoA( statusW->FileName );
statusA.Win32Error = statusW->Win32Error;
statusA.FailureCode = statusW->FailureCode;
ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
(UINT_PTR)&statusA, param2 );
HeapFree( GetProcessHeap(), 0, (LPSTR)statusA.FileName );
}
break;
case SPFILENOTIFY_NEEDMEDIA:
case SPFILENOTIFY_QUEUESCAN:
FIXME("mapping for %d not implemented\n",notification);
......@@ -257,7 +273,7 @@ UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
break;
}
return ret;
return ret;
}
......@@ -348,25 +364,11 @@ static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
{
static const WCHAR Dest[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
static const WCHAR Def[] = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
const WCHAR *dir;
WCHAR *ptr, *ret;
INFCONTEXT context;
INT dirid;
DWORD len1, len2;
if (!SetupFindFirstLineW( hinf, Dest, section, &context ) &&
!SetupFindFirstLineW( hinf, Dest, Def, &context )) return NULL;
if (!SetupGetIntField( &context, 1, &dirid )) return NULL;
if (!(dir = DIRID_get_string( hinf, dirid ))) return NULL;
len1 = strlenW(dir) + 1;
if (!SetupGetStringFieldW( &context, 2, NULL, 0, &len2 )) len2 = 0;
if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len1+len2) * sizeof(WCHAR) ))) return NULL;
strcpyW( ret, dir );
ptr = ret + strlenW(ret);
if (len2 && ptr > ret && ptr[-1] != '\\') *ptr++ = '\\';
if (!SetupGetStringFieldW( &context, 2, ptr, len2, NULL )) *ptr = 0;
return ret;
return PARSER_get_dest_dir( &context );
}
......
......@@ -38,6 +38,7 @@ extern unsigned int PARSER_string_substA( struct inf_file *file, const WCHAR *te
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 );
extern WCHAR *PARSER_get_dest_dir( INFCONTEXT *context );
/* support for Ascii queue callback functions */
......
......@@ -112,10 +112,37 @@ typedef struct _SP_FILE_COPY_PARAMS_W
DECL_WINELIB_SETUPAPI_TYPE_AW(SP_FILE_COPY_PARAMS)
DECL_WINELIB_SETUPAPI_TYPE_AW(PSP_FILE_COPY_PARAMS)
typedef struct _SP_REGISTER_CONTROL_STATUSA
{
DWORD cbSize;
PCSTR FileName;
DWORD Win32Error;
DWORD FailureCode;
} SP_REGISTER_CONTROL_STATUSA, *PSP_REGISTER_CONTROL_STATUSA;
typedef struct _SP_REGISTER_CONTROL_STATUSW
{
DWORD cbSize;
PCWSTR FileName;
DWORD Win32Error;
DWORD FailureCode;
} SP_REGISTER_CONTROL_STATUSW, *PSP_REGISTER_CONTROL_STATUSW;
DECL_WINELIB_TYPE_AW(SP_REGISTER_CONTROL_STATUS)
DECL_WINELIB_TYPE_AW(PSP_REGISTER_CONTROL_STATUS)
#define SPREG_SUCCESS 0x00000000
#define SPREG_LOADLIBRARY 0x00000001
#define SPREG_GETPROCADDR 0x00000002
#define SPREG_REGSVR 0x00000003
#define SPREG_DLLINSTALL 0x00000004
#define SPREG_TIMEOUT 0x00000005
#define SPREG_UNKNOWN 0xffffffff
typedef UINT (CALLBACK *PSP_FILE_CALLBACK_A)( PVOID Context, UINT Notification,
UINT Param1, UINT Param2 );
UINT_PTR Param1, UINT_PTR Param2 );
typedef UINT (CALLBACK *PSP_FILE_CALLBACK_W)( PVOID Context, UINT Notification,
UINT Param1, UINT Param2 );
UINT_PTR Param1, UINT_PTR Param2 );
DECL_WINELIB_SETUPAPI_TYPE_AW(PSP_FILE_CALLBACK)
#define LINE_LEN 256
......@@ -365,6 +392,9 @@ DECL_WINELIB_SETUPAPI_TYPE_AW(PFILEPATHS)
#define FLG_DELREG_OPERATION_MASK (0x000000FE)
#define FLG_DELREG_MULTI_SZ_DELSTRING (FLG_DELREG_TYPE_MULTI_SZ | FLG_ADDREG_DELREG_BIT | 0x00000002)
#define FLG_REGSVR_DLLREGISTER 0x00000001
#define FLG_REGSVR_DLLINSTALL 0x00000002
/* Class installer function codes */
#define DIF_SELECTDEVICE 0x01
#define DIF_INSTALLDEVICE 0x02
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment