我编写了一个在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;
}
答案 0 :(得分:1)
SetWindowLong( hwnd, GWLP_USERDATA, (LONG)ptr );
这是你的问题。您正在使用64位指针并将其转换为32位整数。这会丢失高32位,因此GetWindowLongPtr
会得到一个截断的指针。你在Windows 7上很幸运,因为高位碰巧是零,所以你的截断是无害的。在Windows 8上,你的运气用光了。