Need help in debugging a stack corruption
Stefan Dösinger
stefandoesinger at gmx.at
Sat Jan 7 05:02:27 CST 2006
Hi,
> Best would to see the actual code for that as I do not really understand
> what you did by reading your description of it.
I only have to implement D3D Textures, IDirect3DVertexBuffer and
IDirect3DExecuteBuffer, then my new patch will be more or less complete and
I'll post it here. Shouldn't take too long, depending on the work I have to
do for University ;)
> But I still find what you wrote suspicious: if you have 4 VTables you
> should NEVER cast functions even if they have the same signature - casts
> are only useful if multiple object versions share the same VTable.
> Basically (from what I remember :-) ), the pointer to the VTable is stored
> at the address returned to the application as the COM object. Wine then use
> a fixed offset to find it's private data from the COM object (basically,
> the offset between the start of Wine's data to the VTable it returned to
> the application). Of course, if you have 4 VTables, these offsets are
> different => you cannot find the address of Wine's internal data without
> knowing exactly which object was given as an argument to the function.
That's basically what the original version does with the macros in ddcomimpl.
When I looked at those I didn't really understand their functionality and
what they were good for, so I did it a little different.
That's what it basically looks like( IDirectDraw for example):
My IDirectDrawImpl structure :
struct IDirectDrawImpl {
IDirectDraw7Vtbl *lpVtbl;
ULONG ref;
/* Other members follow here */
}
Most implementation functions are DD7:
HRESULT WINAPI IDirectDrawImpl_SetCooperativeLevel(IDirectDraw7 *iface, HWND
hWnd, DWORD dwFlags);
HRESULT WINAPI IDirectDrawImpl_SetDisplayMode(IDirectDraw7 *iface, DWORD
dwWidth, DWORD dwHeight, DWORD dwBPP, DWORD dwRefreshRate, DWORD dwFlags);
I have 4 versions of the Vtables:
IDirectDraw7Vtbl IDirectDraw7_Vtbl = {
/* IUnknown */
...
/* IDirectDraw7 */
...
IDirectDrawImpl_SetCooperativeLevel,
IDirectDrawImpl_SetDisplayMode,
...
}
IDirectDraw4Vtbl IDirectDraw4_Vtbl = {
/* IUnknown */
...
/* IDirectDraw4 */
...
( void * ) IDirectDrawImpl_SetCooperativeLevel,
( void * ) IDirectDrawImpl_SetDisplayMode,
...
}
The arguments for SetCooperativeLevel and SetDisplayMode are the same for DD7
and DD4 ( IDirectDrawX *, HWND, DWORD), (IDirectDrawX *, DWORD, DWORD, DWORD,
DWORD, DWORD). The only difference is the IDirectDrawX pointer, so I have to
use a cast to supress the warning in older Vtables( The (void *) cast is
equal to the XCAST makro in the original implementation).
A problem arises then the arguments are different in varios versions: For
example IDirectDraw::SetDisplayMode: it only takes a Pointer and 3 DWORDs. Do
I created another function:
HRESULT WINAPI IDirectDrawImpl1_SetDisplayMode(IDirectDraw *iface, DWORD
dwWidth, DWORD dwHeight, DWORD dwBPP);
And for the DD1 Vtable I use
IDirectDrawVtbl IDirectDraw1_Vtbl = {
/* IUnknown */
...
/* IDirectDraw4 */
...
( void * ) IDirectDrawImpl_SetCooperativeLevel,
IDirectDrawImpl1_SetDisplayMode,
...
}
Such functions eighter contain a independent implementation, like in
SetDisplayMode(which is only a one-liner call to WineD3D) or they call the V7
implementation(Like in IDirect3DDevcie). I can't use the VTable for this,
because there's no DD7 Vtable assigned, so I call the I<Iface>Impl_<Method>
function directly(This happens a few times in IDirect3DDevice).
In the implementation functions I can get the Implementation structure easily:
IDirectDrawImpl *This = (IDirectDrawImpl *) iface;
There's no difference in the address of the VTable and the Implementation
structure.
When creating the Interface, I allocate a I<Interface>Impl structure, and I
assign the VTable of the requested version:
if(DD7)
object->lpVtbl = &IDirectDraw7_Vtbl;
else if(DD4)
(IDirectDraw4Vtbl *) object->lpVtbl = &IDirectDraw4_Vtbl;
else if(DD2)
(IDirectDraw2Vtbl *) object->lpVtbl = &IDirectDraw2_Vtbl;
else if(DD1)
(IDirectDrawVtbl *) object->lpVtbl = &IDirectDraw1_Vtbl;
If any implementation funtion really needs to know the version of the
interface, it can compare the VTable addresses:
if(This->lpVtbl == &IDirectDraw7_Vtbl) {
DD7
} else if( (IDirectDraw4Vtbl *) This->lpVtbl == &IDirectDraw4_Vtbl) {
DD4
} ....
So I do not need a Version member in the Implementation structures ;)
This works for all games I tried so far, except for HL 1.1.1.0, so I suspect
the problem to be somewhere else. HL 1.1.1.1 (the Steam version) works,
except that it crashes in native shdocvw when entering the game(This happens
with the original ddraw version too). OpenGL mode still works fine. If there
are problems I don't know yet, they'll arise in IDirect3DDevice, as it has
heavily different VTables.
What are the advantages of this?
* No need for the Thunk_I<Interface>_<Method> functions, except for
IDirectDraw::SetDisplayMode. The app calls directly into the methods.
* No need for the ICOM_THIS_FROM, COM_INTERFACE_CAST, ... Makros.
* No difference between the Implementation address and the address passed to
the app. This makes traces easier to read IMO.
The problems?
* The (void *) cast makes it hard to find incorrectly assigned VTable members.
Maybe that's the problem with HL 1.1.1.0
* Implementation functions can't use the VTables
* It's different from other dlls that use multiple interface versions. (Are
there any? I found only ddraw)
I think I can send a new patch in the next 2 weeks, so you can look at the
whole thing.
Stefan
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://www.winehq.org/pipermail/wine-devel/attachments/20060107/da95d386/attachment.pgp
More information about the wine-devel
mailing list