http://bugs.winehq.org/show_bug.cgi?id=8241
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |focht@gmx.net
--- Comment #13 from Anastasius Focht focht@gmx.net 2009-04-21 17:19:24 --- Hello,
--- quote --- Any thoughts anyone? --- quote ---
Sure ;-)
The app seems to contain various brain damaged snippets from a 16 bit legacy code base *argh*
Example: GlobalFlags() return values are directly compared against GMEM_DISCARDED instead of testing for bit mask. GlobalFlags() *can* potentially return more than one flag set and even lock count. It's only valid to check for GMEM_INVALID_HANDLE directly.
Anyway .. this snippet shows the problem:
--- snip --- ... 0025:Call KERNEL32.GlobalAlloc(00004042,0000001c) ret=0088757c 0025:Ret KERNEL32.GlobalAlloc() retval=01b2c9f2 ret=0088757c ... 0025:Call KERNEL32.GlobalLock(01b2c9f2) ret=00887784 0025:Ret KERNEL32.GlobalLock() retval=01b2ca10 ret=00887784 0025:Call KERNEL32.ReadFile(00000054,01b2ca10,0000001c,0032c6a0,00000000) ret=004dc3ca 0025:Ret KERNEL32.ReadFile() retval=00000001 ret=004dc3ca ... 0025:Call KERNEL32.GlobalUnlock(01b2c9f2) ret=008877f8 0025:Ret KERNEL32.GlobalUnlock() retval=00000000 ret=008877f8 ... 0025:Call KERNEL32.ReadFile(00000054,01b2cff8,0000001c,0032c6a0,00000000) ret=004dc3ca 0025:Ret KERNEL32.ReadFile() retval=00000001 ret=004dc3ca 0025:Call KERNEL32.SetLastError(00000000) ret=008877ee 0025:Ret KERNEL32.SetLastError() retval=00000000 ret=008877ee 0025:Call KERNEL32.GlobalUnlock(01b2cfda) ret=008877f8 0025:Ret KERNEL32.GlobalUnlock() retval=00000000 ret=008877f8 0025:Call KERNEL32.GetLastError() ret=00887807 0025:Ret KERNEL32.GetLastError() retval=00000000 ret=00887807 0025:Call KERNEL32.SetLastError(00000000) ret=00887703 0025:Ret KERNEL32.SetLastError() retval=00000000 ret=00887703 0025:Call KERNEL32.GlobalFlags(01b2c9f2) ret=0088770d 0025:Ret KERNEL32.GlobalFlags() retval=00004000 ret=0088770d 0025:Call KERNEL32.SetLastError(00000000) ret=00887703 0025:Ret KERNEL32.SetLastError() retval=00000000 ret=00887703 0025:Call KERNEL32.GlobalFlags(01b2c9f2) ret=0088770d 0025:Ret KERNEL32.GlobalFlags() retval=00004000 ret=0088770d 0025:Call KERNEL32.SetLastError(00000000) ret=00887703 0025:Ret KERNEL32.SetLastError() retval=00000000 ret=00887703 0025:Call KERNEL32.GlobalFlags(01b2c9f2) ret=0088770d 0025:Ret KERNEL32.GlobalFlags() retval=00004000 ret=0088770d 0025:Call KERNEL32.SetLastError(00000000) ret=0088767d 0025:Ret KERNEL32.SetLastError() retval=00000000 ret=0088767d 0025:Call KERNEL32.GetLastError() ret=008876a8 0025:Ret KERNEL32.GetLastError() retval=00000000 ret=008876a8 0025:Call KERNEL32.FormatMessageA(00001300,00000000,00000000,00000400,0032c664,00000000,00000000) ret=008876c9 0025:Ret KERNEL32.FormatMessageA() retval=00000008 ret=008876c9 ... --- snip ---
The root cause is actually GlobalAlloc( GMEM_DISCARDED | GMEM_ZEROINIT | GMEM_MOVEABLE, size).
See what MSDN says: http://msdn.microsoft.com/en-us/library/aa366574.aspx
--- quote --- HGLOBAL WINAPI GlobalAlloc( __in UINT uFlags, __in SIZE_T dwBytes );
... uFlags [in]
The memory allocation attributes. If zero is specified, the default is GMEM_FIXED. This parameter can be one or more of the following values, except for the incompatible combinations that are specifically noted.
... The following values are obsolete, but are provided for compatibility with 16-bit Windows. They are ignored.
GMEM_DDESHARE GMEM_DISCARDABLE GMEM_LOWER GMEM_NOCOMPACT GMEM_NODISCARD GMEM_NOT_BANKED GMEM_NOTIFY GMEM_SHARE --- quote ---
The "ignored" part is the problem. GMEM_NOTIFY (0x4000) gets passed in.
See how Wine stores the flags:
--- snip dlls/kernel32/heap.c ---
GLOBAL WINAPI GlobalAlloc( UINT flags, /* [in] Object allocation attributes */ SIZE_T size /* [in] Number of bytes to allocate */ ) { ... pintern = HeapAlloc(GetProcessHeap(), 0, sizeof(GLOBAL32_INTERN)); if (pintern) { pintern->Magic = MAGIC_GLOBAL_USED; pintern->Flags = flags >> 8; pintern->LockCount = 0; --- snip dlls/kernel32/heap.c ---
and returns them later:
--- snip dlls/kernel32/heap.c --- UINT WINAPI GlobalFlags(HGLOBAL hmem) { ... if(pintern->Magic==MAGIC_GLOBAL_USED) { retval=pintern->LockCount + (pintern->Flags<<8); if(pintern->Pointer==0) retval|= GMEM_DISCARDED; } ... --- snip dlls/kernel32/heap.c ---
Because the app passed GMEM_NOTIFY which is in the high word (0x4042) -> (flags
- -> 0x40 it will be later returned as 0x4000 (pintern->Flags<<8) which
has incidentally the value of GMEM_DISCARDED (0x4000). This is something the app doesn't expect (the memory isn't free'd yet).
I fixed the flags according to MSDN (ignored part) and the app (Prism Demo v5.0.2) successfully creates new projects and opens existing ones.
Regards