On 1/12/06, Markus Amsler markus.amsler@oribi.org wrote:
ChangeLog: Implement LaunchINFSection on top of DoInfInstall
I'm afraid this implementation isn't correct. DoInfInstall calls SetupInstallFromInfSection which only concerns the Install section of an INF file. SetupInstallFromInfSection and consequently DoInfInstall cannot provide enough functionality for LaunchINFSection/Ex. LaunchINFSection/Ex also takes into acount reg and file saves (see Reg/FileSaveRestore), per user sections (see SetPerUserSecValues), registering ocx's, extracting cabinets, and a whole mush of other intricacies. LaunchINFSection/Ex basically combines all the other functions of advpack into a monstrosity of functionality. I'm working my way towards fully implementing LaunchINFSection/Ex, but I've got to finish the lower levels first, so if you'd like to help in this direction, take a look at the stubs I've mentioned in advpack. I appreciate your effort in this implementation, but it will do more harm than good because we'll have to take it out when it comes time to fully implement LaunchINFSection.
-- James Hawkins
James Hawkins wrote:
On 1/12/06, Markus Amsler markus.amsler@oribi.org wrote:
ChangeLog: Implement LaunchINFSection on top of DoInfInstall
I'm afraid this implementation isn't correct. DoInfInstall calls SetupInstallFromInfSection which only concerns the Install section of an INF file. SetupInstallFromInfSection and consequently DoInfInstall cannot provide enough functionality for LaunchINFSection/Ex. LaunchINFSection/Ex also takes into acount reg and file saves (see Reg/FileSaveRestore), per user sections (see SetPerUserSecValues), registering ocx's, extracting cabinets, and a whole mush of other intricacies. LaunchINFSection/Ex basically combines all the other functions of advpack into a monstrosity of functionality. I'm working my way towards fully implementing LaunchINFSection/Ex, but I've got to finish the lower levels first, so if you'd like to help in this direction, take a look at the stubs I've mentioned in advpack. I appreciate your effort in this implementation, but it will do more harm than good because we'll have to take it out when it comes time to fully implement LaunchINFSection.
-- James Hawkins
I'm aware of that. We just have different approaches. Mine is from higher level functions to lower level, yours the other way round. Our approaches are not exclusive, we can simply meet in the middle (I know i took the easier way :-)). Is that OK for you? I think there's no problem if this patches get applied. The next patch will implement an advanced inf section infrastructure, based on setupapi install.c (See atachement, still needs some work).
The same comments for LaunchINFSection apply here as well. If these three APIs just call DoInfInstall, then what's the point in having them?
Don't ask me, ask Microsoft. My tests/understanding show all four of them do basically the same work. I tested Run(Post|Pre)SetupCommands. All four functions execute this advanced inf section (so i guess this is also true for the others).
Microsofts idea was probably to use them from different places: - DoInfInstall: Internal function that does the real work, with backup,sync/async (undocumented, parameters packed) - RunSetupCommand: Programming API function used from C/C++/.., with backup, sync/async (partially documented, nice function parameters) - LaunchINFSection: useable from commandline, rundll32 without backup, synchronus (documented, arguments packed in a string) - LaunchINFSectionEx: useable from commandline, rundll32 with backup, synchronus (documented, arguments packed in a string) But now every function gets called from programs.
Markus Amsler
c3ccdde665347bf136a251586eaf31a86b43bc21 diff --git a/dlls/advpack/install.c b/dlls/advpack/install.c index 72d8f3c..fbce5f4 100644 --- a/dlls/advpack/install.c +++ b/dlls/advpack/install.c @@ -3,6 +3,7 @@ * * Copyright 2004 Huw D M Davies * Copyright 2005 Sami Aario + * Copyright 2005 Markus Amsler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,6 +26,7 @@ #include "winbase.h" #include "winuser.h" #include "winreg.h" +#include "winternl.h" #include "winver.h" #include "winnls.h" #include "setupapi.h" @@ -34,6 +36,177 @@
WINE_DEFAULT_DEBUG_CHANNEL(advpack);
+typedef BOOL (*iterate_fields_func)( HINF hinf, PCWSTR field, void *arg ); + +/* Unicode constants */ +static const WCHAR RegisterOCXs[] = {'R','e','g','i','s','t','e','r','O','C','X','s',0}; +static const WCHAR UnRegisterOCXs[] = {'U','n','R','e','g','i','s','t','e','r','O','C','X','s',0}; +static const WCHAR BeginPrompt[] = {'B','e','g','i','n','P','r','o','m','p','t',0}; +static const WCHAR EndPrompt[] = {'E','n','d','P','r','o','m','p','t',0}; +static const WCHAR DelDirs[] = {'D','e','l','D','i','r','s',0}; +static const WCHAR BackupReg[] = {'B','a','c','k','u','p','R','e','g',0}; +static const WCHAR RunPreSetupCommands[] = {'R','u','n','P','r','e','S','e','t','u','p', + 'C','o','m','m','a','n','d','s',0}; +static const WCHAR RunPostSetupCommands[] = {'R','u','n','P','o','s','t','S','e','t','u','p', + 'C','o','m','m','a','n','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; +} + +static BOOL registerocxs_callback( HINF hinf, PCWSTR field, void *arg ) +{ + FIXME( "should do registerocxs %s\n", debugstr_w(field) ); + return TRUE; +} + +static BOOL unregisterocxs_callback( HINF hinf, PCWSTR field, void *arg ) +{ + FIXME( "should do unregisterocxs %s\n", debugstr_w(field) ); + return TRUE; +} + +static BOOL beginprompt_callback( HINF hinf, PCWSTR field, void *arg ) +{ + FIXME( "should do beginprompt %s\n", debugstr_w(field) ); + return TRUE; +} + +static BOOL endprompt_callback( HINF hinf, PCWSTR field, void *arg ) +{ + FIXME( "should do endprompt %s\n", debugstr_w(field) ); + return TRUE; +} + +static BOOL deldirs_callback( HINF hinf, PCWSTR field, void *arg ) +{ + FIXME( "should do deldirs %s\n", debugstr_w(field) ); + return TRUE; +} + +static BOOL backupreg_callback( HINF hinf, PCWSTR field, void *arg ) +{ + FIXME( "should do backupreg %s\n", debugstr_w(field) ); + return TRUE; +} + +static BOOL runpresetupcommands_callback( HINF hinf, PCWSTR field, void *arg ) +{ + FIXME( "should do runpresetupcommands %s\n", debugstr_w(field) ); + return TRUE; +} + +static BOOL runpostsetupcommands_callback( HINF hinf, PCWSTR field, void *arg ) +{ + FIXME( "should do runpostupcommands %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 )) + { + WARN("callback failed for %s %s err %ld\n", + debugstr_w(section), debugstr_w(buffer), GetLastError() ); + goto done; + } + } + ok = SetupFindNextMatchLineW( &context, key, &context ); + } + ret = TRUE; + done: + if (buffer && buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer ); + return ret; +} + +/*********************************************************************** + * do_before_install + * + * Performs advanced inf actions before normal setup. + * + * TODO: + * implement PreRollback + */ +static BOOL do_before_install( HINF hinf, PCWSTR section ) +{ + if (!iterate_section_fields( hinf, section, BeginPrompt, beginprompt_callback, NULL )) + return FALSE; + + if (!iterate_section_fields( hinf, section, BackupReg, backupreg_callback, NULL )) + return FALSE; + + if (!iterate_section_fields( hinf, section, RegisterOCXs, registerocxs_callback, NULL )) + return FALSE; + + if (!iterate_section_fields( hinf, section, RunPreSetupCommands, + runpresetupcommands_callback, NULL )) + return FALSE; + + if (!iterate_section_fields( hinf, section, DelDirs, deldirs_callback, NULL )) + return FALSE; + + return TRUE; +} + +/*********************************************************************** + * do_after_install + * + * Performs advanced inf actions after normal setup. + */ +static BOOL do_after_install( HINF hinf, PCWSTR section ) +{ + if (!iterate_section_fields( hinf, section, UnRegisterOCXs, unregisterocxs_callback, NULL )) + return FALSE; + + if (!iterate_section_fields( hinf, section, RunPostSetupCommands, + runpostsetupcommands_callback, NULL )) + return FALSE; + + if (!iterate_section_fields( hinf, section, EndPrompt, endprompt_callback, NULL )) + return FALSE; + + return TRUE; +} + /*********************************************************************** * DoInfInstall (ADVPACK.@) * @@ -48,16 +221,25 @@ WINE_DEFAULT_DEBUG_CHANNEL(advpack); */ HRESULT WINAPI DoInfInstall(LPCINFINSTALLPARAMS setup) { - BOOL ret; + BOOL ret = FALSE; HINF hinf; void *callback_context; + UNICODE_STRING sectionW;
TRACE("%p %s %s %s %s\n", setup->hwnd, debugstr_a(setup->title), debugstr_a(setup->inf_name), debugstr_a(setup->dir), debugstr_a(setup->section_name)); - + hinf = SetupOpenInfFileA(setup->inf_name, NULL, INF_STYLE_WIN4, NULL); - if (hinf == INVALID_HANDLE_VALUE) return HRESULT_FROM_WIN32(GetLastError()); + if (hinf == INVALID_HANDLE_VALUE) + goto done; + + if (!RtlCreateUnicodeStringFromAsciiz( §ionW, setup->section_name )) + goto done; + + ret = do_before_install(hinf, sectionW.Buffer); + if (!ret) + goto done_free;
callback_context = SetupInitDefaultQueueCallback(setup->hwnd);
@@ -65,8 +247,16 @@ HRESULT WINAPI DoInfInstall(LPCINFINSTAL NULL, NULL, 0, SetupDefaultQueueCallbackA, callback_context, NULL, NULL); SetupTermDefaultQueueCallback(callback_context); + if (!ret) + goto done_close; + + ret = do_after_install(hinf, sectionW.Buffer); + + done_close: SetupCloseInfFile(hinf); - + done_free: + RtlFreeUnicodeString( §ionW ); + done: return ret ? S_OK : HRESULT_FROM_WIN32(GetLastError()); }
On 1/13/06, Markus Amsler markus.amsler@oribi.org wrote:
I'm aware of that. We just have different approaches. Mine is from higher level functions to lower level, yours the other way round. Our approaches are not exclusive, we can simply meet in the middle (I know i took the easier way :-)). Is that OK for you? I think there's no problem if this patches get applied. The next patch will implement an advanced inf section infrastructure, based on setupapi install.c (See atachement, still needs some work).
The problem with meeting in the middle is that once the lower level APIs are implemented, and the install APIs mostly implemented, we'll have to try to squeeze in the correct functionality provided by the lower level APIs, which will leave a big mess. A similar process led to our implementation of SHFileOperation...look how that turned out :)
The same comments for LaunchINFSection apply here as well. If these three APIs just call DoInfInstall, then what's the point in having them?
Don't ask me, ask Microsoft. My tests/understanding show all four of them do basically the same work. I tested Run(Post|Pre)SetupCommands. All four functions execute this advanced inf section (so i guess this is also true for the others).
You're right in that they all pretty much do the same basic operation, but they don't do it by calling DoInfInstall. We need to add more test cases to the test suite. It's a pain to create the INF files on the fly, but I've added the yuck part already, so you just have to add the appropriate append_str to the INF. Another step I'm going to take is to set up the INF tests to use a cabinet file as well as some of the more minute details. The bottom line is that we need to do some more testing into what all of these functions do and what their roles are. I know you want to get the fix in for bug 3636, but we can't rush it by putting in a temporary hack (I don't mean hack as in poor quality, just not the correct solution.)
A comment on your patch: since all the advpack APIs are ansi, you don't need to bother converting to unicode, because we shouldn't be calling any unicode APIs and we won't get any unicode input.
-- James Hawkins