PPInstance.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. // Filename: PPInstance.cpp
  2. // Created by: atrestman (14Sept09)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) Carnegie Mellon University. All rights reserved.
  8. //
  9. // All use of this software is subject to the terms of the revised BSD
  10. // license. You should have received a copy of this license along
  11. // with this source code in a file named "LICENSE."
  12. //
  13. ////////////////////////////////////////////////////////////////////
  14. #include "stdafx.h"
  15. #include <string>
  16. #include <sstream>
  17. #include <iostream>
  18. #include <fstream>
  19. #include <algorithm>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <errno.h>
  24. #include <windows.h>
  25. #include <process.h>
  26. #include "resource.h"
  27. #include "PPInstance.h"
  28. #include "P3DActiveXCtrl.h"
  29. #include "PPBrowserObject.h"
  30. #include "PPDownloadRequest.h"
  31. #include "p3d_plugin_config.h"
  32. #include "get_tinyxml.h"
  33. #include "load_plugin.h"
  34. #include "find_root_dir.h"
  35. #include "mkdir_complete.h"
  36. // We can include this header file to get the DTOOL_PLATFORM
  37. // definition, even though we don't link with dtool.
  38. #include "dtool_platform.h"
  39. #include "pandaVersion.h"
  40. #define P3D_CONTENTS_FILENAME "contents.xml"
  41. #define P3D_DEFAULT_PLUGIN_FILENAME "p3d_plugin.dll"
  42. static int s_instanceCount = 0;
  43. void P3D_NofificationSync(P3D_instance *instance)
  44. {
  45. static bool handleRequestOnUIThread = true;
  46. if ( instance )
  47. {
  48. CP3DActiveXCtrl* parent = static_cast<CP3DActiveXCtrl*>(instance->_user_data);
  49. if ( parent )
  50. {
  51. if ( ::IsWindow( parent->m_hWnd ) )
  52. {
  53. ::PostMessage( parent->m_hWnd, WM_PANDA_NOTIFICATION, 0, 0 );
  54. }
  55. else
  56. {
  57. nout << "Can handle P3D_Notification on UI thread. Controls window is invalid\n";
  58. }
  59. }
  60. else
  61. {
  62. nout << "Can handle P3D_Notification on UI thread. Instance's user data is not a Control\n";
  63. }
  64. }
  65. }
  66. PPInstance::PPInstance( CP3DActiveXCtrl& parentCtrl ) :
  67. m_parentCtrl( parentCtrl ), m_p3dInstance( NULL ), m_p3dObject( NULL ), m_handleRequestOnUIThread( true ), m_isInit( false )
  68. {
  69. // We need the root dir first.
  70. m_rootDir = find_root_dir( );
  71. // Then open the logfile.
  72. m_logger.Open( m_rootDir );
  73. m_pluginLoaded = false;
  74. _failed = false;
  75. }
  76. PPInstance::~PPInstance( )
  77. {
  78. if ( m_p3dInstance )
  79. {
  80. P3D_instance_finish( m_p3dInstance );
  81. m_p3dInstance = NULL;
  82. }
  83. if ( m_p3dObject )
  84. {
  85. P3D_OBJECT_DECREF( m_p3dObject );
  86. m_p3dObject = NULL;
  87. }
  88. if ( m_pluginLoaded )
  89. {
  90. UnloadPlugin();
  91. }
  92. }
  93. int PPInstance::DownloadFile( const std::string& from, const std::string& to )
  94. {
  95. int error( 0 );
  96. PPDownloadRequest p3dFileDownloadRequest( *this, to );
  97. PPDownloadCallback dcForFile( p3dFileDownloadRequest );
  98. nout << "Downloading " << from << " into " << to << "\n";
  99. HRESULT hr = ::URLOpenStream( m_parentCtrl.GetControllingUnknown(), from.c_str(), 0, &dcForFile );
  100. if ( FAILED( hr ) )
  101. {
  102. error = 1;
  103. nout << "Error downloading " << from << " :" << hr << "\n";
  104. }
  105. return error;
  106. }
  107. int PPInstance::CopyFile( const std::string& from, const std::string& to )
  108. {
  109. ifstream in(from.c_str(), ios::in | ios::binary);
  110. ofstream out(to.c_str(), ios::out | ios::binary);
  111. static const size_t buffer_size = 4096;
  112. char buffer[buffer_size];
  113. in.read(buffer, buffer_size);
  114. size_t count = in.gcount();
  115. while (count != 0) {
  116. out.write(buffer, count);
  117. if (out.fail()) {
  118. return 1;
  119. }
  120. in.read(buffer, buffer_size);
  121. count = in.gcount();
  122. }
  123. if (!in.eof()) {
  124. return 1;
  125. }
  126. return 0;
  127. }
  128. ////////////////////////////////////////////////////////////////////
  129. // Function: PPInstance::read_contents_file
  130. // Access: Private
  131. // Description: Reads the contents.xml file and starts the core API
  132. // DLL downloading, if necessary.
  133. ////////////////////////////////////////////////////////////////////
  134. bool PPInstance::
  135. read_contents_file(const string &contents_filename) {
  136. TiXmlDocument doc(contents_filename.c_str());
  137. if (!doc.LoadFile()) {
  138. return false;
  139. }
  140. TiXmlElement *xcontents = doc.FirstChildElement("contents");
  141. if (xcontents != NULL) {
  142. // Look for the <host> entry; it might point us at a different
  143. // download URL, and it might mention some mirrors.
  144. find_host(xcontents);
  145. // Now look for the core API package.
  146. TiXmlElement *xpackage = xcontents->FirstChildElement("package");
  147. while (xpackage != NULL) {
  148. const char *name = xpackage->Attribute("name");
  149. if (name != NULL && strcmp(name, "coreapi") == 0) {
  150. const char *platform = xpackage->Attribute("platform");
  151. if (platform != NULL && strcmp(platform, DTOOL_PLATFORM) == 0) {
  152. _core_api_dll.load_xml(xpackage);
  153. return true;
  154. }
  155. }
  156. xpackage = xpackage->NextSiblingElement("package");
  157. }
  158. }
  159. // Couldn't find the coreapi package description.
  160. nout << "No coreapi package defined in contents file for "
  161. << DTOOL_PLATFORM << "\n";
  162. return false;
  163. }
  164. ////////////////////////////////////////////////////////////////////
  165. // Function: PPInstance::find_host
  166. // Access: Private
  167. // Description: Scans the <contents> element for the matching <host>
  168. // element.
  169. ////////////////////////////////////////////////////////////////////
  170. void PPInstance::
  171. find_host(TiXmlElement *xcontents) {
  172. string host_url = PANDA_PACKAGE_HOST_URL;
  173. TiXmlElement *xhost = xcontents->FirstChildElement("host");
  174. if (xhost != NULL) {
  175. const char *url = xhost->Attribute("url");
  176. if (url != NULL && host_url == string(url)) {
  177. // We're the primary host. This is the normal case.
  178. read_xhost(xhost);
  179. return;
  180. } else {
  181. // We're not the primary host; perhaps we're an alternate host.
  182. TiXmlElement *xalthost = xhost->FirstChildElement("alt_host");
  183. while (xalthost != NULL) {
  184. const char *url = xalthost->Attribute("url");
  185. if (url != NULL && host_url == string(url)) {
  186. // Yep, we're this alternate host.
  187. read_xhost(xhost);
  188. return;
  189. }
  190. xalthost = xalthost->NextSiblingElement("alt_host");
  191. }
  192. }
  193. // Hmm, didn't find the URL we used mentioned. Assume we're the
  194. // primary host.
  195. read_xhost(xhost);
  196. }
  197. }
  198. ////////////////////////////////////////////////////////////////////
  199. // Function: PPInstance::read_xhost
  200. // Access: Private
  201. // Description: Reads the host data from the <host> (or <alt_host>)
  202. // entry in the contents.xml file.
  203. ////////////////////////////////////////////////////////////////////
  204. void PPInstance::
  205. read_xhost(TiXmlElement *xhost) {
  206. // Get the "download" URL, which is the source from which we
  207. // download everything other than the contents.xml file.
  208. const char *download_url = xhost->Attribute("download_url");
  209. if (download_url != NULL) {
  210. _download_url_prefix = download_url;
  211. } else {
  212. _download_url_prefix = PANDA_PACKAGE_HOST_URL;
  213. }
  214. if (!_download_url_prefix.empty()) {
  215. if (_download_url_prefix[_download_url_prefix.size() - 1] != '/') {
  216. _download_url_prefix += "/";
  217. }
  218. }
  219. TiXmlElement *xmirror = xhost->FirstChildElement("mirror");
  220. while (xmirror != NULL) {
  221. const char *url = xmirror->Attribute("url");
  222. if (url != NULL) {
  223. add_mirror(url);
  224. }
  225. xmirror = xmirror->NextSiblingElement("mirror");
  226. }
  227. }
  228. ////////////////////////////////////////////////////////////////////
  229. // Function: PPInstance::add_mirror
  230. // Access: Private
  231. // Description: Adds a new URL to serve as a mirror for this host.
  232. // The mirrors will be consulted first, before
  233. // consulting the host directly.
  234. ////////////////////////////////////////////////////////////////////
  235. void PPInstance::
  236. add_mirror(std::string mirror_url) {
  237. // Ensure the URL ends in a slash.
  238. if (!mirror_url.empty() && mirror_url[mirror_url.size() - 1] != '/') {
  239. mirror_url += '/';
  240. }
  241. // Add it to the _mirrors list, but only if it's not already
  242. // there.
  243. if (std::find(_mirrors.begin(), _mirrors.end(), mirror_url) == _mirrors.end()) {
  244. _mirrors.push_back(mirror_url);
  245. }
  246. }
  247. ////////////////////////////////////////////////////////////////////
  248. // Function: PPInstance::choose_random_mirrors
  249. // Access: Public
  250. // Description: Selects num_mirrors elements, chosen at random, from
  251. // the _mirrors list. Adds the selected mirrors to
  252. // result. If there are fewer than num_mirrors elements
  253. // in the list, adds only as many mirrors as we can get.
  254. ////////////////////////////////////////////////////////////////////
  255. void PPInstance::
  256. choose_random_mirrors(std::vector<std::string> &result, int num_mirrors) {
  257. std::vector<size_t> selected;
  258. size_t num_to_select = min(_mirrors.size(), (size_t)num_mirrors);
  259. while (num_to_select > 0) {
  260. size_t i = (size_t)(((double)rand() / (double)RAND_MAX) * _mirrors.size());
  261. while (std::find(selected.begin(), selected.end(), i) != selected.end()) {
  262. // Already found this i, find a new one.
  263. i = (size_t)(((double)rand() / (double)RAND_MAX) * _mirrors.size());
  264. }
  265. selected.push_back(i);
  266. result.push_back(_mirrors[i]);
  267. --num_to_select;
  268. }
  269. }
  270. int PPInstance::DownloadP3DComponents( std::string& p3dDllFilename )
  271. {
  272. int error(0);
  273. // Start off by downloading contents.xml into a local temporary
  274. // file. We get a unique temporary filename each time; this is a
  275. // small file and it's very important that we get the most current
  276. // version, not an old cached version.
  277. TCHAR tempFileName[ MAX_PATH ];
  278. if (!::GetTempFileName( m_rootDir.c_str(), "p3d", 0, tempFileName )) {
  279. nout << "GetTempFileName failed (folder is " << m_rootDir << ")\n";
  280. return 1;
  281. }
  282. std::string localContentsFileName( tempFileName );
  283. // We'll also get the final installation path of the contents.xml
  284. // file.
  285. std::string finalContentsFileName( m_rootDir );
  286. finalContentsFileName += "/";
  287. finalContentsFileName += P3D_CONTENTS_FILENAME;
  288. std::string hostUrl( PANDA_PACKAGE_HOST_URL );
  289. if (!hostUrl.empty() && hostUrl[hostUrl.size() - 1] != '/') {
  290. hostUrl += '/';
  291. }
  292. // Append a query string to the contents.xml URL to uniquify it
  293. // and ensure we don't get a cached version.
  294. std::ostringstream strm;
  295. strm << hostUrl << P3D_CONTENTS_FILENAME << "?" << time(NULL);
  296. std::string remoteContentsUrl( strm.str() );
  297. error = DownloadFile( remoteContentsUrl, localContentsFileName );
  298. if ( !error )
  299. {
  300. if ( !read_contents_file( localContentsFileName ) )
  301. error = 1;
  302. }
  303. if ( error ) {
  304. // If we couldn't download or read the contents.xml file, check
  305. // to see if there's a good one on disk already, as a fallback.
  306. if ( !read_contents_file( finalContentsFileName ) )
  307. error = 1;
  308. } else {
  309. // If we have successfully read the downloaded version,
  310. // then move the downloaded version into the final location.
  311. mkfile_complete( finalContentsFileName, nout );
  312. CopyFile( localContentsFileName, finalContentsFileName );
  313. }
  314. // We don't need the temporary file any more.
  315. ::DeleteFile( localContentsFileName.c_str() );
  316. if (!error) {
  317. // OK, at this point we have successfully read contents.xml,
  318. // and we have a good file spec in _core_api_dll.
  319. if (_core_api_dll.quick_verify(m_rootDir)) {
  320. // The DLL is already on-disk, and is good.
  321. p3dDllFilename = _core_api_dll.get_pathname(m_rootDir);
  322. } else {
  323. // The DLL is not already on-disk, or it's stale. Go get it.
  324. std::string p3dLocalModuleFileName(_core_api_dll.get_pathname(m_rootDir));
  325. mkfile_complete(p3dLocalModuleFileName, nout);
  326. // Try one of the mirrors first.
  327. std::vector<std::string> mirrors;
  328. choose_random_mirrors(mirrors, 2);
  329. error = 1;
  330. for (std::vector<std::string>::iterator si = mirrors.begin();
  331. si != mirrors.end() && error;
  332. ++si) {
  333. std::string url = (*si) + _core_api_dll.get_filename();
  334. error = DownloadFile(url, p3dLocalModuleFileName);
  335. if (!error && !_core_api_dll.full_verify(m_rootDir)) {
  336. // If it's not right after downloading, it's an error.
  337. error = 1;
  338. }
  339. }
  340. // If that failed, go get it from the authoritative host.
  341. if (error) {
  342. std::string url = _download_url_prefix + _core_api_dll.get_filename();
  343. error = DownloadFile(url, p3dLocalModuleFileName);
  344. if (!error && !_core_api_dll.full_verify(m_rootDir)) {
  345. error = 1;
  346. }
  347. }
  348. // If *that* failed, go get it again from the same URL, this
  349. // time with a query prefix to bust through any caches.
  350. if (error) {
  351. std::ostringstream strm;
  352. strm << _download_url_prefix << _core_api_dll.get_filename();
  353. strm << "?" << time(NULL);
  354. std::string url = strm.str();
  355. error = DownloadFile(url, p3dLocalModuleFileName);
  356. if (!error && !_core_api_dll.full_verify(m_rootDir)) {
  357. nout << "After download, " << _core_api_dll.get_filename()
  358. << " is no good.\n";
  359. error = 1;
  360. }
  361. }
  362. if (!error) {
  363. // Downloaded successfully.
  364. p3dDllFilename = _core_api_dll.get_pathname(m_rootDir);
  365. }
  366. }
  367. }
  368. if (error) {
  369. set_failed();
  370. }
  371. return error;
  372. }
  373. int PPInstance::LoadPlugin( const std::string& dllFilename )
  374. {
  375. if ( !m_pluginLoaded )
  376. {
  377. ref_plugin();
  378. m_pluginLoaded = true;
  379. }
  380. int error = 0;
  381. if (!is_plugin_loaded()) {
  382. std::string pathname = dllFilename;
  383. #ifdef P3D_PLUGIN_P3D_PLUGIN
  384. // This is a convenience macro for development. If defined and
  385. // nonempty, it indicates the name of the plugin DLL that we will
  386. // actually run, even after downloading a possibly different
  387. // (presumably older) version. Its purpose is to simplify iteration
  388. // on the plugin DLL.
  389. string override_filename = P3D_PLUGIN_P3D_PLUGIN;
  390. if (!override_filename.empty()) {
  391. pathname = override_filename;
  392. }
  393. #endif // P3D_PLUGIN_P3D_PLUGIN
  394. nout << "Attempting to load core API from " << pathname << "\n";
  395. if (!load_plugin(pathname, "", "", true, "", "", "", false, false, nout)) {
  396. nout << "Unable to launch core API in " << pathname << "\n";
  397. error = 1;
  398. } else {
  399. #ifdef PANDA_OFFICIAL_VERSION
  400. static const bool official = true;
  401. #else
  402. static const bool official = false;
  403. #endif
  404. P3D_set_plugin_version(P3D_PLUGIN_MAJOR_VERSION, P3D_PLUGIN_MINOR_VERSION,
  405. P3D_PLUGIN_SEQUENCE_VERSION, official,
  406. PANDA_DISTRIBUTOR,
  407. PANDA_PACKAGE_HOST_URL, _core_api_dll.get_timestamp());
  408. }
  409. }
  410. if (error) {
  411. set_failed();
  412. }
  413. return error ;
  414. }
  415. int PPInstance::UnloadPlugin()
  416. {
  417. int error( 0 );
  418. if ( m_pluginLoaded )
  419. {
  420. m_pluginLoaded = false;
  421. m_isInit = false;
  422. unref_plugin();
  423. }
  424. return error;
  425. }
  426. // Increments the reference count on the "plugin" library (i.e. the
  427. // core API). Call unref_plugin() later to decrement this count.
  428. void PPInstance::
  429. ref_plugin() {
  430. s_instanceCount += 1;
  431. }
  432. // Decrements the reference count on the "plugin" library. This must
  433. // correspond to an earlier call to ref_plugin(). When the last
  434. // reference is removed, the plugin will be unloaded.
  435. void PPInstance::
  436. unref_plugin() {
  437. assert( s_instanceCount > 0 );
  438. s_instanceCount -= 1;
  439. if ( s_instanceCount == 0 && is_plugin_loaded() ) {
  440. nout << "Unloading core API\n";
  441. unload_plugin();
  442. // This pointer is no longer valid and must be reset for next
  443. // time.
  444. PPBrowserObject::clear_class_definition();
  445. }
  446. }
  447. int PPInstance::Start( const std::string& p3dFilename )
  448. {
  449. m_eventStop.ResetEvent();
  450. P3D_window_handle parent_window;
  451. memset(&parent_window, 0, sizeof(parent_window));
  452. parent_window._window_handle_type = P3D_WHT_win_hwnd;
  453. parent_window._handle._win_hwnd._hwnd = m_parentCtrl.m_hWnd;
  454. RECT rect;
  455. GetClientRect( m_parentCtrl.m_hWnd, &rect );
  456. P3D_token* p3dTokens = new P3D_token[ m_parentCtrl.m_parameters.size() ];
  457. for ( UINT i = 0; i < m_parentCtrl.m_parameters.size(); i++ )
  458. {
  459. std::pair< CString, CString > keyAndValue = m_parentCtrl.m_parameters[ i ];
  460. p3dTokens[i]._keyword = strdup( m_parentCtrl.m_parameters[ i ].first );
  461. p3dTokens[i]._value = strdup( m_parentCtrl.m_parameters[ i ].second );
  462. }
  463. nout << "Creating new P3D instance object \n";
  464. m_p3dInstance = P3D_new_instance( &P3D_NofificationSync, p3dTokens, m_parentCtrl.m_parameters.size(), 0, NULL, (void*)&m_parentCtrl );
  465. for ( UINT j = 0; j < m_parentCtrl.m_parameters.size(); j++ )
  466. {
  467. delete [] p3dTokens[j]._keyword;
  468. delete [] p3dTokens[j]._value;
  469. }
  470. delete [] p3dTokens;
  471. if ( !m_p3dInstance )
  472. {
  473. nout << "Error creating P3D instance: " << GetLastError() << "\n";
  474. return 1;
  475. }
  476. CComPtr<IDispatchEx> pDispatch;
  477. PPBrowserObject *pobj = new PPBrowserObject( &m_parentCtrl, pDispatch );
  478. P3D_instance_set_browser_script_object( m_p3dInstance, pobj );
  479. P3D_OBJECT_DECREF( pobj );
  480. m_p3dObject = P3D_instance_get_panda_script_object( m_p3dInstance );
  481. P3D_OBJECT_INCREF( m_p3dObject );
  482. P3D_instance_setup_window( m_p3dInstance, P3D_WT_embedded, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, &parent_window );
  483. nout << "Starting new P3D instance " << p3dFilename << "\n";
  484. if ( !P3D_instance_start( m_p3dInstance, false, p3dFilename.c_str(), 0 ) )
  485. {
  486. nout << "Error starting P3D instance: " << GetLastError() << "\n";
  487. return 1;
  488. }
  489. m_isInit = true;
  490. return 0;
  491. }
  492. std::string PPInstance::GetHostUrl( )
  493. {
  494. CString hostingPageLocation = m_parentCtrl.m_hostingPageUrl.Left( m_parentCtrl.m_hostingPageUrl.ReverseFind( '/' ) );;
  495. std::string p3dRemoteFilename( hostingPageLocation );
  496. p3dRemoteFilename += "/";
  497. return p3dRemoteFilename;
  498. }
  499. std::string PPInstance::GetP3DFilename( )
  500. {
  501. std::string p3dFilename;
  502. for ( UINT i = 0; i < m_parentCtrl.m_parameters.size(); i++ )
  503. {
  504. std::pair< CString, CString > keyAndValue = m_parentCtrl.m_parameters[ i ];
  505. if ( keyAndValue.first == "data" )
  506. {
  507. p3dFilename = keyAndValue.second;
  508. }
  509. }
  510. return p3dFilename;
  511. }
  512. void PPInstance::HandleRequestLoop()
  513. {
  514. P3D_instance *p3d_inst = P3D_check_request(0.0);
  515. while ( p3d_inst != NULL )
  516. {
  517. P3D_request *request = P3D_instance_get_request(p3d_inst);
  518. if ( request != NULL )
  519. {
  520. CP3DActiveXCtrl* parent = ( CP3DActiveXCtrl* )(p3d_inst->_user_data);
  521. if ( parent )
  522. {
  523. parent->m_instance.HandleRequest( request );
  524. }
  525. else
  526. {
  527. nout << "Error handling P3D request. Instance's user data is not a Control \n";
  528. }
  529. }
  530. p3d_inst = P3D_check_request(0.0);
  531. }
  532. }
  533. void PPInstance::HandleRequestGetUrl( void* data )
  534. {
  535. P3D_request *request = static_cast<P3D_request*>( data );
  536. if ( !request )
  537. {
  538. return;
  539. }
  540. int unique_id = request->_request._get_url._unique_id;
  541. const std::string &url = request->_request._get_url._url;
  542. CP3DActiveXCtrl* parent = static_cast<CP3DActiveXCtrl*> ( request->_instance->_user_data );
  543. if ( !parent )
  544. {
  545. return;
  546. }
  547. nout << "Handling P3D_RT_get_url request from " << url << "\n";
  548. PPDownloadRequest p3dObjectDownloadRequest( parent->m_instance, request );
  549. PPDownloadCallback bsc( p3dObjectDownloadRequest );
  550. HRESULT hr = ::URLOpenStream( parent->GetControllingUnknown(), url.c_str(), 0, &bsc );
  551. P3D_result_code result_code = P3D_RC_done;
  552. if ( FAILED( hr ) )
  553. {
  554. nout << "Error handling P3D_RT_get_url request" << " :" << hr << "\n";
  555. result_code = P3D_RC_generic_error;
  556. }
  557. P3D_instance_feed_url_stream(
  558. request->_instance,
  559. request->_request._get_url._unique_id,
  560. result_code,
  561. 0,
  562. 0,
  563. (const void*)NULL,
  564. 0
  565. );
  566. P3D_request_finish( request, true );
  567. }
  568. void PPInstance::HandleRequest( P3D_request *request )
  569. {
  570. if ( !request )
  571. {
  572. return;
  573. }
  574. bool handled = false;
  575. switch ( request->_request_type )
  576. {
  577. case P3D_RT_stop:
  578. {
  579. P3D_instance_finish( request->_instance );
  580. handled = true;
  581. break;
  582. }
  583. case P3D_RT_get_url:
  584. {
  585. if ( !m_handleRequestOnUIThread )
  586. {
  587. _beginthread( HandleRequestGetUrl, 0, request );
  588. }
  589. else
  590. {
  591. HandleRequestGetUrl( request );
  592. }
  593. handled = true;
  594. return;
  595. }
  596. case P3D_RT_notify:
  597. {
  598. CString notification = request->_request._notify._message;
  599. if ( notification == "ondownloadbegin" )
  600. {
  601. m_handleRequestOnUIThread = false;
  602. }
  603. else if ( notification == "ondownloadcomplete" )
  604. {
  605. m_handleRequestOnUIThread = true;
  606. }
  607. handled = true;
  608. break;
  609. }
  610. default:
  611. {
  612. // Some request types are not handled.
  613. break;
  614. }
  615. };
  616. P3D_request_finish( request, handled );
  617. }
  618. ////////////////////////////////////////////////////////////////////
  619. // Function: PPInstance::set_failed
  620. // Access: Private
  621. // Description: Called when something has gone wrong that prevents
  622. // the plugin instance from running. Specifically, this
  623. // means it failed to load the core API.
  624. ////////////////////////////////////////////////////////////////////
  625. void PPInstance::
  626. set_failed() {
  627. if (!_failed) {
  628. _failed = true;
  629. nout << "Plugin failed.\n";
  630. string expression;
  631. // Look for the "onpluginfail" token.
  632. for (UINT i = 0; i < m_parentCtrl.m_parameters.size(); i++) {
  633. std::pair<CString, CString> keyAndValue = m_parentCtrl.m_parameters[i];
  634. // Make the token lowercase, since HTML is case-insensitive but
  635. // we're not.
  636. const CString &orig_keyword = m_parentCtrl.m_parameters[i].first;
  637. string keyword;
  638. for (const char *p = orig_keyword; *p; ++p) {
  639. keyword += tolower(*p);
  640. }
  641. if (keyword == "onpluginfail") {
  642. expression = m_parentCtrl.m_parameters[i].second;
  643. break;
  644. }
  645. }
  646. if (!expression.empty()) {
  647. // Now attempt to evaluate the expression.
  648. COleVariant varResult;
  649. CComPtr<IDispatch> pDispatch;
  650. CString evalExpression( expression.c_str() );
  651. HRESULT hr = m_parentCtrl.EvalExpression( pDispatch, evalExpression , varResult );
  652. if (FAILED(hr)) {
  653. nout << "Unable to eval " << expression << "\n";
  654. } else {
  655. nout << "Eval " << expression << "\n";
  656. }
  657. }
  658. }
  659. }