diff --git a/dlls/setupapi/install.c b/dlls/setupapi/install.c index 75c3007e268..939f2ac6b93 100644 --- a/dlls/setupapi/install.c +++ b/dlls/setupapi/install.c @@ -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; } diff --git a/dlls/setupapi/parser.c b/dlls/setupapi/parser.c index 87066aa678e..8c760f01b75 100644 --- a/dlls/setupapi/parser.c +++ b/dlls/setupapi/parser.c @@ -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" @@ -999,6 +1000,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.@) */ diff --git a/dlls/setupapi/queue.c b/dlls/setupapi/queue.c index b40f3047a04..38b11151e07 100644 --- a/dlls/setupapi/queue.c +++ b/dlls/setupapi/queue.c @@ -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 ); } diff --git a/dlls/setupapi/setupapi_private.h b/dlls/setupapi/setupapi_private.h index 443c3e4e73a..7cd40e4f146 100644 --- a/dlls/setupapi/setupapi_private.h +++ b/dlls/setupapi/setupapi_private.h @@ -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 */ diff --git a/include/setupapi.h b/include/setupapi.h index bd7e683de83..d9c33fef3a8 100644 --- a/include/setupapi.h +++ b/include/setupapi.h @@ -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