[Bug 47075] 32-bit LAVFilters 0.74.x installer fails to register 64-bit AX codec/ filters in Wow64 environment ( 32-bit regsvr32.exe needs to support 64-bit dll registration and vice versa by re-exec with proper bitness )
wine-bugs at winehq.org
wine-bugs at winehq.org
Fri Apr 26 19:32:33 CDT 2019
https://bugs.winehq.org/show_bug.cgi?id=47075
Anastasius Focht <focht at gmx.net> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |focht at gmx.net
Component|-unknown |programs
URL|https://softpedia-secure-do |https://github.com/Nevcairi
|wnload.com/dl/fbaa35edc239e |el/LAVFilters/releases/down
|424392b469e93e40a24/5cc2b1b |load/0.74.1/LAVFilters-0.74
|2/100186359/software/multim |.1-Installer.exe
|edia/video/LAVFilters-0.74. |
|1-Installer.exe |
Summary|Cannot install LAVFilters, |32-bit LAVFilters 0.74.x
|fails at registering DLLs |installer fails to register
| |64-bit AX codec/filters in
| |Wow64 environment (32-bit
| |regsvr32.exe needs to
| |support 64-bit dll
| |registration and vice versa
| |by re-exec with proper
| |bitness)
Hardware|x86 |x86-64
--- Comment #5 from Anastasius Focht <focht at gmx.net> ---
Hello folks,
confirming.
The installer is 32-bit and tries to register 32-bit _and_ 64-bit dlls (AX
codec/filters).
--- snip ---
$ WINEDEBUG=+seh,+relay,loaddll,+module wine ./LAVFilters-0.74.1-Installer.exe
>>log.txt 2>&1
...
002a:Call KERNEL32.CreateProcessA(00000000,00420474
"\"C:\\users\\focht\\Temp\\is-0VI6K.tmp\\LAVFilters-0.74.1-Installer.tmp\"
/SL5=\"$1006E,12293661,58368,Z:\\home\\focht\\Downloads\\LAVFilters-0.74.1-Installer.exe\"
",00000000,00000000,00000000,00000000,00000000,00000000,0034fe04,0034fdf4)
ret=00409f39
...
002c:Call KERNEL32.__wine_kernel_init() ret=7bc67e16
002c:Ret KERNEL32.__wine_kernel_init() retval=7b472c54 ret=7bc67e16
002a:Ret KERNEL32.CreateProcessA() retval=00000001 ret=00409f39
...
002c:Call KERNEL32.CreateProcessA(00000000,005612c8
"\"C:\\windows\\system32\\regsvr32.exe\" /s \"C:\\Program Files (x86)\\LAV
Filters\\x86\\LAVAudio.ax\"",00000000,00000000,00000000,04000000,00000000,004f02e8
"C:\\windows\\system32",0032e9cc,0032e9bc) ret=00453019
...
002c:Ret KERNEL32.CreateProcessA() retval=00000001 ret=00453019
...
002e:Call KERNEL32.LoadLibraryExW(00113018 L"C:\\Program Files (x86)\\LAV
Filters\\x86\\LAVAudio.ax",00000000,00000008) ret=7efeebf9
...
002e:trace:module:process_attach (L"LAVAudio.ax",(nil)) - END
002e:Ret KERNEL32.LoadLibraryExW() retval=10000000 ret=7efeebf9
002e:Call KERNEL32.GetProcAddress(10000000,7efef337 "DllRegisterServer")
ret=7efeec0a
002e:Ret KERNEL32.GetProcAddress() retval=10002930 ret=7efeec0a
...
002e:Call KERNEL32.ExitProcess(00000000) ret=7efef1dd
--- snip ---
The broken one, where it tries to register 32-bit AX. Still same parent process
-> 32-bitness is inherited:
--- snip ---
002c:Call KERNEL32.CreateProcessA(00000000,005612c8
"\"C:\\windows\\system32\\regsvr32.exe\" /s \"C:\\Program Files (x86)\\LAV
Filters\\x64\\LAVAudio.ax\"",00000000,00000000,00000000,04000000,00000000,004f02e8
"C:\\windows\\system32",0032e9cc,0032e9bc) ret=00453019
...
0034:Ret KERNEL32.__wine_kernel_init() retval=7b472c54 ret=7bc67e16
002c:Ret KERNEL32.CreateProcessA() retval=00000001 ret=00453019
...
0034:Call KERNEL32.LoadLibraryExW(00113018 L"C:\\Program Files (x86)\\LAV
Filters\\x64\\LAVAudio.ax",00000000,00000008) ret=7efeebf9
...
0034:trace:module:open_dll_file L"\\??\\C:\\Program Files (x86)\\LAV
Filters\\x64\\LAVAudio.ax" is for arch 8664, continuing search
0034:warn:module:load_dll Failed to load module L"C:\\Program Files (x86)\\LAV
Filters\\x64\\LAVAudio.ax"; status=c000007b
0034:Ret KERNEL32.LoadLibraryExW() retval=00000000 ret=7efeebf9
0034:Call KERNEL32.ExitProcess(00000003) ret=7efeec5b
...
002c:Call KERNEL32.GetExitCodeProcess(0000008c,0032e984) ret=004588de
002c:Ret KERNEL32.GetExitCodeProcess() retval=00000001 ret=004588de
002c:Call KERNEL32.CloseHandle(0000008c) ret=00458904
002c:Ret KERNEL32.CloseHandle() retval=00000001 ret=00458904
002c:Call KERNEL32.RaiseException(0eedface,00000001,00000007,0032e978)
ret=00458ac8
002c:trace:seh:raise_exception code=eedface flags=1 addr=0x7b44493b ip=7b44493b
tid=002c
002c:trace:seh:raise_exception info[0]=00458ac8
002c:trace:seh:raise_exception info[1]=00561328
002c:trace:seh:raise_exception info[2]=00000003
002c:trace:seh:raise_exception info[3]=00560c4c
002c:trace:seh:raise_exception info[4]=00552404
002c:trace:seh:raise_exception info[5]=0032ea1c
002c:trace:seh:raise_exception info[6]=0032e994
002c:trace:seh:raise_exception eax=7b42e1b9 ebx=00000018 ecx=0032e8c4
edx=0032e978 esi=0032ea1c edi=0032e94
...
002c:Call user32.MessageBoxA(000100a0,00561428 "C:\\Program Files (x86)\\LAV
Filters\\x64\\LAVAudio.ax\r\n\r\nUnable to register the DLL/OCX: RegSvr32
failed with exit code 0x3.\r\n\r\nClick Retry to try again, Ignore to proceed
anyway (not recommended), or Abort to cancel installation.",004f3168
"Error",00000032) ret=0042f878
--- snip ---
This obviously can't work as you can't load a 64-bit code dll into a 32-bit
Wow64 process.
The project is on Github:
https://github.com/Nevcairiel/LAVFilters
https://github.com/Nevcairiel/LAVFilters/releases/tag/0.74.1
@Louis:
Hint: When providing download links, double check it's not user session
generated URI like the previous one from Softpedia. I've replaced it with
Github now.
Anyway, the installer is Inno Setup based which fortunately is open sauce.
https://github.com/jrsoftware/issrc
I spent some time digging through the sources of the installer. It seems to
have all the code paths to handle the registration properly for 32-bit and
64-bit in Wow64 environment. I suspect the authoring/packaging (install script)
doing a questionable thing wrt 32-bit vs. 64-bit dlls.
https://github.com/jrsoftware/issrc/blob/e7d8563af77ba49700b6615649d4b3c6f8b62af7/Projects/RegDLL.pas
--- snip ---
procedure RegisterServerUsingRegSvr32(const AUnregister: Boolean;
const AIs64Bit: Boolean; const Filename: String);
var
SysDir, CmdLine: String;
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
ExitCode: DWORD;
begin
SysDir := GetSystemDir;
CmdLine := '"' + AddBackslash(SysDir) + 'regsvr32.exe"';
if AUnregister then
CmdLine := CmdLine + ' /u';
CmdLine := CmdLine + ' /s "' + Filename + '"';
if AIs64Bit then
Log('Spawning 64-bit RegSvr32: ' + CmdLine)
else
Log('Spawning 32-bit RegSvr32: ' + CmdLine);
FillChar(StartupInfo, SizeOf(StartupInfo), 0);
StartupInfo.cb := SizeOf(StartupInfo);
if not CreateProcessRedir(AIs64Bit, nil, PChar(CmdLine), nil, nil, False,
CREATE_DEFAULT_ERROR_MODE, nil, PChar(SysDir), StartupInfo,
ProcessInfo) then
Win32ErrorMsg('CreateProcess');
CloseHandle(ProcessInfo.hThread);
ExitCode := WaitForAndCloseProcessHandle(ProcessInfo.hProcess);
if ExitCode <> 0 then
raise Exception.Create(FmtSetupMessage1(msgErrorRegSvr32Failed,
Format('0x%x', [ExitCode])));
end;
...
procedure RegisterServer(const AUnregister: Boolean; const AIs64Bit: Boolean;
const Filename: String; const AFailCriticalErrors: Boolean);
var
WindowDisabler: TWindowDisabler;
begin
if AIs64Bit and not IsWin64 then
InternalError('Cannot register 64-bit DLLs on this version of Windows');
{ Disable windows so the user can't utilize our UI while the child process
is running }
WindowDisabler := TWindowDisabler.Create;
try
{ On Windows Vista, to get the "WRP Mitigation" compatibility hack which
a lot of DLLs a require, we must use regsvr32.exe to handle the
(un)registration.
On Windows 2000/XP/2003, use regsvr32.exe as well for behavioral &
error message consistency. }
RegisterServerUsingRegSvr32(AUnregister, AIs64Bit, Filename);
finally
WindowDisabler.Free;
end;
end;
--- snip ---
https://github.com/jrsoftware/issrc/blob/32e8b217216a71d46b8dae815be919219fe88dee/Projects/Install.pas#L2601
--- snip ---
procedure RegisterSvr(const Is64Bit: Boolean; const Filename: String;
const NoErrorMessages: Boolean);
var
NeedToRetry: Boolean;
begin
repeat
if Is64Bit then
LogFmt('Registering 64-bit DLL/OCX: %s', [Filename])
else
LogFmt('Registering 32-bit DLL/OCX: %s', [Filename]);
NeedToRetry := False;
try
RegisterServer(False, Is64Bit, Filename, NoErrorMessages);
Log('Registration successful.');
except
Log('Registration failed:' + SNewLine + GetExceptMessage);
if not NoErrorMessages then
if not AbortRetryIgnoreTaskDialogMsgBox(
Filename + SNewLine2 +
FmtSetupMessage1(msgErrorRegisterServer, GetExceptMessage),
[SetupMessages[msgAbortRetryIgnoreRetry],
SetupMessages[msgFileAbortRetryIgnoreIgnoreNotRecommended],
SetupMessages[msgAbortRetryIgnoreCancel]]) then
NeedToRetry := True;
end;
until not NeedToRetry;
end;
--- snip ---
https://github.com/jrsoftware/issrc/blob/32e8b217216a71d46b8dae815be919219fe88dee/Projects/Install.pas#L2654
--- snip ---
var
I: Integer;
begin
if not NeedsRestart then
for I := 0 to RegisterFilesList.Count-1 do begin
with PRegisterFilesListRec(RegisterFilesList[I])^ do
if not TypeLib then
RegisterSvr(Is64Bit, Filename, NoErrorMessages)
else
RegisterTLib(Is64Bit, Filename, NoErrorMessages);
end
else begin
{ When a restart is needed, all "regserver" & "regtypelib" files will get
registered on the next logon }
Log('Delaying registration of all files until the next logon since a
restart is needed.');
try
RegisterServersOnRestart;
except
Application.HandleException(nil);
end;
end;
end;
--- snip ---
https://github.com/jrsoftware/issrc/blob/32e8b217216a71d46b8dae815be919219fe88dee/Projects/Install.pas#L1549
--- snip ---
{ If foRegisterServer or foRegisterTypeLib is in Options, add the
file to RegisterFilesList for registering later.
Don't attempt to register if the file doesn't exist (which can
happen if the foOnlyIfDestFileExists flag is used). }
if ((foRegisterServer in CurFile^.Options) or
(foRegisterTypeLib in CurFile^.Options)) and
NewFileExistsRedir(DisableFsRedir, DestFile) then begin
LastOperation := '';
if foRegisterTypeLib in CurFile^.Options then
Log('Will register the file (a type library) later.')
else
Log('Will register the file (a DLL/OCX) later.');
New(RegisterRec);
RegisterRec^.Filename := DestFile;
RegisterRec^.Is64Bit := DisableFsRedir;
RegisterRec^.TypeLib := foRegisterTypeLib in CurFile^.Options;
RegisterRec^.NoErrorMessages := foNoRegError in CurFile^.Options;
RegisterFilesList.Add(RegisterRec);
--- snip ---
https://github.com/jrsoftware/issrc/blob/32e8b217216a71d46b8dae815be919219fe88dee/Projects/Install.pas#L1772
--- snip ---
var
FileLocationFilenames: TStringList;
I: Integer;
CurFileNumber: Integer;
CurFile: PSetupFileEntry;
ExternalSize: Integer64;
SourceWildcard: String;
ProgressBefore, ExpectedBytesLeft: Integer64;
DisableFsRedir, FoundFiles: Boolean;
begin
FileLocationFilenames := TStringList.Create;
try
for I := 0 to Entries[seFileLocation].Count-1 do
FileLocationFilenames.Add('');
for CurFileNumber := 0 to Entries[seFile].Count-1 do begin
CurFile := PSetupFileEntry(Entries[seFile][CurFileNumber]);
if ((CurFile^.FileType <> ftUninstExe) or Uninstallable) and
ShouldProcessFileEntry(WizardComponents, WizardTasks, CurFile,
False) then begin
DebugNotifyEntry(seFile, CurFileNumber);
NotifyBeforeInstallFileEntry(CurFile);
DisableFsRedir := InstallDefaultDisableFsRedir;
if fo32Bit in CurFile^.Options then
DisableFsRedir := False;
if fo64Bit in CurFile^.Options then begin
if not IsWin64 then
InternalError('Cannot install files to 64-bit locations on this
version of Windows');
DisableFsRedir := True;
end;
if CurFile^.LocationEntry <> -1 then begin
ExternalSize.Hi := 0; { not used... }
ExternalSize.Lo := 0;
ProcessFileEntry(CurFile, DisableFsRedir, '', '',
FileLocationFilenames, ExternalSize);
end
else begin
{ File is an 'external' file }
if CurFile^.FileType = ftUninstExe then begin
{ This is the file entry for the uninstaller program }
SourceWildcard := NewParamStr(0);
DisableFsRedir := False;
end
else
--- snip ---
The inner installer 'LAVFilters-0.74.1-Installer.tmp' is created in TEMP folder
and can be run manually for easier debugging, along with verbose/log option.
--- snip ---
$ wine ./LAVFilters-0.74.1-Installer.tmp
/SL5="\$1006E,12293661,58368,Z:\\home\\focht\\Downloads\\LAVFilters-0.74.1-Installer.exe"
/LOG
--- snip ---
Which produces a log file 'Setup Log <date> #001.txt' in TEMP folder:
--- snip ---
2019-04-27 00:28:52.015 Log opened. (Time zone: UTC+02:00)
2019-04-27 00:28:52.015 Setup version: Inno Setup version 5.6.1 (a)
2019-04-27 00:28:52.015 Original Setup EXE:
Z:\home\focht\Downloads\LAVFilters-0.74.1-Installer.exe
2019-04-27 00:28:52.015 Setup command line:
/SL5=$1006E,12293661,58368,Z:\home\focht\Downloads\LAVFilters-0.74.1-Installer.exe
/LOG
2019-04-27 00:28:52.015 Windows version: 6.1.7601 SP1 (NT platform: Yes)
2019-04-27 00:28:52.015 64-bit Windows: Yes
2019-04-27 00:28:52.015 Processor architecture: x64
2019-04-27 00:28:52.015 User privileges: Administrative
2019-04-27 00:28:52.016 64-bit install mode: No
2019-04-27 00:28:52.016 Created temporary directory:
C:\users\focht\Temp\is-KU7T7.tmp
...
2019-04-27 00:29:30.548 Registering 32-bit DLL/OCX: C:\Program Files
(x86)\LAV Filters\x86\LAVAudio.ax
2019-04-27 00:29:30.551 Spawning 32-bit RegSvr32:
"C:\windows\system32\regsvr32.exe" /s "C:\Program Files (x86)\LAV
Filters\x86\LAVAudio.ax"
2019-04-27 00:29:30.694 Registration successful.
2019-04-27 00:29:30.694 Registering 32-bit DLL/OCX: C:\Program Files
(x86)\LAV Filters\x86\LAVSplitter.ax
2019-04-27 00:29:30.697 Spawning 32-bit RegSvr32:
"C:\windows\system32\regsvr32.exe" /s "C:\Program Files (x86)\LAV
Filters\x86\LAVSplitter.ax"
2019-04-27 00:29:30.842 Registration successful.
2019-04-27 00:29:30.842 Registering 32-bit DLL/OCX: C:\Program Files
(x86)\LAV Filters\x86\LAVVideo.ax
2019-04-27 00:29:30.845 Spawning 32-bit RegSvr32:
"C:\windows\system32\regsvr32.exe" /s "C:\Program Files (x86)\LAV
Filters\x86\LAVVideo.ax"
2019-04-27 00:29:30.983 Registration successful.
2019-04-27 00:29:30.983 Registering 32-bit DLL/OCX: C:\Program Files
(x86)\LAV Filters\x64\LAVAudio.ax
2019-04-27 00:29:30.985 Spawning 32-bit RegSvr32:
"C:\windows\system32\regsvr32.exe" /s "C:\Program Files (x86)\LAV
Filters\x64\LAVAudio.ax"
2019-04-27 00:29:31.075 Registration failed:
RegSvr32 failed with exit code 0x3.
2019-04-27 00:29:31.075 Message box (Abort/Retry/Ignore):
C:\Program Files (x86)\LAV Filters\x64\LAVAudio.ax
Unable to register the DLL/OCX: RegSvr32 failed with
exit code 0x3.
Click Retry to try again, Ignore to proceed anyway
(not recommended), or Abort to cancel installation.
--- snip ---
'64-bit install mode: No' (!)
And yes, it really spawns 32-bit regsvr32.exe for the 64-bit Codec/Filter dll.
@Louis
--- quote ---
This looks like a regression. I tried manually register in wine-4.0 and in
current git.
--- quote ---
No, Wine behaves more correctly now. It was fixed with
https://source.winehq.org/git/wine.git/commitdiff/9839bb7691a1b1c57a4ca501d03825420c1609d7
and friends.
It seems MS implemented a workaround for 'regsvr32.exe' to "help" all those
broken/brain damaged installers to still succeed in such Wow64 scenarios.
Even Wine respawns processes with proper bitness to cope with Wow64 environment
process/dll bitness requirements. The latest case was Wine uninstaller
(https://source.winehq.org/git/wine.git/commitdiff/88580a3ad6e6afea25716b8717a33d20184154e5).
I found this blog entry which supports my analysis:
http://blog.differentpla.net/blog/2008/10/25/things-i-learnt-this-week-regsvr32exe-on-windows-x64/
Internet Archive link in case it goes away:
https://web.archive.org/web/20150912153210/http://blog.differentpla.net/blog/2008/10/25/things-i-learnt-this-week-regsvr32exe-on-windows-x64/
--- quote ---
Things I learnt this week: RegSvr32.EXE on Windows x64
2008-10-25 16:17:29 +0000
On Windows, 64-bit processes cannot load 32-bit DLLs, and 32-bit processes
cannot load 64-bit DLLs. How does REGSVR32.EXE manage to successfully register
both 32-bit and 64-bit COM DLLs?
On Windows x64 (I’ve checked on Windows Vista and Windows 2003, and I assume
it’s the same for Windows XP and Windows 2008) there are two copies of
REGSVR32.EXE. One of them is in C:\Windows\System32, and is 64-bit; the other
is in C:\Windows\SysWOW64, and is 32-bit.
If you attempt to use the 64-bit version of REGSVR32.EXE to register a 32-bit
DLL, it spots this and spawns the 32-bit version to do the registration.
Similarly, if you attempt to use the 32-bit version of REGSVR32.EXE to register
a 64-bit DLL, it spawns the 64-bit version.
--- quote ---
Wine source:
https://source.winehq.org/git/wine.git/blob/HEAD:/programs/regsvr32/regsvr32.c#l91
--- snip ---
91 /**
92 * Loads procedure.
93 *
94 * Parameters:
95 * strDll - name of the dll.
96 * procName - name of the procedure to load from the dll.
97 * DllHandle - a variable that receives the handle of the loaded dll.
98 */
99 static VOID *LoadProc(const WCHAR* strDll, const char* procName, HMODULE*
DllHandle)
100 {
101 VOID* (*proc)(void);
102
103 *DllHandle = LoadLibraryExW(strDll, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
104 if(!*DllHandle)
105 {
106 output_write(STRING_DLL_LOAD_FAILED, strDll);
107 ExitProcess(LOADLIBRARY_FAILED);
108 }
109 proc = (VOID *) GetProcAddress(*DllHandle, procName);
110 if(!proc)
111 {
112 output_write(STRING_PROC_NOT_IMPLEMENTED, procName, strDll);
113 FreeLibrary(*DllHandle);
114 return NULL;
115 }
116 return proc;
117 }
--- snip ---
So you might want to check for 'ERROR_BAD_EXE_FORMAT' lasterror in case of
'LoadLibraryExW()' failure and respawn with proper bitness (either direction).
$ sha1sum LAVFilters-0.74.1-Installer.exe
ab9f0c04ea67088ea4f52b310565172427a567d6 LAVFilters-0.74.1-Installer.exe
$ du -sh LAVFilters-0.74.1-Installer.exe
12M LAVFilters-0.74.1-Installer.exe
$ wine --version
wine-4.7
Regards
--
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.
More information about the wine-bugs
mailing list