Thread overview
Access violation when calling member function through pointer
Apr 17, 2005
aleko
Apr 17, 2005
Andrew Fedoniouk
Apr 19, 2005
aleko
Apr 17, 2005
Ben Hinkle
Apr 17, 2005
Ben Hinkle
Apr 19, 2005
aleko
April 17, 2005
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


April 17, 2005
> 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
>
> 


April 17, 2005
> 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


April 17, 2005
"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.


April 19, 2005
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


April 19, 2005
>> 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