http://bugs.winehq.org/show_bug.cgi?id=6194
------- Additional Comments From focht@gmx.net 2007-14-05 05:11 ------- Hello,
dealing with the real installer "update/update.exe". Just a hint: the installer places a log file under $WINDIR/KB842773.log
After accepting EULA, it comes up with error messagebox "The update.ver file is not correct".
The reason is the way wine setupapi currently handles .inf files.
--- snip trace --- 0028:Call setupapi.SetupOpenInfFileA(60e098ac "b:\temp\update\update.ver",00000000,00000001,00000000) ret=01037e79 ... 0028:Call KERNEL32.MultiByteToWideChar(00000000,00000000,005f0000 "[SourceFileInfo]\r\nsp1qfe\bitsinst.exe=250B3702C7CCD7C2F9E4DAA1555C933E,000600060A28062C,27136,SP1QFE\r\nsp1qfe\bitsprx2.dll=4EBEA67F4BB4EB402E725CA7CA2857AE,000600060A280621,7680,SP1QFE\r\nsp1qfe\bitsprx3.dll=C788A1D9330DA011EF25E95D3BC7BDE5,000600060A280621,7168,SP1QFE\r\nsp1qfe\qmgr.dll=696AC"...,0000025a,001872e8,0000025a) ret=604f6b7a ... Ret setupapi.SetupOpenInfFileA() retval=ffffffff ret=01037e79 --- snip trace ---
SetupOpenInfFileA -> SetupOpenInfFileW -> parse_file
Offending code:
--- snip dlls/setupapi/parser.c ---
static struct inf_file *parse_file( HANDLE handle, const WCHAR *class, UINT *error_line ) { ...
if (!err) /* now check signature */ { int version_index = find_section( file, Version ); if (version_index != -1) { struct line *line = find_line( file, version_index, Signature ); if (line && line->nb_fields > 0) { struct field *field = file->fields + line->first_field; if (!strcmpiW( field->text, Chicago )) goto done; if (!strcmpiW( field->text, WindowsNT )) goto done; if (!strcmpiW( field->text, Windows95 )) goto done; } } if (error_line) *error_line = 0; err = ERROR_WRONG_INF_STYLE; } ... } --- snip dlls/setupapi/parser.c ---
Wine is too strict here. The windows installer uses setupapi to parse ini-style files, which doesnt contain the "[Version]" section. Windows setupapi accepts this.
To fix this, dont set "ERROR_WRONG_INF_STYLE" if section not found. If you really need to, set this error inside the "version index case", section format/parse error whatever.
After fixing this, the installer goes futher and stops again.
--- snip trace --- 0011:Call setupapi.SetupGetSourceFileLocationA(00190838,00000000,0018346c "",6ccb777c,00000000,00000000,6ccb7778) ret=010368db 0011:trace:setupapi:SetupGetSourceFileLocationA 0x190838, (nil), "", 0x6ccb777c, (nil), 0x00000000, 0x6ccb7778 0011:Call KERNEL32.MultiByteToWideChar(00000000,00000000,0018346c "",ffffffff,00000000,00000000) ret=6066b603 0011:Ret KERNEL32.MultiByteToWideChar() retval=00000001 ret=6066b603 0011:Call ntdll.RtlAllocateHeap(00110000,00000000,00000002) ret=6066b628 0011:Ret ntdll.RtlAllocateHeap() retval=0017cba8 ret=6066b628 0011:Call KERNEL32.MultiByteToWideChar(00000000,00000000,0018346c "",ffffffff,0017cba8,00000001) ret=6066b665 0011:Ret KERNEL32.MultiByteToWideChar() retval=00000001 ret=6066b665 0011:trace:setupapi:SetupGetSourceFileLocationW 0x190838, (nil), L"", 0x6ccb777c, (nil), 0x00000000, 0x6ccb76a8 0011:trace:setupapi:SetupFindFirstLineW (0x190838,L"SourceDisksFiles.x86",L""): not found 0011:trace:setupapi:SetupFindNextMatchLineW (0x190838,L"SourceDisksFiles",L""): not found ... 0011:Ret setupapi.SetupGetSourceFileLocationA() retval=00000000 ret=010368db --- snip trace ---
offending code:
--- snip dlls/setupapi/query.c --- BOOL WINAPI SetupGetSourceFileLocationA( HINF hinf, PINFCONTEXT context, PCSTR filename, PUINT source_id, PSTR buffer, DWORD buffer_size, PDWORD required_size ) { ... if (filename && !(filenameW = strdupAtoW( filename ))) return FALSE; ... } --- snip dlls/setupapi/query.c ---
http://msdn2.microsoft.com/en-us/library/aa377390.aspx says:
"[in] Optional pointer to a null-terminated string containing the filename (no path) for which to return the full source location. This parameter can be NULL, but either FileName or InfContext must be specified."
Another undocumented behaviour. The installer supplies an empty string as "filename" argument which wine doesnt handle.
To fix this (handle empty string case):
--- snip dlls/setupapi/query.c --- BOOL WINAPI SetupGetSourceFileLocationA( HINF hinf, PINFCONTEXT context, PCSTR filename, PUINT source_id, PSTR buffer, DWORD buffer_size, PDWORD required_size ) { ... if (filename && *filename != '\0' && !(filenameW = strdupAtoW( filename ))) return FALSE; ... } --- snip dlls/setupapi/query.c ---
After fixing this, the installer goes further and stops again with "general failure".
--- snip trace --- 0011:Call setupapi.SetupScanFileQueueA(00187760,00000004,00000000,01064aca,61a01768,61a01764) ret=0106504d 0011:fixme:setupapi:SetupScanFileQueueA stub 0011:Ret setupapi.SetupScanFileQueueA() retval=00000000 ret=0106504d --- snip trace ---
Well, due to SetupScanFileQueueA() being a stub it wont go further. A quick fix (just to get this installer to go on) is to return "TRUE":
--- snip dlls/setupapi/queue.c --- BOOL WINAPI SetupScanFileQueueA( HSPFILEQ queue, DWORD flags, HWND window, PSP_FILE_CALLBACK_A callback, PVOID context, PDWORD result ) { FIXME("stub\n"); return TRUE; } --- snip dlls/setupapi/queue.c ---
This doesnt cause any harm (at least for the installer) though a real implementation would be better (to pass callback notifcations on node walk).
With this "hack" applied is goes on and *really* dies due to unimplemented API functions:
--- snip trace --- 0009:Call KERNEL32.RaiseException(80000100,00000001,00000002,0033c118) ret=71d3f5b1 0009:trace:seh:raise_exception code=80000100 flags=1 addr=0x7b840d20 0009:trace:seh:raise_exception info[0]=71d3f620 0009:trace:seh:raise_exception info[1]=71d417fd wine: Call from 0x7b840d20 to unimplemented function setupapi.dll.pSetupGetQueueFlags, aborting --- snip trace ---
Although undocumented this is not an obstacle for me .. as usual :-) Here it goes...
--- snip dlls/setupapi/queue.c --- /*********************************************************************** * pSetupGetQueueFlags (SETUPAPI.@) */ DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle ) { struct file_queue *queue = handle; return( queue != NULL) ? queue->flags : 0; }
/*********************************************************************** * pSetupSetQueueFlags (SETUPAPI.@) */ BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags ) { struct file_queue *queue = handle; if( queue) { queue->flags = flags; } return( queue != NULL); } --- snip dlls/setupapi/queue.c ---
and
--- snip dlls/setupapi/setupapi.spec --- .. @ stdcall pSetupGetQueueFlags(ptr) .. @ stdcall pSetupSetQueueFlags(ptr long) --- snip dlls/setupapi/setupapi.spec ---
After adding the missing APIs the installer lives again. It finally stops with error "Failed to install catalog files".
--- snip KB842773.log --- InstallCatalogFiles: MyInstallCatalog failed for KB842773.cat; error=0x000004c7. DoInstallation:MyInstallCatalogFiles failed:STR_CATALOG_INSTALL_FAILED --- snip KB842773.log ---
--- snip trace --- ... 0009:Call wintrust.CryptCATOpen(0019b110 L"c:\windows\KB842773.cat",00000000,00000000,00000000,00000000) ret=01062197 0009:fixme:wintrust:CryptCATOpen (L"c:\windows\KB842773.cat", 0, 0, 0, 0) stub 0009:Ret wintrust.CryptCATOpen() retval=00000000 ret=01062197 ... --- snip trace ---
Well, this is where my journey currently ends. Implementing this requires more wintrust/crypt infrastructure which is currently worked on. A quick hack would require changes in several places (which i have not the time). So you have to wait until wintrust crypt catalog management gets polished up...
Hope you enjoyed it a bit :-)
Regards