www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Access violation when calling member function through pointer

reply aleko <aleko_member pathlink.com> writes:
Hi,

I have a window class with a static WndMain handler. After creating the window,
I tag it with the address of the class instance so that WndProc knows which
class instance to dispatch events to. When called, WndProc extracts the class
pointer, and calls the appropriate event handler method. The problem is that
when WndProc tries to dereference the "this" pointer an access violation occurs.
Here's some code:

class MyWindow
{
public:
bool create()
{
// fill WNDCLASSA...
// register class...
// create window...
SetWindowLong( _HWnd, GWL_USERDATA, cast(uint)&this );
}

private:

extern( Windows )
static uint WndProc( HWND hwnd, uint msg, uint lparam, uint wparam )
{
// get address 
MyWindow *thisWnd = cast(MyWindow*)GetWindowLong( hwnd, GWL_USERDATA );
int result = 0;

switch( msg )
{
:
thisWnd.onSomeEvent( 1, 2, 3 ); // Access violation! Why??
:
}
}
}

Thanks in advance,

Aleko
Apr 16 2005
next sibling parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
 When called, WndProc extracts the class
 pointer, and calls the appropriate event handler method. The problem is 
 that
 when WndProc tries to dereference the "this" pointer an access violation 
 occurs.

Well.... your are not alone, once per month this question arises :) The problem is that you are not storing Window reference in the place where "mark-n-sweeping" GC can reach it on "mark" stage. So your Window instance is getting deleted on "sweep" as it is not visible for D runtime thus your are trying to work with the instance which was destroyed already. One of the possible solutions is to use static global map ( 'all' below ) which maps HWND to correspondent Window instance class Window { HWND hWnd; ............. } Window[HWND] all; void createWindow(Window w) { w.hWnd = CreateWindowExW(0,cast(LPCWSTR)"DWindow",...., null); all[hWnd] = w.hWnd; } private Window self(HWND h) { Window *pw = h in all; if( pw !== null ) return *pw; return null; } extern(Windows) LRESULT DWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_SIZE: case WM_MOVE: { Window w = self(hWnd); if(w is null) break; } break; ..... } } Regards. Andrew. http://terrainformatica.com "aleko" <aleko_member pathlink.com> wrote in message news:d3ssu4$12av$1 digitaldaemon.com...
 Hi,

 I have a window class with a static WndMain handler. After creating the 
 window,
 I tag it with the address of the class instance so that WndProc knows 
 which
 class instance to dispatch events to. When called, WndProc extracts the 
 class
 pointer, and calls the appropriate event handler method. The problem is 
 that
 when WndProc tries to dereference the "this" pointer an access violation 
 occurs.
 Here's some code:

 class MyWindow
 {
 public:
 bool create()
 {
 // fill WNDCLASSA...
 // register class...
 // create window...
 SetWindowLong( _HWnd, GWL_USERDATA, cast(uint)&this );
 }

 private:

 extern( Windows )
 static uint WndProc( HWND hwnd, uint msg, uint lparam, uint wparam )
 {
 // get address
 MyWindow *thisWnd = cast(MyWindow*)GetWindowLong( hwnd, GWL_USERDATA );
 int result = 0;

 switch( msg )
 {
 :
 thisWnd.onSomeEvent( 1, 2, 3 ); // Access violation! Why??
 :
 }
 }
 }

 Thanks in advance,

 Aleko

 

Apr 16 2005
parent aleko <aleko_member pathlink.com> writes:
Thanks, you pointed me in the right direction. It works now.

The problem is that you are not storing Window reference in
the place where "mark-n-sweeping" GC can reach it on "mark" stage.

So your Window instance is getting deleted on "sweep" as it is not visible
for D runtime thus your are trying to work with the instance which was
destroyed already.

This seems very strange to me. I can see how this would effect local objects, but the window instance remains referenced in WinMain where it is created. Another thing that puzzled me is the need to use the address-of operator on 'this', i.e. cast(uint)&this. Is 'this' a reference or a pointer? Thanks, Aleko
Apr 19 2005
prev sibling parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
 SetWindowLong( _HWnd, GWL_USERDATA, cast(uint)&this );

try "this" instead of "&this"
 MyWindow thisWnd = cast(MyWindow)cast(void*)GetWindowLong( hwnd, 
 GWL_USERDATA );

and store to a MyWindow
Apr 17 2005
parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Ben Hinkle" <ben.hinkle gmail.com> wrote in message 
news:d3tgmd$1h4q$1 digitaldaemon.com...
 SetWindowLong( _HWnd, GWL_USERDATA, cast(uint)&this );

try "this" instead of "&this"

oh yeah - you are probably going to need something like cast(uint)cast(void*)this.
Apr 17 2005
parent aleko <aleko_member pathlink.com> writes:
 try "this" instead of "&this"


That was my initial idea. I was quite surprised when the compiler complained that it couldn't convert from a MyWindow to a uint. It looked to me as if 'this' is a reference, and not a pointer.
oh yeah - you are probably going to need something like 
cast(uint)cast(void*)this. 

I hadn't though of that. For someone with a C++ background this is a bit of a stretch. Aleko
Apr 19 2005