IEWebGameCtrl.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "stdafx.h"
  23. #include "IEWebGameCtrl.h"
  24. #include "../common/webCommon.h"
  25. // CIEWebGameCtrl (one and only one instance please)
  26. CIEWebGameCtrl* CIEWebGameCtrl::sInstance = NULL;
  27. // Javascript accessible methods
  28. // plugin.getVariable("$MyVariable"); - get a Torque 3D console variable
  29. STDMETHODIMP CIEWebGameCtrl::getVariable(BSTR name, BSTR* value)
  30. {
  31. std::wstring wstr;
  32. std::string sstr;
  33. const char* astr;
  34. wstr.assign(name);
  35. sstr = WebCommon::WStringToString(wstr);
  36. astr = sstr.c_str();
  37. const char* avalue = NULL;
  38. char vinfo[256];
  39. vinfo[0] = 0;
  40. // requesting the version information
  41. if (!_stricmp(astr, "$version"))
  42. {
  43. char plugin[4096];
  44. GetModuleFileNameA(WebCommon::gPluginModule, plugin, 4096);
  45. DWORD dwHandle = 0;
  46. DWORD dwSize = GetFileVersionInfoSizeA(plugin, &dwHandle);
  47. if (dwSize >= 0)
  48. {
  49. LPBYTE lpInfo = new BYTE[dwSize];
  50. ZeroMemory(lpInfo, dwSize);
  51. if(GetFileVersionInfoA(plugin, 0, dwSize, lpInfo))
  52. {
  53. UINT valLen = MAX_PATH;
  54. LPVOID valPtr = NULL;
  55. if(::VerQueryValue(lpInfo,
  56. TEXT("\\"),
  57. &valPtr,
  58. &valLen))
  59. {
  60. VS_FIXEDFILEINFO* pFinfo = (VS_FIXEDFILEINFO*)valPtr;
  61. sprintf(vinfo, "%i.%i", (pFinfo->dwProductVersionMS >> 16) & 0xFF, (pFinfo->dwFileVersionMS) & 0xFF);
  62. }
  63. }
  64. delete[] lpInfo;
  65. }
  66. if (!vinfo[0])
  67. strcpy(vinfo, "-1");
  68. avalue = vinfo;
  69. }
  70. else
  71. avalue = WebCommon::GetVariable(astr);
  72. sstr = avalue;
  73. wstr = WebCommon::StringToWString(sstr);
  74. *value = SysAllocString(wstr.c_str());
  75. return S_OK;
  76. }
  77. // plugin.setVariable("$MyVariable", 42); - set a Torque 3D console variable
  78. STDMETHODIMP CIEWebGameCtrl::setVariable(BSTR name, BSTR value)
  79. {
  80. std::wstring wstr;
  81. std::string nstr, vstr;
  82. const char* vname;
  83. const char* vvalue;
  84. wstr.assign(name);
  85. nstr = WebCommon::WStringToString(wstr);
  86. vname = nstr.c_str();
  87. wstr.assign(value);
  88. vstr = WebCommon::WStringToString(wstr);
  89. vvalue = vstr.c_str();
  90. WebCommon::SetVariable(vname, vvalue);
  91. return S_OK;
  92. }
  93. // plugin.startup(); - called once web page is fully loaded and plugin (including Torque 3D) is initialized
  94. STDMETHODIMP CIEWebGameCtrl::startup()
  95. {
  96. mInitialized = true;
  97. std::vector<JavasScriptExport>::iterator i;
  98. for (i = mJavaScriptExports.begin(); i != mJavaScriptExports.end();i++)
  99. {
  100. internalExportFunction(*i);
  101. }
  102. WebCommon::AddSecureFunctions();
  103. return S_OK;
  104. }
  105. // var result = plugin.callScript("mySecureFunction('one', 'two', 'three');"); - call a TorqueScript function marked as secure in webConfig.h with supplied arguments
  106. // includes function parser
  107. STDMETHODIMP CIEWebGameCtrl::callScript(BSTR code, BSTR* value)
  108. {
  109. std::wstring wcode;
  110. std::string scode;
  111. wcode.assign(code);
  112. scode = WebCommon::WStringToString(wcode);
  113. const char* sig = scode.c_str();
  114. // do not allow large strings which could be used maliciously
  115. if (scode.length() > 255 || !mInitialized)
  116. {
  117. *value = SysAllocString(L"");
  118. return E_INVALIDARG;
  119. }
  120. // data buffers for laying out data in a Torque 3D console friendly manner
  121. char nameSpace[256];
  122. char fname[256];
  123. char argv[256][256];
  124. char* argvv[256];
  125. int argc = 0;
  126. unsigned int argBegin = 0;
  127. memset(nameSpace, 0, 256);
  128. memset(fname, 0, 256);
  129. memset(argv, 0, 256 * 256);
  130. for (unsigned int i = 0; i < scode.length(); i++)
  131. {
  132. if (sig[i] == ')' || sig[i] == ';')
  133. {
  134. //scan out last arg is any
  135. char dummy[256];
  136. memset(dummy, 0, 256);
  137. WebCommon::StringCopy(dummy, &sig[argBegin], i - argBegin);
  138. if (strlen(dummy))
  139. {
  140. strcpy_s(argv[argc], dummy);
  141. argvv[argc] = argv[argc];
  142. argc++;
  143. }
  144. break; // done
  145. }
  146. // namespace
  147. if (sig[i]==':')
  148. {
  149. if (nameSpace[0] || fname[0])
  150. {
  151. *value = SysAllocString(L"");
  152. return E_INVALIDARG;
  153. }
  154. if (i > 0 && sig[i-1] == ':')
  155. {
  156. if (i - 2 > 0)
  157. WebCommon::StringCopy(nameSpace, sig, i - 1);
  158. }
  159. continue;
  160. }
  161. // args begin
  162. if (sig[i] == '(' )
  163. {
  164. if (fname[0] || i < 1)
  165. {
  166. *value = SysAllocString(L"");
  167. return E_INVALIDARG;
  168. }
  169. //everything before this is function name, minus nameSpace
  170. if (nameSpace[0])
  171. {
  172. int nlen = strlen(nameSpace);
  173. WebCommon::StringCopy(fname, &sig[nlen + 2], i - nlen - 2);
  174. }
  175. else
  176. {
  177. WebCommon::StringCopy(fname, sig, i);
  178. }
  179. WebCommon::StringCopy(argv[0], fname, strlen(fname)+1);
  180. argvv[0] = argv[0];
  181. argc++;
  182. argBegin = i + 1;
  183. }
  184. // args
  185. if (sig[i] == ',' )
  186. {
  187. if (argBegin >= i || argc == 255)
  188. {
  189. *value = SysAllocString(L"");
  190. return E_INVALIDARG;
  191. }
  192. WebCommon::StringCopy(argv[argc], &sig[argBegin], i - argBegin);
  193. argvv[argc] = argv[argc];
  194. argc++;
  195. argBegin = i + 1;
  196. }
  197. }
  198. const char* retVal;
  199. std::string sretVal;
  200. std::wstring wretVal;
  201. if (fname[0])
  202. {
  203. // call into the Torque 3D shared library (console system) and get return value
  204. retVal = torque_callsecurefunction(nameSpace, fname, argc, (const char **) argvv);
  205. sretVal= retVal;
  206. wretVal = WebCommon::StringToWString(sretVal);
  207. *value = SysAllocString(wretVal.c_str());
  208. }
  209. else
  210. {
  211. *value = SysAllocString(L"");
  212. return E_INVALIDARG;
  213. }
  214. return S_OK;
  215. }
  216. // the sole entry point for Torque 3D console system into our browser plugin (handed over as a function pointer)
  217. static const char * MyStringCallback(void *obj, int argc, const char* argv[])
  218. {
  219. static char ret[4096];
  220. strcpy_s(ret,CIEWebGameCtrl::sInstance->callFunction(argv[0], argc, argv));
  221. return ret;
  222. }
  223. // Get the location we're loading the plugin from (http://, file://) including address
  224. // this is used by the domain locking feature to ensure that your plugin is only
  225. // being used from your web site
  226. bool CIEWebGameCtrl::checkDomain()
  227. {
  228. HRESULT hrResult = S_FALSE;
  229. IMoniker* pMoniker = NULL;
  230. LPOLESTR sDisplayName;
  231. hrResult = m_spClientSite->GetMoniker(OLEGETMONIKER_TEMPFORUSER,
  232. OLEWHICHMK_CONTAINER,
  233. &pMoniker);
  234. if(SUCCEEDED(hrResult))
  235. {
  236. hrResult = pMoniker->GetDisplayName(NULL,
  237. NULL,
  238. &sDisplayName);
  239. pMoniker->Release();
  240. std::wstring wstr;
  241. std::string sstr;
  242. wstr.assign(sDisplayName);
  243. sstr = WebCommon::WStringToString(wstr);
  244. return WebCommon::CheckDomain(sstr.c_str());
  245. }
  246. return false;
  247. }
  248. // handles TorqueScript -> Javascript calling including return value
  249. const char* CIEWebGameCtrl::callFunction(const char* name, LONG numArguments, const char* argv[])
  250. {
  251. //sanity
  252. if (numArguments > 200)
  253. return "";
  254. // A bunch of COM'esque stuff to which ultimately boils down to finding a Javascript function on the page
  255. HRESULT hr;
  256. LPOLECONTAINER pContainer;
  257. IHTMLDocument* pHTML = NULL;
  258. CComPtr<IDispatch> pScript;
  259. CComQIPtr<IHTMLWindow2> pWin;
  260. if (!m_spClientSite)
  261. return "";
  262. hr = m_spClientSite->GetContainer(&pContainer);
  263. if (FAILED(hr))
  264. {
  265. return "";
  266. }
  267. hr = pContainer->QueryInterface(IID_IHTMLDocument, (void
  268. **)&pHTML);
  269. if (FAILED(hr))
  270. {
  271. pContainer->Release();
  272. return "";
  273. }
  274. hr = pHTML->get_Script(&pScript);
  275. if (FAILED(hr))
  276. {
  277. pContainer->Release();
  278. pHTML->Release();
  279. return "";
  280. }
  281. DISPID idMethod = 0;
  282. std::string smethod = name;
  283. std::wstring wmethod = WebCommon::StringToWString(smethod);
  284. OLECHAR FAR* sMethod = (OLECHAR FAR*)wmethod.c_str();
  285. hr = pScript->GetIDsOfNames(IID_NULL, &sMethod, 1, LOCALE_SYSTEM_DEFAULT,&idMethod);
  286. if (FAILED(hr))
  287. {
  288. pContainer->Release();
  289. pHTML->Release();
  290. return "";
  291. }
  292. // setup arguments and return value variants
  293. VARIANT pVarRet = {0};
  294. VariantInit(&pVarRet);
  295. if (numArguments <= 1)
  296. {
  297. DISPPARAMS dpNoArgs = {NULL, NULL, 0, 0};
  298. hr = pScript->Invoke(idMethod, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD,
  299. &dpNoArgs, &pVarRet, NULL, NULL);
  300. }
  301. else
  302. {
  303. DISPPARAMS params;
  304. VARIANTARG args[256];
  305. std::wstring wargs[256];
  306. for (LONG i = 0; i < numArguments - 1; i++ )
  307. {
  308. VariantInit(&args[i]);
  309. // Invoke wants these in reverse order
  310. std::string s = argv[numArguments - i - 1];
  311. wargs[i] = WebCommon::StringToWString(s);
  312. args[i].vt = VT_BSTR;
  313. args[i].bstrVal = SysAllocString(wargs[i].c_str());
  314. }
  315. params.cArgs = numArguments - 1;
  316. params.rgdispidNamedArgs = NULL;
  317. params.cNamedArgs = 0;
  318. params.rgvarg = args;
  319. // whew, actually call the Javascript
  320. hr = pScript->Invoke(idMethod, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD,
  321. &params, &pVarRet, NULL, NULL);
  322. for (LONG i = 0; i < numArguments - 1; i++ )
  323. {
  324. SysFreeString(args[i].bstrVal);
  325. }
  326. }
  327. if (FAILED(hr))
  328. {
  329. pContainer->Release();
  330. pHTML->Release();
  331. return "";
  332. }
  333. VariantChangeType(&pVarRet, &pVarRet, 0, VT_BSTR);
  334. std::wstring wstr;
  335. std::string sstr;
  336. static char ret[4096];
  337. wstr.assign(pVarRet.bstrVal);
  338. sstr = WebCommon::WStringToString(wstr);
  339. strcpy_s(ret, sstr.c_str());
  340. pContainer->Release();
  341. pHTML->Release();
  342. return ret;
  343. }
  344. // handle the actual export (once we're actually all ready to go)
  345. void CIEWebGameCtrl::internalExportFunction(const JavasScriptExport& jsexport)
  346. {
  347. torque_exportstringcallback(MyStringCallback,"JS",jsexport.jsCallback.c_str(),"",jsexport.numArguments,jsexport.numArguments);
  348. }
  349. // plugin.exportFunction("MyJavascriptFunction",3); - export a Javascript function to the Torque 3D console system via its name and argument count
  350. // If we haven't initialized Torque 3D yet, cache it
  351. STDMETHODIMP CIEWebGameCtrl::exportFunction(BSTR callback, LONG numArguments)
  352. {
  353. JavasScriptExport jsexport;
  354. std::wstring wstr;
  355. wstr.assign(callback);
  356. jsexport.jsCallback = WebCommon::WStringToString(wstr);
  357. jsexport.numArguments = numArguments;
  358. if (!mInitialized)
  359. {
  360. //queue it up
  361. mJavaScriptExports.push_back(jsexport);
  362. }
  363. else
  364. {
  365. internalExportFunction(jsexport);
  366. }
  367. return S_OK;
  368. }
  369. // Our web deployment is installer based, no code signing necessary
  370. STDMETHODIMP CIEWebGameCtrl::GetInterfaceSafetyOptions(REFIID riid,
  371. DWORD *pdwSupportedOptions,DWORD *pdwEnabledOptions)
  372. {
  373. return S_OK;
  374. }
  375. STDMETHODIMP CIEWebGameCtrl::SetInterfaceSafetyOptions(REFIID riid,
  376. DWORD dwOptionSetMask,DWORD dwEnabledOptions)
  377. {
  378. return S_OK;
  379. }