GetWindowLongPtr在Windows 8和Windows 10中崩溃

时间:2015-10-12 11:27:32

标签: c++ windows winapi

我编写了一个在hwnd窗口中托管webbrowser的应用程序。在Windows 7 64位中,一切都运行得很好。不幸的是,在Windows 8和Windows 10中,应用程序崩溃了。我找到了一条崩溃应用程序的行,请你告诉我为什么会崩溃?

IOleObject* browserObject;
IWebBrowser2* webBrowser2;

browserObject = *((IOleObject**)GetWindowLongPtr(hwnd, GWLP_USERDATA));
browserObject->lpVtbl->QueryInterface(browserObject, &IID_IWebBrowser2,
        (void**)&webBrowser2));


long WINAPI EmbedBrowserObject( HWND hwnd, void* externalDispatch )
{
    IOleObject* browserObject;
    IWebBrowser2* webBrowser2;
    RECT rect;
    register char* ptr;
    register _IOleClientSiteEx* _iOleClientSiteEx;

    // Our IOleClientSite, IOleInPlaceSite, and IOleInPlaceFrame functions need to
    // get our window handle. We
    // could store that in some global. But then, that would mean that our
    // functions would work with only that
    // one window. If we want to create multiple windows, each hosting its own
    // browser object (to display its
    // own web page), then we need to create unique IOleClientSite,
    // IOleInPlaceSite, and IOleInPlaceFrame
    // structs for each window. And we'll put an extra member at the end of those
    // structs to store our extra
    // data such as a window handle. So, our functions won't have to touch global
    // data, and can therefore be
    // re-entrant and work with multiple objects/windows.
    //
    // Remember that a pointer to our IOleClientSite we create here will be passed
    // as the first arg to every
    // one of our IOleClientSite functions. Ditto with the IOleInPlaceFrame object
    // we create here, and the
    // IOleInPlaceFrame functions. So, our functions are able to retrieve the
    // window handle we'll store here,
    // and then, they'll work with all such windows containing a browser control.
    //
    // Furthermore, since the browser will be calling our IOleClientSite's
    // QueryInterface to get a pointer to
    // our IOleInPlaceSite and IDocHostUIHandler objects, that means that our
    // IOleClientSite QueryInterface
    // must have an easy way to grab those pointers. Probably the easiest thing to
    // do is just embed our
    // IOleInPlaceSite and IDocHostUIHandler objects inside of an extended
    // IOleClientSite which we'll call
    // a _IOleClientSiteEx. As long as they come after the pointer to the
    // IOleClientSite VTable, then we're
    // ok.
    //
    // Of course, we need to GlobalAlloc the above structs now. We'll just get all
    // 3 with a single call to
    // GlobalAlloc, especially since they're are contained inside of our
    // _IOleClientSiteEx anyway.
    //
    // So, we're not actually allocating separate IOleClientSite, IOleInPlaceSite,
    // IOleInPlaceFrame and
    // IDocHostUIHandler structs.
    //
    // One final thing. We're going to allocate extra room to store the pointer to
    // the browser object.
    if ( !( ptr = (char*)GlobalAlloc( GMEM_FIXED, sizeof( _IOleClientSiteEx ) + sizeof( IOleObject* ) ) ) )
        return ( -1 );

    // Initialize our IOleClientSite object with a pointer to our IOleClientSite
    // VTable.
    _iOleClientSiteEx = (_IOleClientSiteEx*)( ptr + sizeof( IOleObject* ) );
    _iOleClientSiteEx->client.lpVtbl = &MyIOleClientSiteTable;

    // Initialize our IOleInPlaceSite object with a pointer to our IOleInPlaceSite
    // VTable.
    _iOleClientSiteEx->inplace.inplace.lpVtbl = &MyIOleInPlaceSiteTable;

    // Initialize our IOleInPlaceFrame object with a pointer to our
    // IOleInPlaceFrame VTable.
    _iOleClientSiteEx->inplace.frame.frame.lpVtbl = &MyIOleInPlaceFrameTable;

    // Save our HWND (in the IOleInPlaceFrame object) so our IOleInPlaceFrame
    // functions can retrieve it.
    _iOleClientSiteEx->inplace.frame.window = hwnd;

    // Initialize our IDocHostUIHandler object with a pointer to our
    // IDocHostUIHandler VTable.
    _iOleClientSiteEx->ui.ui.lpVtbl = &MyIDocHostUIHandlerTable;
    _iOleClientSiteEx->ui.externalDispatch = (IDispatch*)externalDispatch;

    // Get a pointer to the browser object and lock it down (so it doesn't
    // "disappear" while we're using
    // it in this program). We do this by calling the OS function
    // CoCreateInstance().
    //
    // NOTE: We need this pointer to interact with and control the browser. With
    // normal WIN32 controls such as a
    // Static, Edit, Combobox, etc, you obtain an HWND and send messages to it
    // with SendMessage(). Not so with
    // the browser object. You need to get a pointer to it. This object contains
    // an array of pointers to functions           // you can call within the
    // browser object. Actually, it contains a 'lpVtbl' member that is a pointer
    // to that
    // array. We call the array a 'VTable'.
    //
    // For example, the browser object happens to have a SetClientSite() function
    // we want to call. So, after we
    // retrieve the pointer to the browser object (in a local we'll name
    // 'browserObject'), then we can call that
    // function, and pass it args, as so:
    //
    // browserObject->lpVtbl->SetClientSite(browserObject, SomeIOleClientObject);
    //
    // There's our pointer to the browser object in 'browserObject'. And there's
    // the pointer to the browser object's
    // VTable in 'browserObject->lpVtbl'. And the pointer to the SetClientSite
    // function happens to be stored in a
    // member named 'SetClientSite' within the VTable. So we are actually
    // indirectly calling SetClientSite by using
    // a pointer to it. That's how you use a VTable.

    // Get Internet Explorer's IWebBrowser2 object (ie, IE's main object)
    if ( !CoCreateInstance( &CLSID_WebBrowser, 0, CLSCTX_INPROC, &IID_IWebBrowser2,
                            (void**)&webBrowser2 ) ) {
        browserObject = 0;

        // We need to get a pointer to IWebBrowser2's IOleObject child object
        webBrowser2->lpVtbl->QueryInterface( webBrowser2, &IID_IOleObject,
                                             (void**)&browserObject );

        // Ok, we now have the pointer to the IOleObject child object in
        // 'browserObject'. Let's save this in the
        // memory block we allocated above, and then save the pointer to that whole
        // thing in our window's
        // USERDATA member. That way, if we need multiple windows each hosting its
        // own browser object, we can
        // call EmbedBrowserObject() for each one, and easily associate the
        // appropriate browser object with
        // its matching window and its own objects containing per-window data.
        if ( ( *( (IOleObject**)ptr ) = browserObject ) ) {
            SetWindowLong( hwnd, GWLP_USERDATA, (LONG)ptr );

            // Give the browser a pointer to my IOleClientSite object.
            //
            // NOTE: We pass our _IOleClientSiteEx struct and lie -- saying that it's
            // a IOleClientSite. It's ok. A
            // _IOleClientSiteEx struct starts with an embedded IOleClientSite. So the
            // browser won't care, and we want
            // this extended struct passed to our IOleClientSite functions.
            if ( !browserObject->lpVtbl->SetClientSite(
                      browserObject, (IOleClientSite*)_iOleClientSiteEx ) ) {
                // Set the display area of our browser control the same as our window's
                // size
                // and actually put the browser object into our window.
                GetClientRect( hwnd, &rect );
                if ( !browserObject->lpVtbl->DoVerb(
                          browserObject, OLEIVERB_INPLACEACTIVATE, 0,
                          (IOleClientSite*)_iOleClientSiteEx, 0, hwnd, &rect ) ) {
                    // Let's call several functions in the IWebBrowser2 object to position
                    // the browser display area
                    // in our window. The functions we call are put_Left(), put_Top(),
                    // put_Width(), and put_Height().
                    // Note that we reference the IWebBrowser2 object's VTable to get
                    // pointers to those functions. And
                    // also note that the first arg we pass to each is the pointer to the
                    // IWebBrowser2 object.
                    webBrowser2->lpVtbl->put_Left( webBrowser2, 0 );
                    webBrowser2->lpVtbl->put_Top( webBrowser2, 0 );
                    webBrowser2->lpVtbl->put_Width( webBrowser2, rect.right );
                    webBrowser2->lpVtbl->put_Height( webBrowser2, rect.bottom );

                    // We no longer need the IWebBrowser2 object (ie, we don't plan to
                    // call any more functions in it
                    // right now, so we can release our hold on it). Note that we'll still
                    // maintain our hold on the
                    // browser IOleObject until we're done with that object.
                    webBrowser2->lpVtbl->Release( webBrowser2 );

                    // Success
                    return ( 0 );
                }
            }

            webBrowser2->lpVtbl->Release( webBrowser2 );

            // Something went wrong setting up the browser!
            UnEmbedBrowserObject( hwnd );
            return ( -4 );
        }

        webBrowser2->lpVtbl->Release( webBrowser2 );

        GlobalFree( ptr );

        // Can't create an instance of the browser!
        return ( -3 );
    }

        GlobalFree( ptr );
        enter code here
        // Can't get the web browser's IWebBrowser2!
        return ( -2 );
    }

然后从获取webbrowser2对象的函数调用此代码。

@import "../valo/valo";
@import "common";
@import "views/login";
@import "views/dashboardview";
@import "views/schedule";
@import "views/sales";
@import "views/transactions";
@import "views/reports";

// Optimize the CSS output
$v-included-components: remove($v-included-components, accordion);
$v-included-components: remove($v-included-components, colorpicker);
$v-included-components: remove($v-included-components, grid);
$v-included-components: remove($v-included-components, popupview);
$v-included-components: remove($v-included-components, progressbar);
$v-included-components: remove($v-included-components, slider);
$v-included-components: remove($v-included-components, splitpanel);
$v-included-components: remove($v-included-components, tree);
$v-included-components: remove($v-included-components, treetable);
$v-included-components: remove($v-included-components, twincolselect);

// Main layout padding
$view-padding: round($v-unit-size / 1.5) !default;

// Slight adjustment to menu background-color
$valo-menu-background-color: #414B56;

@mixin dashboard {
  @include valo;
  @include dashboard-common;
  @include dashboard-login-view;
  @include dashboard-dashboard-view;
  @include dashboard-schedule-view;
  @include dashboard-sales-view;
  @include dashboard-transactions-view;
  @include dashboard-reports-view;
}

1 个答案:

答案 0 :(得分:1)

SetWindowLong( hwnd, GWLP_USERDATA, (LONG)ptr );

这是你的问题。您正在使用64位指针并将其转换为32位整数。这会丢失高32位,因此GetWindowLongPtr会得到一个截断的指针。你在Windows 7上很幸运,因为高位碰巧是零,所以你的截断是无害的。在Windows 8上,你的运气用光了。