Mercurial > dwindows
comparison win/browser.c @ 2017:686b2d049056
Win: Attempt to add event handler to capture DocumentComplete with embedded IE.
This code doesm't work yet, but I needed to commit it to switch computers.
author | bsmith@81767d24-ef19-dc11-ae90-00e081727c95 |
---|---|
date | Fri, 08 Nov 2019 07:20:17 +0000 |
parents | f696215e6d4e |
children | 663d79f28e46 |
comparison
equal
deleted
inserted
replaced
2016:f696215e6d4e | 2017:686b2d049056 |
---|---|
25 #include <windows.h> | 25 #include <windows.h> |
26 #include <exdisp.h> // Defines of stuff like IWebBrowser2. This is an include file with Visual C 6 and above | 26 #include <exdisp.h> // Defines of stuff like IWebBrowser2. This is an include file with Visual C 6 and above |
27 #include <mshtml.h> // Defines of stuff like IHTMLDocument2. This is an include file with Visual C 6 and above | 27 #include <mshtml.h> // Defines of stuff like IHTMLDocument2. This is an include file with Visual C 6 and above |
28 #include <mshtmhst.h> // Defines of stuff like IDocHostUIHandler. This is an include file with Visual C 6 and above | 28 #include <mshtmhst.h> // Defines of stuff like IDocHostUIHandler. This is an include file with Visual C 6 and above |
29 #include <crtdbg.h> // for _ASSERT() | 29 #include <crtdbg.h> // for _ASSERT() |
30 #include <initguid.h> | |
30 #include "dw.h" | 31 #include "dw.h" |
31 | 32 |
32 // This is used by DisplayHTMLStr(). It can be global because we never change it. | 33 // This is used by DisplayHTMLStr(). It can be global because we never change it. |
33 static const SAFEARRAYBOUND ArrayBound = {1, 0}; | 34 static const SAFEARRAYBOUND ArrayBound = {1, 0}; |
34 | 35 |
1073 { | 1074 { |
1074 NOTIMPLEMENTED; | 1075 NOTIMPLEMENTED; |
1075 } | 1076 } |
1076 | 1077 |
1077 | 1078 |
1078 | 1079 // The DWEventHandler object must be created by an application using IWebBRowser2, |
1079 | 1080 // and given to IWebBrowser2's IConnectPoint object (via |
1080 | 1081 // IConnectPoint's Advise function). |
1081 | 1082 // {4115B8E2-1823-4bbc-B10D-3D33AAA12ACF} |
1083 | |
1084 // DWEventHandler VTable's GUID | |
1085 // {d2d531c4-83d7-48d7-b733-840245ea2b34} | |
1086 DEFINE_GUID(DIID_DWEventHandler, 0xd2d531c4, 0x83d7, 0x48d7, 0xb7, 0x33, 0x84, 0x2, 0x45, 0xea, 0x2b, 0x34); | |
1087 | |
1088 // DWEventHandler's VTable | |
1089 #undef INTERFACE | |
1090 #define INTERFACE DWEventHandler | |
1091 DECLARE_INTERFACE_ (INTERFACE, IUnknown) | |
1092 { | |
1093 // IUnknown functions | |
1094 STDMETHOD (QueryInterface) (THIS_ REFIID, void **) PURE; | |
1095 STDMETHOD_ (ULONG, AddRef) (THIS) PURE; | |
1096 STDMETHOD_ (ULONG, Release) (THIS) PURE; | |
1097 // Extra functions | |
1098 STDMETHOD_ (void, DocumentComplete) (THIS_ IDispatch*, VARIANT*) PURE; | |
1099 }; | |
1100 | |
1101 // IWebBrowser2 supports us giving it only 1 DWEventHandler object, so for simplicity, we | |
1102 // can just declare it as a global. That way, we don't need to allocate it, free it, | |
1103 // nor maintain a reference count for it. Here's our 1 DWEventHandler object. | |
1104 static DWEventHandler MyDWEventHandler; | |
1105 | |
1106 | |
1107 static HRESULT STDMETHODCALLTYPE DWEventHandler_QueryInterface(DWEventHandler *this, REFIID vTableGuid, void **ppv) | |
1108 { | |
1109 // This is an DWEventHandler object, so we must recognize DWEventHandler VTable's GUID, | |
1110 // Our DWEventHandler can also masquerade as an IUnknown | |
1111 if (!IsEqualIID(vTableGuid, &IID_IUnknown) && !IsEqualIID(vTableGuid, &DIID_DWEventHandler)) | |
1112 { | |
1113 *ppv = 0; | |
1114 return(E_NOINTERFACE); | |
1115 } | |
1116 | |
1117 *ppv = this; | |
1118 | |
1119 // Normally, we'd call our AddRef function here. But since our DWEventHandler isn't | |
1120 // allocated, we don't need to bother with reference counting | |
1121 return(NOERROR); | |
1122 } | |
1123 | |
1124 static ULONG STDMETHODCALLTYPE DWEventHandler_AddRef(DWEventHandler *this) | |
1125 { | |
1126 // Our one and only DWEventHandler isn't allocated. Instead, it is statically | |
1127 // declared above (MyDWEventHandler). So we'll just return a 1 | |
1128 return(1); | |
1129 } | |
1130 | |
1131 static ULONG STDMETHODCALLTYPE DWEventHandler_Release(DWEventHandler *this) | |
1132 { | |
1133 return(1); | |
1134 } | |
1135 | |
1136 // This is the extra function for DWEventHandler. | |
1137 | |
1138 static void STDMETHODCALLTYPE DWEventHandler_DocumentComplete(DWEventHandler *this, IDispatch* pDisp, VARIANT* URL) | |
1139 { | |
1140 // Do a compare of the two elements. We happen to know that | |
1141 // we'll be passing an array of DWORD values to Sort() | |
1142 dw_debug("DocumentComplete() called!\n"); | |
1143 } | |
1144 | |
1145 | |
1146 // Our DWEventHandler VTable. We need only one of these, so we can | |
1147 // declare it static | |
1148 static const DWEventHandlerVtbl DWEventHandler_Vtbl = { | |
1149 DWEventHandler_QueryInterface, | |
1150 DWEventHandler_AddRef, | |
1151 DWEventHandler_Release, | |
1152 DWEventHandler_DocumentComplete | |
1153 }; | |
1082 | 1154 |
1083 | 1155 |
1084 /*************************** UnEmbedBrowserObject() ************************ | 1156 /*************************** UnEmbedBrowserObject() ************************ |
1085 * Called to detach the browser object from our host window, and free its | 1157 * Called to detach the browser object from our host window, and free its |
1086 * resources, right before we destroy our window. | 1158 * resources, right before we destroy our window. |
1530 IOleObject *browserObject; | 1602 IOleObject *browserObject; |
1531 IWebBrowser2 *webBrowser2; | 1603 IWebBrowser2 *webBrowser2; |
1532 RECT rect; | 1604 RECT rect; |
1533 char *ptr; | 1605 char *ptr; |
1534 _IOleClientSiteEx *_iOleClientSiteEx; | 1606 _IOleClientSiteEx *_iOleClientSiteEx; |
1607 | |
1608 MyDWEventHandler.lpVtbl = (DWEventHandlerVtbl *)&DWEventHandler_Vtbl; | |
1535 | 1609 |
1536 // Our IOleClientSite, IOleInPlaceSite, and IOleInPlaceFrame functions need to get our window handle. We | 1610 // Our IOleClientSite, IOleInPlaceSite, and IOleInPlaceFrame functions need to get our window handle. We |
1537 // could store that in some global. But then, that would mean that our functions would work with only that | 1611 // could store that in some global. But then, that would mean that our functions would work with only that |
1538 // one window. If we want to create multiple windows, each hosting its own browser object (to display its | 1612 // one window. If we want to create multiple windows, each hosting its own browser object (to display its |
1539 // own web page), then we need to create unique IOleClientSite, IOleInPlaceSite, and IOleInPlaceFrame | 1613 // own web page), then we need to create unique IOleClientSite, IOleInPlaceSite, and IOleInPlaceFrame |
1610 // USERDATA field. That way, if we need multiple windows each hosting its own browser object, we can | 1684 // USERDATA field. That way, if we need multiple windows each hosting its own browser object, we can |
1611 // call EmbedBrowserObject() for each one, and easily associate the appropriate browser object with | 1685 // call EmbedBrowserObject() for each one, and easily associate the appropriate browser object with |
1612 // its matching window and its own objects containing per-window data. | 1686 // its matching window and its own objects containing per-window data. |
1613 *((IOleObject **)ptr) = browserObject; | 1687 *((IOleObject **)ptr) = browserObject; |
1614 dw_window_set_data(hwnd, "_dw_html", (void *)ptr); | 1688 dw_window_set_data(hwnd, "_dw_html", (void *)ptr); |
1615 | 1689 |
1616 // We can now call the browser object's SetHostNames function. SetHostNames lets the browser object know our | 1690 // We can now call the browser object's SetHostNames function. SetHostNames lets the browser object know our |
1617 // application's name and the name of the document in which we're embedding the browser. (Since we have no | 1691 // application's name and the name of the document in which we're embedding the browser. (Since we have no |
1618 // document name, we'll pass a 0 for the latter). When the browser object is opened for editing, it displays | 1692 // document name, we'll pass a 0 for the latter). When the browser object is opened for editing, it displays |
1619 // these names in its titlebar. | 1693 // these names in its titlebar. |
1620 // | 1694 // |
1658 // object, so we can call some of the functions in the former's table. For example, one IWebBrowser2 function | 1732 // object, so we can call some of the functions in the former's table. For example, one IWebBrowser2 function |
1659 // we intend to call below will be Navigate2(). So we call the browser object's QueryInterface to get our | 1733 // we intend to call below will be Navigate2(). So we call the browser object's QueryInterface to get our |
1660 // pointer to the IWebBrowser2 object. | 1734 // pointer to the IWebBrowser2 object. |
1661 !browserObject->lpVtbl->QueryInterface(browserObject, &IID_IWebBrowser2, (void**)&webBrowser2)) | 1735 !browserObject->lpVtbl->QueryInterface(browserObject, &IID_IWebBrowser2, (void**)&webBrowser2)) |
1662 { | 1736 { |
1737 IConnectionPointContainer *container; | |
1738 IConnectionPoint *point; | |
1739 HRESULT hr; | |
1740 | |
1663 // Ok, now the pointer to our IWebBrowser2 object is in 'webBrowser2', and so its VTable is | 1741 // Ok, now the pointer to our IWebBrowser2 object is in 'webBrowser2', and so its VTable is |
1664 // webBrowser2->lpVtbl. | 1742 // webBrowser2->lpVtbl. |
1665 | 1743 |
1666 // Let's call several functions in the IWebBrowser2 object to position the browser display area | 1744 // Let's call several functions in the IWebBrowser2 object to position the browser display area |
1667 // in our window. The functions we call are put_Left(), put_Top(), put_Width(), and put_Height(). | 1745 // in our window. The functions we call are put_Left(), put_Top(), put_Width(), and put_Height(). |
1670 webBrowser2->lpVtbl->put_Left(webBrowser2, 0); | 1748 webBrowser2->lpVtbl->put_Left(webBrowser2, 0); |
1671 webBrowser2->lpVtbl->put_Top(webBrowser2, 0); | 1749 webBrowser2->lpVtbl->put_Top(webBrowser2, 0); |
1672 webBrowser2->lpVtbl->put_Width(webBrowser2, rect.right); | 1750 webBrowser2->lpVtbl->put_Width(webBrowser2, rect.right); |
1673 webBrowser2->lpVtbl->put_Height(webBrowser2, rect.bottom); | 1751 webBrowser2->lpVtbl->put_Height(webBrowser2, rect.bottom); |
1674 | 1752 |
1753 // Get IWebBrowser2' IConnectionPointContainer sub-object. We do this by calling | |
1754 // IWebBrowser2' QueryInterface, and pass it the standard GUID for an | |
1755 // IConnectionPointContainer VTable | |
1756 if ((hr = webBrowser2->lpVtbl->QueryInterface(webBrowser2, &IID_IConnectionPointContainer, &container))) | |
1757 dw_debug("QueryInterface error: Can't get IConnectionPointContainer object"); | |
1758 else | |
1759 { | |
1760 // Get IWebBrowser2' IConnectionPoint sub-object for specifically giving | |
1761 // IWebBRowser2 our DWEventHandler. We do this by calling IConnectionPointContainer's | |
1762 // FindConnectionPoint, and pass it DWEventHandler VTable's GUID | |
1763 hr = container->lpVtbl->FindConnectionPoint(container, &DIID_DWEventHandler, &point); | |
1764 | |
1765 // We don't need the IConnectionPointContainer, now that we got the one IConnectionPoint | |
1766 // we want (ie, the one we use to give IWebBrowser2 our DWEventHandler) | |
1767 container->lpVtbl->Release(container); | |
1768 | |
1769 if (hr) | |
1770 dw_debug("FindConnectionPoint error: Can't get IConnectionPoint object"); | |
1771 else | |
1772 { | |
1773 DWORD cookie; | |
1774 | |
1775 // Now call the IConnectionPoint's Advise function, giving it some object | |
1776 // whose QueryInterface it will call to get our DWEventHandler object. Let's | |
1777 // just give it our DWEventHandler object. So Advise will call our DWEventHandler's | |
1778 // QueryInterface to tell us to give it a pointer to our DWEventHandler. Dumb? | |
1779 // You bet. All of this convoluted stuff is a combination of poor pre-planning | |
1780 // by Microsoft programmers when they designed this stuff, as well as the | |
1781 // colossal blunder of designing COM to accomodate the limitations of early, | |
1782 // primitive editions of Visual Basic. | |
1783 // | |
1784 // Advise() gives us back a "cookie" value that we'll need to later pass to | |
1785 // Unadvise() (when we want to tell IWebBrowser2 to stop using our DWEventHandler) | |
1786 if ((hr = point->lpVtbl->Advise(point, (IUnknown *)&MyDWEventHandler, &cookie))) | |
1787 dw_debug("Advise error: Can't set our DWEventHandler object"); | |
1788 else | |
1789 dw_window_set_data(hwnd, "_dw_html_cookie", DW_INT_TO_POINTER(cookie)); | |
1790 } | |
1791 } | |
1792 | |
1675 // We no longer need the IWebBrowser2 object (ie, we don't plan to call any more functions in it | 1793 // We no longer need the IWebBrowser2 object (ie, we don't plan to call any more functions in it |
1676 // right now, so we can release our hold on it). Note that we'll still maintain our hold on the | 1794 // right now, so we can release our hold on it). Note that we'll still maintain our hold on the |
1677 // browser object until we're done with that object. | 1795 // browser object until we're done with that object. |
1678 webBrowser2->lpVtbl->Release(webBrowser2); | 1796 webBrowser2->lpVtbl->Release(webBrowser2); |
1679 | 1797 |