https://bugs.winehq.org/show_bug.cgi?id=12757
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|REOPENED |NEW CC| |focht@gmx.net Summary|Europa Universalis Rome: |Europa Universalis Rome |Crashes on start-up |crashes on startup | |(D3DXLoadSurfaceFromFileInM | |emory must not | |unconditionally call | |CoUninitialize(), different | |COM threading model used)
--- Comment #20 from Anastasius Focht focht@gmx.net --- Hello folks,
confirming - although this bug has been recycled at least once for different issues.
The game uses a multi-threaded apartment on its main thread. Multiple Wine components/API create apartment-threaded COM inproc servers on the same thread (dsound, d3dx, ...).
The caller needs to be aware of this situation (RPC_E_CHANGED_MODE) in order to avoid messing up the coinit refcount. The visible part is the infamous 'Attempt to change threading model of this apartment from multi-threaded to apartment threaded' message in terminal.
Relevant part of trace log:
The game creates multi-threaded apartment and quartz instance:
--- snip --- 0025:Call ole32.CoInitializeEx(00000000,0000000c) ret=00897417 ... 0025:Ret ole32.CoInitializeEx() retval=00000000 ret=00897417 ... 0025:Call ole32.CoCreateInstance(00a37470,00000000,00000003,00a37420,00e454d8) ret=008317a7 ... 0025:Call KERNEL32.LoadLibraryExW(0033ee8e L"C:\windows\system32\quartz.dll",00000000,00000008) ret=7eb6a6cb ... 0025:Ret PE DLL (proc=0x7d2c1b70,module=0x7d210000 L"quartz.dll",reason=PROCESS_ATTACH,res=(nil)) retval=1 0025:Ret KERNEL32.LoadLibraryExW() retval=7d210000 ret=7eb6a6cb ... 0025:Ret ole32.CoCreateInstance() retval=00000000 ret=008317a7 --- snip ---
Wine uses multiple COM servers on the same thread with apartment threading model:
--- snip --- ... 0025:Call dsound.DirectSoundCreate8(00000000,00de1880,00000000) ret=0082f977 ... 0025:Call ole32.CoInitialize(00000000) ret=7e2ce081 0025:err:ole:CoInitializeEx Attempt to change threading model of this apartment from multi-threaded to apartment threaded 0025:Ret ole32.CoInitialize() retval=80010106 ret=7e2ce081 0025:Call ole32.CoCreateInstance(7e2e27d8,00000000,00000001,7e2e27a8,0033efa8) ret=7e2ce0b6 ... --- snip ---
The problematic one:
--- snip --- ... 0025:trace:d3dx:D3DXLoadSurfaceFromFileInMemory dst_surface 0xb34afa8, dst_palette (nil), dst_rect (null), src_data 0x1570000, src_data_size 65580, src_rect (null), filter 0x1, color_key 0x00000000, src_info (nil). 0025:trace:d3dx:D3DXGetImageInfoFromFileInMemory (0x1570000, 65580, 0x33ea64) 0025:Call ole32.CoInitializeEx(00000000,00000002) ret=7ed82a47 0025:err:ole:CoInitializeEx Attempt to change threading model of this apartment from multi-threaded to apartment threaded 0025:Ret ole32.CoInitializeEx() retval=80010106 ret=7ed82a47 0025:Call ole32.CoCreateInstance(7ed9ed1c,00000000,00000001,7ed9ed2c,0033e8cc) ret=7ed82a7f ... 0025:trace:d3dx:D3DXLoadSurfaceFromMemory (0xb34afa8, (nil), (null), 0xb361c10, 0x16, 512, (nil), (0,0)-(128,128) 0x1, 0x00000000) ... 0025:Call ole32.CoUninitialize() ret=7ed84242 0025:Call quartz.DllCanUnloadNow() ret=7eb6c1c3 0025:Call rpcrt4.NdrDllCanUnloadNow(7d30bab8) ret=7d2633fd 0025:Ret rpcrt4.NdrDllCanUnloadNow() retval=00000000 ret=7d2633fd 0025:Ret quartz.DllCanUnloadNow() retval=00000000 ret=7eb6c1c3 0025:Call KERNEL32.FreeLibrary(7d210000) ret=7eb6aa42 0025:Call PE DLL (proc=0x7d2c1b70,module=0x7d210000 L"quartz.dll",reason=PROCESS_DETACH,res=(nil)) 0025:Ret PE DLL (proc=0x7d2c1b70,module=0x7d210000 L"quartz.dll",reason=PROCESS_DETACH,res=(nil)) retval=1 0025:Call PE DLL (proc=0x7dcc9d1c,module=0x7dcb0000 L"msvfw32.dll",reason=PROCESS_DETACH,res=(nil)) 0025:Ret PE DLL (proc=0x7dcc9d1c,module=0x7dcb0000 L"msvfw32.dll",reason=PROCESS_DETACH,res=(nil)) retval=1 0025:Call PE DLL (proc=0x7cd1c3bc,module=0x7cc60000 L"comctl32.dll",reason=PROCESS_DETACH,res=(nil)) ... --- snip ---
At this point 'quartz.dll' is unloaded from memory but the game still holds COM class/iface references!
The crash is a late manifestation, it tries to call quartz.BasicAudio_put_Volume() with the PE image already gone.
Wine code like D3DXGetImageInfoFromFileInMemory() does it right, taking CoInitializeEx() result into account. The COM threading model used might be still questionable.
Source: http://source.winehq.org/git/wine.git/blob/fa8a0dc7f61715a093a3b2e4453e843a4...
--- snip --- 1023 HRESULT WINAPI D3DXLoadSurfaceFromFileInMemory(IDirect3DSurface9 *pDestSurface, 1024 const PALETTEENTRY *pDestPalette, const RECT *pDestRect, const void *pSrcData, UINT SrcDataSize, 1025 const RECT *pSrcRect, DWORD dwFilter, D3DCOLOR Colorkey, D3DXIMAGE_INFO *pSrcInfo) 1026 { ... 1081 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 1082 1083 if (FAILED(CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (void**)&factory))) 1084 goto cleanup_err; ... 1180 cleanup_err: 1181 if (factory) 1182 IWICImagingFactory_Release(factory); 1183 1184 CoUninitialize(); ... --- snip ---
With that bug fixed it runs farther - and crashes again due to another d3dx9_36 insufficiency.
$ sha1sum Rome_Demo.exe 57e1fc8f2a1b8eeb0a1ccff218010eb828b00159 Rome_Demo.exe
$ du -sh Rome_Demo.exe 308M Rome_Demo.exe
$ wine --version wine-1.7.13-27-ge610713
Regards