tauri-windows.c 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175
  1. #include "tauri-windows-webview.h"
  2. #include "tauri.h"
  3. #pragma comment(lib, "user32.lib")
  4. #pragma comment(lib, "ole32.lib")
  5. #pragma comment(lib, "oleaut32.lib")
  6. #define WM_WEBVIEW_DISPATCH (WM_APP + 1)
  7. typedef struct {
  8. IOleInPlaceFrame frame;
  9. HWND window;
  10. } _IOleInPlaceFrameEx;
  11. typedef struct {
  12. IOleInPlaceSite inplace;
  13. _IOleInPlaceFrameEx frame;
  14. } _IOleInPlaceSiteEx;
  15. typedef struct {
  16. IDocHostUIHandler ui;
  17. } _IDocHostUIHandlerEx;
  18. typedef struct {
  19. IInternetSecurityManager mgr;
  20. } _IInternetSecurityManagerEx;
  21. typedef struct {
  22. IServiceProvider provider;
  23. _IInternetSecurityManagerEx mgr;
  24. } _IServiceProviderEx;
  25. typedef struct {
  26. IOleClientSite client;
  27. _IOleInPlaceSiteEx inplace;
  28. _IDocHostUIHandlerEx ui;
  29. IDispatch external;
  30. _IServiceProviderEx provider;
  31. } _IOleClientSiteEx;
  32. #ifdef __cplusplus
  33. #define iid_ref(x) &(x)
  34. #define iid_unref(x) *(x)
  35. #else
  36. #define iid_ref(x) (x)
  37. #define iid_unref(x) (x)
  38. #endif
  39. static inline WCHAR *webview_to_utf16(const char *s) {
  40. DWORD size = MultiByteToWideChar(CP_UTF8, 0, s, -1, 0, 0);
  41. WCHAR *ws = (WCHAR *)GlobalAlloc(GMEM_FIXED, sizeof(WCHAR) * size);
  42. if (ws == NULL) {
  43. return NULL;
  44. }
  45. MultiByteToWideChar(CP_UTF8, 0, s, -1, ws, size);
  46. return ws;
  47. }
  48. static inline char *webview_from_utf16(WCHAR *ws) {
  49. int n = WideCharToMultiByte(CP_UTF8, 0, ws, -1, NULL, 0, NULL, NULL);
  50. char *s = (char *)GlobalAlloc(GMEM_FIXED, n);
  51. if (s == NULL) {
  52. return NULL;
  53. }
  54. WideCharToMultiByte(CP_UTF8, 0, ws, -1, s, n, NULL, NULL);
  55. return s;
  56. }
  57. static int iid_eq(REFIID a, const IID *b) {
  58. return memcmp((const void *)iid_ref(a), (const void *)b, sizeof(GUID)) == 0;
  59. }
  60. static HRESULT STDMETHODCALLTYPE JS_QueryInterface(IDispatch FAR *This,
  61. REFIID riid,
  62. LPVOID FAR *ppvObj) {
  63. if (iid_eq(riid, &IID_IDispatch)) {
  64. *ppvObj = This;
  65. return S_OK;
  66. }
  67. *ppvObj = 0;
  68. return E_NOINTERFACE;
  69. }
  70. static ULONG STDMETHODCALLTYPE JS_AddRef(IDispatch FAR *This) { return 1; }
  71. static ULONG STDMETHODCALLTYPE JS_Release(IDispatch FAR *This) { return 1; }
  72. static HRESULT STDMETHODCALLTYPE JS_GetTypeInfoCount(IDispatch FAR *This,
  73. UINT *pctinfo) {
  74. return S_OK;
  75. }
  76. static HRESULT STDMETHODCALLTYPE JS_GetTypeInfo(IDispatch FAR *This,
  77. UINT iTInfo, LCID lcid,
  78. ITypeInfo **ppTInfo) {
  79. return S_OK;
  80. }
  81. #define WEBVIEW_JS_INVOKE_ID 0x1000
  82. static HRESULT STDMETHODCALLTYPE JS_GetIDsOfNames(IDispatch FAR *This,
  83. REFIID riid,
  84. LPOLESTR *rgszNames,
  85. UINT cNames, LCID lcid,
  86. DISPID *rgDispId) {
  87. if (cNames != 1) {
  88. return S_FALSE;
  89. }
  90. if (wcscmp(rgszNames[0], L"invoke") == 0) {
  91. rgDispId[0] = WEBVIEW_JS_INVOKE_ID;
  92. return S_OK;
  93. }
  94. return S_FALSE;
  95. }
  96. static HRESULT STDMETHODCALLTYPE
  97. JS_Invoke(IDispatch FAR *This, DISPID dispIdMember, REFIID riid, LCID lcid,
  98. WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
  99. EXCEPINFO *pExcepInfo, UINT *puArgErr) {
  100. size_t offset = (size_t) & ((_IOleClientSiteEx *)NULL)->external;
  101. _IOleClientSiteEx *ex = (_IOleClientSiteEx *)((char *)(This)-offset);
  102. struct webview *w = (struct webview *)GetWindowLongPtr(
  103. ex->inplace.frame.window, GWLP_USERDATA);
  104. if (pDispParams->cArgs == 1 && pDispParams->rgvarg[0].vt == VT_BSTR) {
  105. BSTR bstr = pDispParams->rgvarg[0].bstrVal;
  106. char *s = webview_from_utf16(bstr);
  107. if (s != NULL) {
  108. if (dispIdMember == WEBVIEW_JS_INVOKE_ID) {
  109. if (w->external_invoke_cb != NULL) {
  110. w->external_invoke_cb(w, s);
  111. }
  112. } else {
  113. return S_FALSE;
  114. }
  115. GlobalFree(s);
  116. }
  117. }
  118. return S_OK;
  119. }
  120. static IDispatchVtbl ExternalDispatchTable = {
  121. JS_QueryInterface, JS_AddRef, JS_Release, JS_GetTypeInfoCount,
  122. JS_GetTypeInfo, JS_GetIDsOfNames, JS_Invoke};
  123. static ULONG STDMETHODCALLTYPE Site_AddRef(IOleClientSite FAR *This) {
  124. return 1;
  125. }
  126. static ULONG STDMETHODCALLTYPE Site_Release(IOleClientSite FAR *This) {
  127. return 1;
  128. }
  129. static HRESULT STDMETHODCALLTYPE Site_SaveObject(IOleClientSite FAR *This) {
  130. return E_NOTIMPL;
  131. }
  132. static HRESULT STDMETHODCALLTYPE Site_GetMoniker(IOleClientSite FAR *This,
  133. DWORD dwAssign,
  134. DWORD dwWhichMoniker,
  135. IMoniker **ppmk) {
  136. return E_NOTIMPL;
  137. }
  138. static HRESULT STDMETHODCALLTYPE
  139. Site_GetContainer(IOleClientSite FAR *This, LPOLECONTAINER FAR *ppContainer) {
  140. *ppContainer = 0;
  141. return E_NOINTERFACE;
  142. }
  143. static HRESULT STDMETHODCALLTYPE Site_ShowObject(IOleClientSite FAR *This) {
  144. return NOERROR;
  145. }
  146. static HRESULT STDMETHODCALLTYPE Site_OnShowWindow(IOleClientSite FAR *This,
  147. BOOL fShow) {
  148. return E_NOTIMPL;
  149. }
  150. static HRESULT STDMETHODCALLTYPE
  151. Site_RequestNewObjectLayout(IOleClientSite FAR *This) {
  152. return E_NOTIMPL;
  153. }
  154. static HRESULT STDMETHODCALLTYPE Site_QueryInterface(IOleClientSite FAR *This,
  155. REFIID riid,
  156. void **ppvObject) {
  157. if (iid_eq(riid, &IID_IUnknown) || iid_eq(riid, &IID_IOleClientSite)) {
  158. *ppvObject = &((_IOleClientSiteEx *)This)->client;
  159. } else if (iid_eq(riid, &IID_IOleInPlaceSite)) {
  160. *ppvObject = &((_IOleClientSiteEx *)This)->inplace;
  161. } else if (iid_eq(riid, &IID_IDocHostUIHandler)) {
  162. *ppvObject = &((_IOleClientSiteEx *)This)->ui;
  163. } else if (iid_eq(riid, &IID_IServiceProvider)) {
  164. *ppvObject = &((_IOleClientSiteEx *)This)->provider;
  165. } else {
  166. *ppvObject = 0;
  167. return (E_NOINTERFACE);
  168. }
  169. return S_OK;
  170. }
  171. static HRESULT STDMETHODCALLTYPE InPlace_QueryInterface(
  172. IOleInPlaceSite FAR *This, REFIID riid, LPVOID FAR *ppvObj) {
  173. return (Site_QueryInterface(
  174. (IOleClientSite *)((char *)This - sizeof(IOleClientSite)), riid, ppvObj));
  175. }
  176. static ULONG STDMETHODCALLTYPE InPlace_AddRef(IOleInPlaceSite FAR *This) {
  177. return 1;
  178. }
  179. static ULONG STDMETHODCALLTYPE InPlace_Release(IOleInPlaceSite FAR *This) {
  180. return 1;
  181. }
  182. static HRESULT STDMETHODCALLTYPE InPlace_GetWindow(IOleInPlaceSite FAR *This,
  183. HWND FAR *lphwnd) {
  184. *lphwnd = ((_IOleInPlaceSiteEx FAR *)This)->frame.window;
  185. return S_OK;
  186. }
  187. static HRESULT STDMETHODCALLTYPE
  188. InPlace_ContextSensitiveHelp(IOleInPlaceSite FAR *This, BOOL fEnterMode) {
  189. return E_NOTIMPL;
  190. }
  191. static HRESULT STDMETHODCALLTYPE
  192. InPlace_CanInPlaceActivate(IOleInPlaceSite FAR *This) {
  193. return S_OK;
  194. }
  195. static HRESULT STDMETHODCALLTYPE
  196. InPlace_OnInPlaceActivate(IOleInPlaceSite FAR *This) {
  197. return S_OK;
  198. }
  199. static HRESULT STDMETHODCALLTYPE
  200. InPlace_OnUIActivate(IOleInPlaceSite FAR *This) {
  201. return S_OK;
  202. }
  203. static HRESULT STDMETHODCALLTYPE InPlace_GetWindowContext(
  204. IOleInPlaceSite FAR *This, LPOLEINPLACEFRAME FAR *lplpFrame,
  205. LPOLEINPLACEUIWINDOW FAR *lplpDoc, LPRECT lprcPosRect, LPRECT lprcClipRect,
  206. LPOLEINPLACEFRAMEINFO lpFrameInfo) {
  207. *lplpFrame = (LPOLEINPLACEFRAME) & ((_IOleInPlaceSiteEx *)This)->frame;
  208. *lplpDoc = 0;
  209. lpFrameInfo->fMDIApp = FALSE;
  210. lpFrameInfo->hwndFrame = ((_IOleInPlaceFrameEx *)*lplpFrame)->window;
  211. lpFrameInfo->haccel = 0;
  212. lpFrameInfo->cAccelEntries = 0;
  213. return S_OK;
  214. }
  215. static HRESULT STDMETHODCALLTYPE InPlace_Scroll(IOleInPlaceSite FAR *This,
  216. SIZE scrollExtent) {
  217. return E_NOTIMPL;
  218. }
  219. static HRESULT STDMETHODCALLTYPE
  220. InPlace_OnUIDeactivate(IOleInPlaceSite FAR *This, BOOL fUndoable) {
  221. return S_OK;
  222. }
  223. static HRESULT STDMETHODCALLTYPE
  224. InPlace_OnInPlaceDeactivate(IOleInPlaceSite FAR *This) {
  225. return S_OK;
  226. }
  227. static HRESULT STDMETHODCALLTYPE
  228. InPlace_DiscardUndoState(IOleInPlaceSite FAR *This) {
  229. return E_NOTIMPL;
  230. }
  231. static HRESULT STDMETHODCALLTYPE
  232. InPlace_DeactivateAndUndo(IOleInPlaceSite FAR *This) {
  233. return E_NOTIMPL;
  234. }
  235. static HRESULT STDMETHODCALLTYPE
  236. InPlace_OnPosRectChange(IOleInPlaceSite FAR *This, LPCRECT lprcPosRect) {
  237. IOleObject *browserObject;
  238. IOleInPlaceObject *inplace;
  239. browserObject = *((IOleObject **)((char *)This - sizeof(IOleObject *) -
  240. sizeof(IOleClientSite)));
  241. if (!browserObject->lpVtbl->QueryInterface(browserObject,
  242. iid_unref(&IID_IOleInPlaceObject),
  243. (void **)&inplace)) {
  244. inplace->lpVtbl->SetObjectRects(inplace, lprcPosRect, lprcPosRect);
  245. inplace->lpVtbl->Release(inplace);
  246. }
  247. return S_OK;
  248. }
  249. static HRESULT STDMETHODCALLTYPE Frame_QueryInterface(
  250. IOleInPlaceFrame FAR *This, REFIID riid, LPVOID FAR *ppvObj) {
  251. return E_NOTIMPL;
  252. }
  253. static ULONG STDMETHODCALLTYPE Frame_AddRef(IOleInPlaceFrame FAR *This) {
  254. return 1;
  255. }
  256. static ULONG STDMETHODCALLTYPE Frame_Release(IOleInPlaceFrame FAR *This) {
  257. return 1;
  258. }
  259. static HRESULT STDMETHODCALLTYPE Frame_GetWindow(IOleInPlaceFrame FAR *This,
  260. HWND FAR *lphwnd) {
  261. *lphwnd = ((_IOleInPlaceFrameEx *)This)->window;
  262. return S_OK;
  263. }
  264. static HRESULT STDMETHODCALLTYPE
  265. Frame_ContextSensitiveHelp(IOleInPlaceFrame FAR *This, BOOL fEnterMode) {
  266. return E_NOTIMPL;
  267. }
  268. static HRESULT STDMETHODCALLTYPE Frame_GetBorder(IOleInPlaceFrame FAR *This,
  269. LPRECT lprectBorder) {
  270. return E_NOTIMPL;
  271. }
  272. static HRESULT STDMETHODCALLTYPE Frame_RequestBorderSpace(
  273. IOleInPlaceFrame FAR *This, LPCBORDERWIDTHS pborderwidths) {
  274. return E_NOTIMPL;
  275. }
  276. static HRESULT STDMETHODCALLTYPE Frame_SetBorderSpace(
  277. IOleInPlaceFrame FAR *This, LPCBORDERWIDTHS pborderwidths) {
  278. return E_NOTIMPL;
  279. }
  280. static HRESULT STDMETHODCALLTYPE Frame_SetActiveObject(
  281. IOleInPlaceFrame FAR *This, IOleInPlaceActiveObject *pActiveObject,
  282. LPCOLESTR pszObjName) {
  283. return S_OK;
  284. }
  285. static HRESULT STDMETHODCALLTYPE
  286. Frame_InsertMenus(IOleInPlaceFrame FAR *This, HMENU hmenuShared,
  287. LPOLEMENUGROUPWIDTHS lpMenuWidths) {
  288. return E_NOTIMPL;
  289. }
  290. static HRESULT STDMETHODCALLTYPE Frame_SetMenu(IOleInPlaceFrame FAR *This,
  291. HMENU hmenuShared,
  292. HOLEMENU holemenu,
  293. HWND hwndActiveObject) {
  294. return S_OK;
  295. }
  296. static HRESULT STDMETHODCALLTYPE Frame_RemoveMenus(IOleInPlaceFrame FAR *This,
  297. HMENU hmenuShared) {
  298. return E_NOTIMPL;
  299. }
  300. static HRESULT STDMETHODCALLTYPE Frame_SetStatusText(IOleInPlaceFrame FAR *This,
  301. LPCOLESTR pszStatusText) {
  302. return S_OK;
  303. }
  304. static HRESULT STDMETHODCALLTYPE
  305. Frame_EnableModeless(IOleInPlaceFrame FAR *This, BOOL fEnable) {
  306. return S_OK;
  307. }
  308. static HRESULT STDMETHODCALLTYPE
  309. Frame_TranslateAccelerator(IOleInPlaceFrame FAR *This, LPMSG lpmsg, WORD wID) {
  310. return E_NOTIMPL;
  311. }
  312. static HRESULT STDMETHODCALLTYPE UI_QueryInterface(IDocHostUIHandler FAR *This,
  313. REFIID riid,
  314. LPVOID FAR *ppvObj) {
  315. return (Site_QueryInterface((IOleClientSite *)((char *)This -
  316. sizeof(IOleClientSite) -
  317. sizeof(_IOleInPlaceSiteEx)),
  318. riid, ppvObj));
  319. }
  320. static ULONG STDMETHODCALLTYPE UI_AddRef(IDocHostUIHandler FAR *This) {
  321. return 1;
  322. }
  323. static ULONG STDMETHODCALLTYPE UI_Release(IDocHostUIHandler FAR *This) {
  324. return 1;
  325. }
  326. static HRESULT STDMETHODCALLTYPE UI_ShowContextMenu(
  327. IDocHostUIHandler FAR *This, DWORD dwID, POINT __RPC_FAR *ppt,
  328. IUnknown __RPC_FAR *pcmdtReserved, IDispatch __RPC_FAR *pdispReserved) {
  329. return S_OK;
  330. }
  331. static HRESULT STDMETHODCALLTYPE
  332. UI_GetHostInfo(IDocHostUIHandler FAR *This, DOCHOSTUIINFO __RPC_FAR *pInfo) {
  333. pInfo->cbSize = sizeof(DOCHOSTUIINFO);
  334. pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER;
  335. pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT;
  336. return S_OK;
  337. }
  338. static HRESULT STDMETHODCALLTYPE UI_ShowUI(
  339. IDocHostUIHandler FAR *This, DWORD dwID,
  340. IOleInPlaceActiveObject __RPC_FAR *pActiveObject,
  341. IOleCommandTarget __RPC_FAR *pCommandTarget,
  342. IOleInPlaceFrame __RPC_FAR *pFrame, IOleInPlaceUIWindow __RPC_FAR *pDoc) {
  343. return S_OK;
  344. }
  345. static HRESULT STDMETHODCALLTYPE UI_HideUI(IDocHostUIHandler FAR *This) {
  346. return S_OK;
  347. }
  348. static HRESULT STDMETHODCALLTYPE UI_UpdateUI(IDocHostUIHandler FAR *This) {
  349. return S_OK;
  350. }
  351. static HRESULT STDMETHODCALLTYPE UI_EnableModeless(IDocHostUIHandler FAR *This,
  352. BOOL fEnable) {
  353. return S_OK;
  354. }
  355. static HRESULT STDMETHODCALLTYPE
  356. UI_OnDocWindowActivate(IDocHostUIHandler FAR *This, BOOL fActivate) {
  357. return S_OK;
  358. }
  359. static HRESULT STDMETHODCALLTYPE
  360. UI_OnFrameWindowActivate(IDocHostUIHandler FAR *This, BOOL fActivate) {
  361. return S_OK;
  362. }
  363. static HRESULT STDMETHODCALLTYPE
  364. UI_ResizeBorder(IDocHostUIHandler FAR *This, LPCRECT prcBorder,
  365. IOleInPlaceUIWindow __RPC_FAR *pUIWindow, BOOL fRameWindow) {
  366. return S_OK;
  367. }
  368. static HRESULT STDMETHODCALLTYPE
  369. UI_TranslateAccelerator(IDocHostUIHandler FAR *This, LPMSG lpMsg,
  370. const GUID __RPC_FAR *pguidCmdGroup, DWORD nCmdID) {
  371. return S_FALSE;
  372. }
  373. static HRESULT STDMETHODCALLTYPE UI_GetOptionKeyPath(
  374. IDocHostUIHandler FAR *This, LPOLESTR __RPC_FAR *pchKey, DWORD dw) {
  375. return S_FALSE;
  376. }
  377. static HRESULT STDMETHODCALLTYPE UI_GetDropTarget(
  378. IDocHostUIHandler FAR *This, IDropTarget __RPC_FAR *pDropTarget,
  379. IDropTarget __RPC_FAR *__RPC_FAR *ppDropTarget) {
  380. return S_FALSE;
  381. }
  382. static HRESULT STDMETHODCALLTYPE UI_GetExternal(
  383. IDocHostUIHandler FAR *This, IDispatch __RPC_FAR *__RPC_FAR *ppDispatch) {
  384. *ppDispatch = (IDispatch *)(This + 1);
  385. return S_OK;
  386. }
  387. static HRESULT STDMETHODCALLTYPE UI_TranslateUrl(
  388. IDocHostUIHandler FAR *This, DWORD dwTranslate, OLECHAR __RPC_FAR *pchURLIn,
  389. OLECHAR __RPC_FAR *__RPC_FAR *ppchURLOut) {
  390. *ppchURLOut = 0;
  391. return S_FALSE;
  392. }
  393. static HRESULT STDMETHODCALLTYPE
  394. UI_FilterDataObject(IDocHostUIHandler FAR *This, IDataObject __RPC_FAR *pDO,
  395. IDataObject __RPC_FAR *__RPC_FAR *ppDORet) {
  396. *ppDORet = 0;
  397. return S_FALSE;
  398. }
  399. static const TCHAR *classname = "WebView";
  400. static const SAFEARRAYBOUND ArrayBound = {1, 0};
  401. static IOleClientSiteVtbl MyIOleClientSiteTable = {
  402. Site_QueryInterface, Site_AddRef, Site_Release,
  403. Site_SaveObject, Site_GetMoniker, Site_GetContainer,
  404. Site_ShowObject, Site_OnShowWindow, Site_RequestNewObjectLayout};
  405. static IOleInPlaceSiteVtbl MyIOleInPlaceSiteTable = {
  406. InPlace_QueryInterface,
  407. InPlace_AddRef,
  408. InPlace_Release,
  409. InPlace_GetWindow,
  410. InPlace_ContextSensitiveHelp,
  411. InPlace_CanInPlaceActivate,
  412. InPlace_OnInPlaceActivate,
  413. InPlace_OnUIActivate,
  414. InPlace_GetWindowContext,
  415. InPlace_Scroll,
  416. InPlace_OnUIDeactivate,
  417. InPlace_OnInPlaceDeactivate,
  418. InPlace_DiscardUndoState,
  419. InPlace_DeactivateAndUndo,
  420. InPlace_OnPosRectChange};
  421. static IOleInPlaceFrameVtbl MyIOleInPlaceFrameTable = {
  422. Frame_QueryInterface,
  423. Frame_AddRef,
  424. Frame_Release,
  425. Frame_GetWindow,
  426. Frame_ContextSensitiveHelp,
  427. Frame_GetBorder,
  428. Frame_RequestBorderSpace,
  429. Frame_SetBorderSpace,
  430. Frame_SetActiveObject,
  431. Frame_InsertMenus,
  432. Frame_SetMenu,
  433. Frame_RemoveMenus,
  434. Frame_SetStatusText,
  435. Frame_EnableModeless,
  436. Frame_TranslateAccelerator};
  437. static IDocHostUIHandlerVtbl MyIDocHostUIHandlerTable = {
  438. UI_QueryInterface,
  439. UI_AddRef,
  440. UI_Release,
  441. UI_ShowContextMenu,
  442. UI_GetHostInfo,
  443. UI_ShowUI,
  444. UI_HideUI,
  445. UI_UpdateUI,
  446. UI_EnableModeless,
  447. UI_OnDocWindowActivate,
  448. UI_OnFrameWindowActivate,
  449. UI_ResizeBorder,
  450. UI_TranslateAccelerator,
  451. UI_GetOptionKeyPath,
  452. UI_GetDropTarget,
  453. UI_GetExternal,
  454. UI_TranslateUrl,
  455. UI_FilterDataObject};
  456. static HRESULT STDMETHODCALLTYPE IS_QueryInterface(IInternetSecurityManager FAR *This, REFIID riid, void **ppvObject) {
  457. return E_NOTIMPL;
  458. }
  459. static ULONG STDMETHODCALLTYPE IS_AddRef(IInternetSecurityManager FAR *This) { return 1; }
  460. static ULONG STDMETHODCALLTYPE IS_Release(IInternetSecurityManager FAR *This) { return 1; }
  461. static HRESULT STDMETHODCALLTYPE IS_SetSecuritySite(IInternetSecurityManager FAR *This, IInternetSecurityMgrSite *pSited) {
  462. return INET_E_DEFAULT_ACTION;
  463. }
  464. static HRESULT STDMETHODCALLTYPE IS_GetSecuritySite(IInternetSecurityManager FAR *This, IInternetSecurityMgrSite **ppSite) {
  465. return INET_E_DEFAULT_ACTION;
  466. }
  467. static HRESULT STDMETHODCALLTYPE IS_MapUrlToZone(IInternetSecurityManager FAR *This, LPCWSTR pwszUrl, DWORD *pdwZone, DWORD dwFlags) {
  468. *pdwZone = URLZONE_LOCAL_MACHINE;
  469. return S_OK;
  470. }
  471. static HRESULT STDMETHODCALLTYPE IS_GetSecurityId(IInternetSecurityManager FAR *This, LPCWSTR pwszUrl, BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved) {
  472. return INET_E_DEFAULT_ACTION;
  473. }
  474. static HRESULT STDMETHODCALLTYPE IS_ProcessUrlAction(IInternetSecurityManager FAR *This, LPCWSTR pwszUrl, DWORD dwAction, BYTE *pPolicy, DWORD cbPolicy, BYTE *pContext, DWORD cbContext, DWORD dwFlags, DWORD dwReserved) {
  475. return INET_E_DEFAULT_ACTION;
  476. }
  477. static HRESULT STDMETHODCALLTYPE IS_QueryCustomPolicy(IInternetSecurityManager FAR *This, LPCWSTR pwszUrl, REFGUID guidKey, BYTE **ppPolicy, DWORD *pcbPolicy, BYTE *pContext, DWORD cbContext, DWORD dwReserved) {
  478. return INET_E_DEFAULT_ACTION;
  479. }
  480. static HRESULT STDMETHODCALLTYPE IS_SetZoneMapping(IInternetSecurityManager FAR *This, DWORD dwZone, LPCWSTR lpszPattern, DWORD dwFlags) {
  481. return INET_E_DEFAULT_ACTION;
  482. }
  483. static HRESULT STDMETHODCALLTYPE IS_GetZoneMappings(IInternetSecurityManager FAR *This, DWORD dwZone, IEnumString **ppenumString, DWORD dwFlags) {
  484. return INET_E_DEFAULT_ACTION;
  485. }
  486. static IInternetSecurityManagerVtbl MyInternetSecurityManagerTable = {IS_QueryInterface, IS_AddRef, IS_Release, IS_SetSecuritySite, IS_GetSecuritySite, IS_MapUrlToZone, IS_GetSecurityId, IS_ProcessUrlAction, IS_QueryCustomPolicy, IS_SetZoneMapping, IS_GetZoneMappings};
  487. static HRESULT STDMETHODCALLTYPE SP_QueryInterface(IServiceProvider FAR *This, REFIID riid, void **ppvObject) {
  488. return (Site_QueryInterface(
  489. (IOleClientSite *)((char *)This - sizeof(IOleClientSite) - sizeof(_IOleInPlaceSiteEx) - sizeof(_IDocHostUIHandlerEx) - sizeof(IDispatch)), riid, ppvObject));
  490. }
  491. static ULONG STDMETHODCALLTYPE SP_AddRef(IServiceProvider FAR *This) { return 1; }
  492. static ULONG STDMETHODCALLTYPE SP_Release(IServiceProvider FAR *This) { return 1; }
  493. static HRESULT STDMETHODCALLTYPE SP_QueryService(IServiceProvider FAR *This, REFGUID siid, REFIID riid, void **ppvObject) {
  494. if (iid_eq(siid, &IID_IInternetSecurityManager) && iid_eq(riid, &IID_IInternetSecurityManager)) {
  495. *ppvObject = &((_IServiceProviderEx *)This)->mgr;
  496. } else {
  497. *ppvObject = 0;
  498. return (E_NOINTERFACE);
  499. }
  500. return S_OK;
  501. }
  502. static IServiceProviderVtbl MyServiceProviderTable = {SP_QueryInterface, SP_AddRef, SP_Release, SP_QueryService};
  503. static void UnEmbedBrowserObject(struct webview *w) {
  504. if (w->priv.browser != NULL) {
  505. (*w->priv.browser)->lpVtbl->Close(*w->priv.browser, OLECLOSE_NOSAVE);
  506. (*w->priv.browser)->lpVtbl->Release(*w->priv.browser);
  507. GlobalFree(w->priv.browser);
  508. w->priv.browser = NULL;
  509. }
  510. }
  511. static int EmbedBrowserObject(struct webview *w) {
  512. RECT rect;
  513. IWebBrowser2 *webBrowser2 = NULL;
  514. LPCLASSFACTORY pClassFactory = NULL;
  515. _IOleClientSiteEx *_iOleClientSiteEx = NULL;
  516. IOleObject **browser = (IOleObject **)GlobalAlloc(
  517. GMEM_FIXED, sizeof(IOleObject *) + sizeof(_IOleClientSiteEx));
  518. if (browser == NULL) {
  519. goto error;
  520. }
  521. w->priv.browser = browser;
  522. _iOleClientSiteEx = (_IOleClientSiteEx *)(browser + 1);
  523. _iOleClientSiteEx->client.lpVtbl = &MyIOleClientSiteTable;
  524. _iOleClientSiteEx->inplace.inplace.lpVtbl = &MyIOleInPlaceSiteTable;
  525. _iOleClientSiteEx->inplace.frame.frame.lpVtbl = &MyIOleInPlaceFrameTable;
  526. _iOleClientSiteEx->inplace.frame.window = w->priv.hwnd;
  527. _iOleClientSiteEx->ui.ui.lpVtbl = &MyIDocHostUIHandlerTable;
  528. _iOleClientSiteEx->external.lpVtbl = &ExternalDispatchTable;
  529. _iOleClientSiteEx->provider.provider.lpVtbl = &MyServiceProviderTable;
  530. _iOleClientSiteEx->provider.mgr.mgr.lpVtbl = &MyInternetSecurityManagerTable;
  531. if (CoGetClassObject(iid_unref(&CLSID_WebBrowser),
  532. CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, NULL,
  533. iid_unref(&IID_IClassFactory),
  534. (void **)&pClassFactory) != S_OK) {
  535. goto error;
  536. }
  537. if (pClassFactory == NULL) {
  538. goto error;
  539. }
  540. if (pClassFactory->lpVtbl->CreateInstance(pClassFactory, 0,
  541. iid_unref(&IID_IOleObject),
  542. (void **)browser) != S_OK) {
  543. goto error;
  544. }
  545. pClassFactory->lpVtbl->Release(pClassFactory);
  546. if ((*browser)->lpVtbl->SetClientSite(
  547. *browser, (IOleClientSite *)_iOleClientSiteEx) != S_OK) {
  548. goto error;
  549. }
  550. (*browser)->lpVtbl->SetHostNames(*browser, L"My Host Name", 0);
  551. if (OleSetContainedObject((struct IUnknown *)(*browser), TRUE) != S_OK) {
  552. goto error;
  553. }
  554. GetClientRect(w->priv.hwnd, &rect);
  555. if ((*browser)->lpVtbl->DoVerb((*browser), OLEIVERB_SHOW, NULL,
  556. (IOleClientSite *)_iOleClientSiteEx, -1,
  557. w->priv.hwnd, &rect) != S_OK) {
  558. goto error;
  559. }
  560. if ((*browser)->lpVtbl->QueryInterface((*browser),
  561. iid_unref(&IID_IWebBrowser2),
  562. (void **)&webBrowser2) != S_OK) {
  563. goto error;
  564. }
  565. webBrowser2->lpVtbl->put_Left(webBrowser2, 0);
  566. webBrowser2->lpVtbl->put_Top(webBrowser2, 0);
  567. webBrowser2->lpVtbl->put_Width(webBrowser2, rect.right);
  568. webBrowser2->lpVtbl->put_Height(webBrowser2, rect.bottom);
  569. webBrowser2->lpVtbl->Release(webBrowser2);
  570. return 0;
  571. error:
  572. UnEmbedBrowserObject(w);
  573. if (pClassFactory != NULL) {
  574. pClassFactory->lpVtbl->Release(pClassFactory);
  575. }
  576. if (browser != NULL) {
  577. GlobalFree(browser);
  578. }
  579. return -1;
  580. }
  581. #define WEBVIEW_DATA_URL_PREFIX "data:text/html,"
  582. static int DisplayHTMLPage(struct webview *w) {
  583. IWebBrowser2 *webBrowser2;
  584. VARIANT myURL;
  585. LPDISPATCH lpDispatch;
  586. IHTMLDocument2 *htmlDoc2;
  587. BSTR bstr;
  588. IOleObject *browserObject;
  589. SAFEARRAY *sfArray;
  590. VARIANT *pVar;
  591. browserObject = *w->priv.browser;
  592. int isDataURL = 0;
  593. const char *webview_url = webview_check_url(w->url);
  594. if (!browserObject->lpVtbl->QueryInterface(
  595. browserObject, iid_unref(&IID_IWebBrowser2), (void **)&webBrowser2)) {
  596. LPCSTR webPageName;
  597. isDataURL = (strncmp(webview_url, WEBVIEW_DATA_URL_PREFIX,
  598. strlen(WEBVIEW_DATA_URL_PREFIX)) == 0);
  599. if (isDataURL) {
  600. webPageName = "about:blank";
  601. } else {
  602. webPageName = (LPCSTR)webview_url;
  603. }
  604. VariantInit(&myURL);
  605. myURL.vt = VT_BSTR;
  606. #ifndef UNICODE
  607. {
  608. wchar_t *buffer = webview_to_utf16(webPageName);
  609. if (buffer == NULL) {
  610. goto badalloc;
  611. }
  612. myURL.bstrVal = SysAllocString(buffer);
  613. GlobalFree(buffer);
  614. }
  615. #else
  616. myURL.bstrVal = SysAllocString(webPageName);
  617. #endif
  618. if (!myURL.bstrVal) {
  619. badalloc:
  620. webBrowser2->lpVtbl->Release(webBrowser2);
  621. return (-6);
  622. }
  623. webBrowser2->lpVtbl->Navigate2(webBrowser2, &myURL, 0, 0, 0, 0);
  624. VariantClear(&myURL);
  625. if (!isDataURL) {
  626. return 0;
  627. }
  628. char *url = (char *)calloc(1, strlen(webview_url) + 1);
  629. char *q = url;
  630. for (const char *p = webview_url + strlen(WEBVIEW_DATA_URL_PREFIX); *q = *p;
  631. p++, q++) {
  632. if (*q == '%' && *(p + 1) && *(p + 2)) {
  633. sscanf(p + 1, "%02x", q);
  634. p = p + 2;
  635. }
  636. }
  637. if (webBrowser2->lpVtbl->get_Document(webBrowser2, &lpDispatch) == S_OK) {
  638. if (lpDispatch->lpVtbl->QueryInterface(lpDispatch,
  639. iid_unref(&IID_IHTMLDocument2),
  640. (void **)&htmlDoc2) == S_OK) {
  641. if ((sfArray = SafeArrayCreate(VT_VARIANT, 1,
  642. (SAFEARRAYBOUND *)&ArrayBound))) {
  643. if (!SafeArrayAccessData(sfArray, (void **)&pVar)) {
  644. pVar->vt = VT_BSTR;
  645. #ifndef UNICODE
  646. {
  647. wchar_t *buffer = webview_to_utf16(url);
  648. if (buffer == NULL) {
  649. goto release;
  650. }
  651. bstr = SysAllocString(buffer);
  652. GlobalFree(buffer);
  653. }
  654. #else
  655. bstr = SysAllocString(string);
  656. #endif
  657. if ((pVar->bstrVal = bstr)) {
  658. htmlDoc2->lpVtbl->write(htmlDoc2, sfArray);
  659. htmlDoc2->lpVtbl->close(htmlDoc2);
  660. }
  661. }
  662. SafeArrayDestroy(sfArray);
  663. }
  664. release:
  665. free(url);
  666. htmlDoc2->lpVtbl->Release(htmlDoc2);
  667. }
  668. lpDispatch->lpVtbl->Release(lpDispatch);
  669. }
  670. webBrowser2->lpVtbl->Release(webBrowser2);
  671. return (0);
  672. }
  673. return (-5);
  674. }
  675. static LRESULT CALLBACK wndproc(HWND hwnd, UINT uMsg, WPARAM wParam,
  676. LPARAM lParam) {
  677. struct webview *w = (struct webview *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  678. switch (uMsg) {
  679. case WM_CREATE:
  680. w = (struct webview *)((CREATESTRUCT *)lParam)->lpCreateParams;
  681. w->priv.hwnd = hwnd;
  682. return EmbedBrowserObject(w);
  683. case WM_DESTROY:
  684. UnEmbedBrowserObject(w);
  685. PostQuitMessage(0);
  686. return TRUE;
  687. case WM_SIZE: {
  688. IWebBrowser2 *webBrowser2;
  689. IOleObject *browser = *w->priv.browser;
  690. if (browser->lpVtbl->QueryInterface(browser, iid_unref(&IID_IWebBrowser2),
  691. (void **)&webBrowser2) == S_OK) {
  692. RECT rect;
  693. GetClientRect(hwnd, &rect);
  694. webBrowser2->lpVtbl->put_Width(webBrowser2, rect.right);
  695. webBrowser2->lpVtbl->put_Height(webBrowser2, rect.bottom);
  696. }
  697. return TRUE;
  698. }
  699. case WM_WEBVIEW_DISPATCH: {
  700. webview_dispatch_fn f = (webview_dispatch_fn)wParam;
  701. void *arg = (void *)lParam;
  702. (*f)(w, arg);
  703. return TRUE;
  704. }
  705. }
  706. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  707. }
  708. #define WEBVIEW_KEY_FEATURE_BROWSER_EMULATION \
  709. "Software\\Microsoft\\Internet " \
  710. "Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION"
  711. static int webview_fix_ie_compat_mode() {
  712. HKEY hKey;
  713. DWORD ie_version = 11000;
  714. TCHAR appname[MAX_PATH + 1];
  715. TCHAR *p;
  716. if (GetModuleFileName(NULL, appname, MAX_PATH + 1) == 0) {
  717. return -1;
  718. }
  719. for (p = &appname[strlen(appname) - 1]; p != appname && *p != '\\'; p--) {
  720. }
  721. p++;
  722. if (RegCreateKey(HKEY_CURRENT_USER, WEBVIEW_KEY_FEATURE_BROWSER_EMULATION,
  723. &hKey) != ERROR_SUCCESS) {
  724. return -1;
  725. }
  726. if (RegSetValueEx(hKey, p, 0, REG_DWORD, (BYTE *)&ie_version,
  727. sizeof(ie_version)) != ERROR_SUCCESS) {
  728. RegCloseKey(hKey);
  729. return -1;
  730. }
  731. RegCloseKey(hKey);
  732. return 0;
  733. }
  734. WEBVIEW_API int webview_init(struct webview *w) {
  735. WNDCLASSEX wc;
  736. HINSTANCE hInstance;
  737. DWORD style;
  738. RECT clientRect;
  739. RECT rect;
  740. if (webview_fix_ie_compat_mode() < 0) {
  741. return -1;
  742. }
  743. hInstance = GetModuleHandle(NULL);
  744. if (hInstance == NULL) {
  745. return -1;
  746. }
  747. if (OleInitialize(NULL) != S_OK) {
  748. return -1;
  749. }
  750. ZeroMemory(&wc, sizeof(WNDCLASSEX));
  751. wc.cbSize = sizeof(WNDCLASSEX);
  752. wc.hInstance = hInstance;
  753. wc.lpfnWndProc = wndproc;
  754. wc.lpszClassName = classname;
  755. RegisterClassEx(&wc);
  756. style = WS_OVERLAPPEDWINDOW;
  757. if (!w->resizable) {
  758. style = WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
  759. }
  760. rect.left = 0;
  761. rect.top = 0;
  762. rect.right = w->width;
  763. rect.bottom = w->height;
  764. AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, 0);
  765. GetClientRect(GetDesktopWindow(), &clientRect);
  766. int left = (clientRect.right / 2) - ((rect.right - rect.left) / 2);
  767. int top = (clientRect.bottom / 2) - ((rect.bottom - rect.top) / 2);
  768. rect.right = rect.right - rect.left + left;
  769. rect.left = left;
  770. rect.bottom = rect.bottom - rect.top + top;
  771. rect.top = top;
  772. w->priv.hwnd =
  773. CreateWindowEx(0, classname, w->title, style, rect.left, rect.top,
  774. rect.right - rect.left, rect.bottom - rect.top,
  775. HWND_DESKTOP, NULL, hInstance, (void *)w);
  776. if (w->priv.hwnd == 0) {
  777. OleUninitialize();
  778. return -1;
  779. }
  780. SetWindowLongPtr(w->priv.hwnd, GWLP_USERDATA, (LONG_PTR)w);
  781. DisplayHTMLPage(w);
  782. SetWindowText(w->priv.hwnd, w->title);
  783. ShowWindow(w->priv.hwnd, SW_SHOWDEFAULT);
  784. UpdateWindow(w->priv.hwnd);
  785. SetFocus(w->priv.hwnd);
  786. return 0;
  787. }
  788. WEBVIEW_API int webview_loop(struct webview *w, int blocking) {
  789. MSG msg;
  790. if (blocking) {
  791. GetMessage(&msg, 0, 0, 0);
  792. } else {
  793. PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
  794. }
  795. switch (msg.message) {
  796. case WM_QUIT:
  797. return -1;
  798. case WM_COMMAND:
  799. case WM_KEYDOWN:
  800. case WM_KEYUP: {
  801. HRESULT r = S_OK;
  802. IWebBrowser2 *webBrowser2;
  803. IOleObject *browser = *w->priv.browser;
  804. if (browser->lpVtbl->QueryInterface(browser, iid_unref(&IID_IWebBrowser2),
  805. (void **)&webBrowser2) == S_OK) {
  806. IOleInPlaceActiveObject *pIOIPAO;
  807. if (browser->lpVtbl->QueryInterface(
  808. browser, iid_unref(&IID_IOleInPlaceActiveObject),
  809. (void **)&pIOIPAO) == S_OK) {
  810. r = pIOIPAO->lpVtbl->TranslateAccelerator(pIOIPAO, &msg);
  811. pIOIPAO->lpVtbl->Release(pIOIPAO);
  812. }
  813. webBrowser2->lpVtbl->Release(webBrowser2);
  814. }
  815. if (r != S_FALSE) {
  816. break;
  817. }
  818. }
  819. default:
  820. TranslateMessage(&msg);
  821. DispatchMessage(&msg);
  822. }
  823. return 0;
  824. }
  825. WEBVIEW_API int webview_eval(struct webview *w, const char *js) {
  826. IWebBrowser2 *webBrowser2;
  827. IHTMLDocument2 *htmlDoc2;
  828. IDispatch *docDispatch;
  829. IDispatch *scriptDispatch;
  830. if ((*w->priv.browser)
  831. ->lpVtbl->QueryInterface((*w->priv.browser),
  832. iid_unref(&IID_IWebBrowser2),
  833. (void **)&webBrowser2) != S_OK) {
  834. return -1;
  835. }
  836. if (webBrowser2->lpVtbl->get_Document(webBrowser2, &docDispatch) != S_OK) {
  837. return -1;
  838. }
  839. if (docDispatch->lpVtbl->QueryInterface(docDispatch,
  840. iid_unref(&IID_IHTMLDocument2),
  841. (void **)&htmlDoc2) != S_OK) {
  842. return -1;
  843. }
  844. if (htmlDoc2->lpVtbl->get_Script(htmlDoc2, &scriptDispatch) != S_OK) {
  845. return -1;
  846. }
  847. DISPID dispid;
  848. BSTR evalStr = SysAllocString(L"eval");
  849. if (scriptDispatch->lpVtbl->GetIDsOfNames(
  850. scriptDispatch, iid_unref(&IID_NULL), &evalStr, 1,
  851. LOCALE_SYSTEM_DEFAULT, &dispid) != S_OK) {
  852. SysFreeString(evalStr);
  853. return -1;
  854. }
  855. SysFreeString(evalStr);
  856. DISPPARAMS params;
  857. VARIANT arg;
  858. VARIANT result;
  859. EXCEPINFO excepInfo;
  860. UINT nArgErr = (UINT)-1;
  861. params.cArgs = 1;
  862. params.cNamedArgs = 0;
  863. params.rgvarg = &arg;
  864. arg.vt = VT_BSTR;
  865. static const char *prologue = "(function(){";
  866. static const char *epilogue = ";})();";
  867. int n = strlen(prologue) + strlen(epilogue) + strlen(js) + 1;
  868. char *eval = (char *)malloc(n);
  869. snprintf(eval, n, "%s%s%s", prologue, js, epilogue);
  870. wchar_t *buf = webview_to_utf16(eval);
  871. if (buf == NULL) {
  872. return -1;
  873. }
  874. arg.bstrVal = SysAllocString(buf);
  875. if (scriptDispatch->lpVtbl->Invoke(
  876. scriptDispatch, dispid, iid_unref(&IID_NULL), 0, DISPATCH_METHOD,
  877. &params, &result, &excepInfo, &nArgErr) != S_OK) {
  878. return -1;
  879. }
  880. SysFreeString(arg.bstrVal);
  881. free(eval);
  882. scriptDispatch->lpVtbl->Release(scriptDispatch);
  883. htmlDoc2->lpVtbl->Release(htmlDoc2);
  884. docDispatch->lpVtbl->Release(docDispatch);
  885. return 0;
  886. }
  887. WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
  888. void *arg) {
  889. PostMessageW(w->priv.hwnd, WM_WEBVIEW_DISPATCH, (WPARAM)fn, (LPARAM)arg);
  890. }
  891. WEBVIEW_API void webview_set_title(struct webview *w, const char *title) {
  892. SetWindowText(w->priv.hwnd, title);
  893. }
  894. WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) {
  895. if (w->priv.is_fullscreen == !!fullscreen) {
  896. return;
  897. }
  898. if (w->priv.is_fullscreen == 0) {
  899. w->priv.saved_style = GetWindowLong(w->priv.hwnd, GWL_STYLE);
  900. w->priv.saved_ex_style = GetWindowLong(w->priv.hwnd, GWL_EXSTYLE);
  901. GetWindowRect(w->priv.hwnd, &w->priv.saved_rect);
  902. }
  903. w->priv.is_fullscreen = !!fullscreen;
  904. if (fullscreen) {
  905. MONITORINFO monitor_info;
  906. SetWindowLong(w->priv.hwnd, GWL_STYLE,
  907. w->priv.saved_style & ~(WS_CAPTION | WS_THICKFRAME));
  908. SetWindowLong(w->priv.hwnd, GWL_EXSTYLE,
  909. w->priv.saved_ex_style &
  910. ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
  911. WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
  912. monitor_info.cbSize = sizeof(monitor_info);
  913. GetMonitorInfo(MonitorFromWindow(w->priv.hwnd, MONITOR_DEFAULTTONEAREST),
  914. &monitor_info);
  915. RECT r;
  916. r.left = monitor_info.rcMonitor.left;
  917. r.top = monitor_info.rcMonitor.top;
  918. r.right = monitor_info.rcMonitor.right;
  919. r.bottom = monitor_info.rcMonitor.bottom;
  920. SetWindowPos(w->priv.hwnd, NULL, r.left, r.top, r.right - r.left,
  921. r.bottom - r.top,
  922. SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
  923. } else {
  924. SetWindowLong(w->priv.hwnd, GWL_STYLE, w->priv.saved_style);
  925. SetWindowLong(w->priv.hwnd, GWL_EXSTYLE, w->priv.saved_ex_style);
  926. SetWindowPos(w->priv.hwnd, NULL, w->priv.saved_rect.left,
  927. w->priv.saved_rect.top,
  928. w->priv.saved_rect.right - w->priv.saved_rect.left,
  929. w->priv.saved_rect.bottom - w->priv.saved_rect.top,
  930. SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
  931. }
  932. }
  933. WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
  934. uint8_t b, uint8_t a) {
  935. HBRUSH brush = CreateSolidBrush(RGB(r, g, b));
  936. SetClassLongPtr(w->priv.hwnd, GCLP_HBRBACKGROUND, (LONG_PTR)brush);
  937. }
  938. /* These are missing parts from MinGW */
  939. #ifndef __IFileDialog_INTERFACE_DEFINED__
  940. #define __IFileDialog_INTERFACE_DEFINED__
  941. enum _FILEOPENDIALOGOPTIONS {
  942. FOS_OVERWRITEPROMPT = 0x2,
  943. FOS_STRICTFILETYPES = 0x4,
  944. FOS_NOCHANGEDIR = 0x8,
  945. FOS_PICKFOLDERS = 0x20,
  946. FOS_FORCEFILESYSTEM = 0x40,
  947. FOS_ALLNONSTORAGEITEMS = 0x80,
  948. FOS_NOVALIDATE = 0x100,
  949. FOS_ALLOWMULTISELECT = 0x200,
  950. FOS_PATHMUSTEXIST = 0x800,
  951. FOS_FILEMUSTEXIST = 0x1000,
  952. FOS_CREATEPROMPT = 0x2000,
  953. FOS_SHAREAWARE = 0x4000,
  954. FOS_NOREADONLYRETURN = 0x8000,
  955. FOS_NOTESTFILECREATE = 0x10000,
  956. FOS_HIDEMRUPLACES = 0x20000,
  957. FOS_HIDEPINNEDPLACES = 0x40000,
  958. FOS_NODEREFERENCELINKS = 0x100000,
  959. FOS_DONTADDTORECENT = 0x2000000,
  960. FOS_FORCESHOWHIDDEN = 0x10000000,
  961. FOS_DEFAULTNOMINIMODE = 0x20000000,
  962. FOS_FORCEPREVIEWPANEON = 0x40000000
  963. };
  964. typedef DWORD FILEOPENDIALOGOPTIONS;
  965. typedef enum FDAP { FDAP_BOTTOM = 0, FDAP_TOP = 1 } FDAP;
  966. DEFINE_GUID(IID_IFileDialog, 0x42f85136, 0xdb7e, 0x439c, 0x85, 0xf1, 0xe4, 0x07,
  967. 0x5d, 0x13, 0x5f, 0xc8);
  968. typedef struct IFileDialogVtbl {
  969. BEGIN_INTERFACE
  970. HRESULT(STDMETHODCALLTYPE *QueryInterface)
  971. (IFileDialog *This, REFIID riid, void **ppvObject);
  972. ULONG(STDMETHODCALLTYPE *AddRef)(IFileDialog *This);
  973. ULONG(STDMETHODCALLTYPE *Release)(IFileDialog *This);
  974. HRESULT(STDMETHODCALLTYPE *Show)(IFileDialog *This, HWND hwndOwner);
  975. HRESULT(STDMETHODCALLTYPE *SetFileTypes)
  976. (IFileDialog *This, UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec);
  977. HRESULT(STDMETHODCALLTYPE *SetFileTypeIndex)
  978. (IFileDialog *This, UINT iFileType);
  979. HRESULT(STDMETHODCALLTYPE *GetFileTypeIndex)
  980. (IFileDialog *This, UINT *piFileType);
  981. HRESULT(STDMETHODCALLTYPE *Advise)
  982. (IFileDialog *This, IFileDialogEvents *pfde, DWORD *pdwCookie);
  983. HRESULT(STDMETHODCALLTYPE *Unadvise)(IFileDialog *This, DWORD dwCookie);
  984. HRESULT(STDMETHODCALLTYPE *SetOptions)
  985. (IFileDialog *This, FILEOPENDIALOGOPTIONS fos);
  986. HRESULT(STDMETHODCALLTYPE *GetOptions)
  987. (IFileDialog *This, FILEOPENDIALOGOPTIONS *pfos);
  988. HRESULT(STDMETHODCALLTYPE *SetDefaultFolder)
  989. (IFileDialog *This, IShellItem *psi);
  990. HRESULT(STDMETHODCALLTYPE *SetFolder)(IFileDialog *This, IShellItem *psi);
  991. HRESULT(STDMETHODCALLTYPE *GetFolder)(IFileDialog *This, IShellItem **ppsi);
  992. HRESULT(STDMETHODCALLTYPE *GetCurrentSelection)
  993. (IFileDialog *This, IShellItem **ppsi);
  994. HRESULT(STDMETHODCALLTYPE *SetFileName)(IFileDialog *This, LPCWSTR pszName);
  995. HRESULT(STDMETHODCALLTYPE *GetFileName)(IFileDialog *This, LPWSTR *pszName);
  996. HRESULT(STDMETHODCALLTYPE *SetTitle)(IFileDialog *This, LPCWSTR pszTitle);
  997. HRESULT(STDMETHODCALLTYPE *SetOkButtonLabel)
  998. (IFileDialog *This, LPCWSTR pszText);
  999. HRESULT(STDMETHODCALLTYPE *SetFileNameLabel)
  1000. (IFileDialog *This, LPCWSTR pszLabel);
  1001. HRESULT(STDMETHODCALLTYPE *GetResult)(IFileDialog *This, IShellItem **ppsi);
  1002. HRESULT(STDMETHODCALLTYPE *AddPlace)
  1003. (IFileDialog *This, IShellItem *psi, FDAP fdap);
  1004. HRESULT(STDMETHODCALLTYPE *SetDefaultExtension)
  1005. (IFileDialog *This, LPCWSTR pszDefaultExtension);
  1006. HRESULT(STDMETHODCALLTYPE *Close)(IFileDialog *This, HRESULT hr);
  1007. HRESULT(STDMETHODCALLTYPE *SetClientGuid)(IFileDialog *This, REFGUID guid);
  1008. HRESULT(STDMETHODCALLTYPE *ClearClientData)(IFileDialog *This);
  1009. HRESULT(STDMETHODCALLTYPE *SetFilter)
  1010. (IFileDialog *This, IShellItemFilter *pFilter);
  1011. END_INTERFACE
  1012. } IFileDialogVtbl;
  1013. interface IFileDialog {
  1014. CONST_VTBL IFileDialogVtbl *lpVtbl;
  1015. };
  1016. DEFINE_GUID(IID_IFileOpenDialog, 0xd57c7288, 0xd4ad, 0x4768, 0xbe, 0x02, 0x9d,
  1017. 0x96, 0x95, 0x32, 0xd9, 0x60);
  1018. DEFINE_GUID(IID_IFileSaveDialog, 0x84bccd23, 0x5fde, 0x4cdb, 0xae, 0xa4, 0xaf,
  1019. 0x64, 0xb8, 0x3d, 0x78, 0xab);
  1020. #endif
  1021. WEBVIEW_API void webview_dialog(struct webview *w,
  1022. enum webview_dialog_type dlgtype, int flags,
  1023. const char *title, const char *arg,
  1024. char *result, size_t resultsz) {
  1025. if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
  1026. dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) {
  1027. IFileDialog *dlg = NULL;
  1028. IShellItem *res = NULL;
  1029. WCHAR *ws = NULL;
  1030. char *s = NULL;
  1031. FILEOPENDIALOGOPTIONS opts = 0, add_opts = 0;
  1032. if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN) {
  1033. if (CoCreateInstance(
  1034. iid_unref(&CLSID_FileOpenDialog), NULL, CLSCTX_INPROC_SERVER,
  1035. iid_unref(&IID_IFileOpenDialog), (void **)&dlg) != S_OK) {
  1036. goto error_dlg;
  1037. }
  1038. if (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY) {
  1039. add_opts |= FOS_PICKFOLDERS;
  1040. }
  1041. add_opts |= FOS_NOCHANGEDIR | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE |
  1042. FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_SHAREAWARE |
  1043. FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS |
  1044. FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE;
  1045. } else {
  1046. if (CoCreateInstance(
  1047. iid_unref(&CLSID_FileSaveDialog), NULL, CLSCTX_INPROC_SERVER,
  1048. iid_unref(&IID_IFileSaveDialog), (void **)&dlg) != S_OK) {
  1049. goto error_dlg;
  1050. }
  1051. add_opts |= FOS_OVERWRITEPROMPT | FOS_NOCHANGEDIR |
  1052. FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_SHAREAWARE |
  1053. FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS |
  1054. FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE;
  1055. }
  1056. if (dlg->lpVtbl->GetOptions(dlg, &opts) != S_OK) {
  1057. goto error_dlg;
  1058. }
  1059. opts &= ~FOS_NOREADONLYRETURN;
  1060. opts |= add_opts;
  1061. if (dlg->lpVtbl->SetOptions(dlg, opts) != S_OK) {
  1062. goto error_dlg;
  1063. }
  1064. if (dlg->lpVtbl->Show(dlg, w->priv.hwnd) != S_OK) {
  1065. goto error_dlg;
  1066. }
  1067. if (dlg->lpVtbl->GetResult(dlg, &res) != S_OK) {
  1068. goto error_dlg;
  1069. }
  1070. if (res->lpVtbl->GetDisplayName(res, SIGDN_FILESYSPATH, &ws) != S_OK) {
  1071. goto error_result;
  1072. }
  1073. s = webview_from_utf16(ws);
  1074. strncpy(result, s, resultsz);
  1075. result[resultsz - 1] = '\0';
  1076. CoTaskMemFree(ws);
  1077. error_result:
  1078. res->lpVtbl->Release(res);
  1079. error_dlg:
  1080. dlg->lpVtbl->Release(dlg);
  1081. return;
  1082. } else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) {
  1083. #if 0
  1084. /* MinGW often doesn't contain TaskDialog, we'll use MessageBox for now */
  1085. WCHAR *wtitle = webview_to_utf16(title);
  1086. WCHAR *warg = webview_to_utf16(arg);
  1087. TaskDialog(w->priv.hwnd, NULL, NULL, wtitle, warg, 0, NULL, NULL);
  1088. GlobalFree(warg);
  1089. GlobalFree(wtitle);
  1090. #else
  1091. UINT type = MB_OK;
  1092. switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) {
  1093. case WEBVIEW_DIALOG_FLAG_INFO:
  1094. type |= MB_ICONINFORMATION;
  1095. break;
  1096. case WEBVIEW_DIALOG_FLAG_WARNING:
  1097. type |= MB_ICONWARNING;
  1098. break;
  1099. case WEBVIEW_DIALOG_FLAG_ERROR:
  1100. type |= MB_ICONERROR;
  1101. break;
  1102. }
  1103. MessageBox(w->priv.hwnd, arg, title, type);
  1104. #endif
  1105. }
  1106. }
  1107. WEBVIEW_API void webview_terminate(struct webview *w) { PostQuitMessage(0); }
  1108. WEBVIEW_API void webview_exit(struct webview *w) {
  1109. DestroyWindow(w->priv.hwnd);
  1110. OleUninitialize();
  1111. }
  1112. WEBVIEW_API void webview_print_log(const char *s) { OutputDebugString(s); }