get twindowlongptr崩溃在windows 8和windows 10

GetWindowLongPtr crash in windows 8 and windows 10

本文关键字:windows twindowlongptr 崩溃 get      更新时间:2023-10-16

我写了一个应用程序,它在一个hwnd窗口内托管一个web浏览器。在windows 7 64位系统中,一切都运行得很完美。不幸的是,在windows 8和windows 10中,应用程序崩溃了。我发现一行代码导致应用程序崩溃,你能告诉我为什么会崩溃吗?

ExternalDispatch *m_external = myHost->getDispatch();
m_external->AddRef();
result = EmbedBrowserObject(hwnd, m_external);
if (result)  {
    return(-1);
}

然后从一个获取webbrowser2对象的函数调用这段代码。

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 );
    }
SetWindowLong( hwnd, GWLP_USERDATA, (LONG)ptr );

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