PPInstance.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  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_NotificationSync(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_ptr( 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,
  396. m_rootDir, nout)) {
  397. nout << "Unable to launch core API in " << pathname << "\n";
  398. error = 1;
  399. } else {
  400. #ifdef PANDA_OFFICIAL_VERSION
  401. static const bool official = true;
  402. #else
  403. static const bool official = false;
  404. #endif
  405. P3D_set_plugin_version_ptr(P3D_PLUGIN_MAJOR_VERSION, P3D_PLUGIN_MINOR_VERSION,
  406. P3D_PLUGIN_SEQUENCE_VERSION, official,
  407. PANDA_DISTRIBUTOR,
  408. PANDA_PACKAGE_HOST_URL, _core_api_dll.get_timestamp());
  409. }
  410. }
  411. if (error) {
  412. set_failed();
  413. }
  414. return error ;
  415. }
  416. int PPInstance::UnloadPlugin()
  417. {
  418. int error( 0 );
  419. if ( m_pluginLoaded )
  420. {
  421. m_pluginLoaded = false;
  422. m_isInit = false;
  423. unref_plugin();
  424. }
  425. return error;
  426. }
  427. // Increments the reference count on the "plugin" library (i.e. the
  428. // core API). Call unref_plugin() later to decrement this count.
  429. void PPInstance::
  430. ref_plugin() {
  431. s_instanceCount += 1;
  432. }
  433. // Decrements the reference count on the "plugin" library. This must
  434. // correspond to an earlier call to ref_plugin(). When the last
  435. // reference is removed, the plugin will be unloaded.
  436. void PPInstance::
  437. unref_plugin() {
  438. assert( s_instanceCount > 0 );
  439. s_instanceCount -= 1;
  440. if ( s_instanceCount == 0 && is_plugin_loaded() ) {
  441. nout << "Unloading core API\n";
  442. unload_plugin();
  443. // This pointer is no longer valid and must be reset for next
  444. // time.
  445. PPBrowserObject::clear_class_definition();
  446. }
  447. }
  448. int PPInstance::Start( const std::string& p3dFilename )
  449. {
  450. m_eventStop.ResetEvent();
  451. P3D_window_handle parent_window;
  452. memset(&parent_window, 0, sizeof(parent_window));
  453. parent_window._window_handle_type = P3D_WHT_win_hwnd;
  454. parent_window._handle._win_hwnd._hwnd = m_parentCtrl.m_hWnd;
  455. RECT rect;
  456. GetClientRect( m_parentCtrl.m_hWnd, &rect );
  457. P3D_token* p3dTokens = new P3D_token[ m_parentCtrl.m_parameters.size() ];
  458. for ( UINT i = 0; i < m_parentCtrl.m_parameters.size(); i++ )
  459. {
  460. std::pair< CString, CString > keyAndValue = m_parentCtrl.m_parameters[ i ];
  461. p3dTokens[i]._keyword = strdup( m_parentCtrl.m_parameters[ i ].first );
  462. p3dTokens[i]._value = strdup( m_parentCtrl.m_parameters[ i ].second );
  463. }
  464. nout << "Creating new P3D instance object \n";
  465. m_p3dInstance = P3D_new_instance_ptr( &P3D_NotificationSync, p3dTokens, m_parentCtrl.m_parameters.size(), 0, NULL, (void*)&m_parentCtrl );
  466. for ( UINT j = 0; j < m_parentCtrl.m_parameters.size(); j++ )
  467. {
  468. delete [] p3dTokens[j]._keyword;
  469. delete [] p3dTokens[j]._value;
  470. }
  471. delete [] p3dTokens;
  472. if ( !m_p3dInstance )
  473. {
  474. nout << "Error creating P3D instance: " << GetLastError() << "\n";
  475. return 1;
  476. }
  477. CComPtr<IDispatchEx> pDispatch;
  478. PPBrowserObject *pobj = new PPBrowserObject( &m_parentCtrl, pDispatch );
  479. P3D_instance_set_browser_script_object_ptr( m_p3dInstance, pobj );
  480. P3D_OBJECT_DECREF( pobj );
  481. m_p3dObject = P3D_instance_get_panda_script_object_ptr( m_p3dInstance );
  482. P3D_OBJECT_INCREF( m_p3dObject );
  483. P3D_instance_setup_window_ptr( m_p3dInstance, P3D_WT_embedded, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, &parent_window );
  484. nout << "Starting new P3D instance " << p3dFilename << "\n";
  485. if ( !P3D_instance_start_ptr( m_p3dInstance, false, p3dFilename.c_str(), 0 ) )
  486. {
  487. nout << "Error starting P3D instance: " << GetLastError() << "\n";
  488. return 1;
  489. }
  490. m_isInit = true;
  491. return 0;
  492. }
  493. std::string PPInstance::GetHostUrl( )
  494. {
  495. CString hostingPageLocation = m_parentCtrl.m_hostingPageUrl.Left( m_parentCtrl.m_hostingPageUrl.ReverseFind( '/' ) );;
  496. std::string p3dRemoteFilename( hostingPageLocation );
  497. p3dRemoteFilename += "/";
  498. return p3dRemoteFilename;
  499. }
  500. std::string PPInstance::GetP3DFilename( )
  501. {
  502. std::string p3dFilename;
  503. for ( UINT i = 0; i < m_parentCtrl.m_parameters.size(); i++ )
  504. {
  505. std::pair< CString, CString > keyAndValue = m_parentCtrl.m_parameters[ i ];
  506. if ( keyAndValue.first == "data" )
  507. {
  508. p3dFilename = keyAndValue.second;
  509. }
  510. }
  511. return p3dFilename;
  512. }
  513. void PPInstance::HandleRequestLoop()
  514. {
  515. P3D_instance *p3d_inst = P3D_check_request_ptr(0.0);
  516. while ( p3d_inst != NULL )
  517. {
  518. P3D_request *request = P3D_instance_get_request_ptr(p3d_inst);
  519. if ( request != NULL )
  520. {
  521. CP3DActiveXCtrl* parent = ( CP3DActiveXCtrl* )(p3d_inst->_user_data);
  522. if ( parent )
  523. {
  524. parent->m_instance.HandleRequest( request );
  525. }
  526. else
  527. {
  528. nout << "Error handling P3D request. Instance's user data is not a Control \n";
  529. }
  530. }
  531. p3d_inst = P3D_check_request_ptr(0.0);
  532. }
  533. }
  534. void PPInstance::HandleRequestGetUrl( void* data )
  535. {
  536. P3D_request *request = static_cast<P3D_request*>( data );
  537. if ( !request )
  538. {
  539. return;
  540. }
  541. int unique_id = request->_request._get_url._unique_id;
  542. const std::string &url = request->_request._get_url._url;
  543. CP3DActiveXCtrl* parent = static_cast<CP3DActiveXCtrl*> ( request->_instance->_user_data );
  544. if ( !parent )
  545. {
  546. return;
  547. }
  548. nout << "Handling P3D_RT_get_url request from " << url << "\n";
  549. PPDownloadRequest p3dObjectDownloadRequest( parent->m_instance, request );
  550. PPDownloadCallback bsc( p3dObjectDownloadRequest );
  551. HRESULT hr = ::URLOpenStream( parent->GetControllingUnknown(), url.c_str(), 0, &bsc );
  552. P3D_result_code result_code = P3D_RC_done;
  553. if ( FAILED( hr ) )
  554. {
  555. nout << "Error handling P3D_RT_get_url request" << " :" << hr << "\n";
  556. result_code = P3D_RC_generic_error;
  557. }
  558. P3D_instance_feed_url_stream_ptr(
  559. request->_instance,
  560. request->_request._get_url._unique_id,
  561. result_code,
  562. 0,
  563. 0,
  564. (const void*)NULL,
  565. 0
  566. );
  567. P3D_request_finish_ptr( request, true );
  568. }
  569. void PPInstance::HandleRequest( P3D_request *request )
  570. {
  571. if ( !request )
  572. {
  573. return;
  574. }
  575. bool handled = false;
  576. switch ( request->_request_type )
  577. {
  578. case P3D_RT_stop:
  579. {
  580. P3D_instance_finish_ptr( request->_instance );
  581. handled = true;
  582. break;
  583. }
  584. case P3D_RT_get_url:
  585. {
  586. if ( !m_handleRequestOnUIThread )
  587. {
  588. _beginthread( HandleRequestGetUrl, 0, request );
  589. }
  590. else
  591. {
  592. HandleRequestGetUrl( request );
  593. }
  594. handled = true;
  595. return;
  596. }
  597. case P3D_RT_notify:
  598. {
  599. CString notification = request->_request._notify._message;
  600. if ( notification == "ondownloadbegin" )
  601. {
  602. m_handleRequestOnUIThread = false;
  603. }
  604. else if ( notification == "ondownloadcomplete" )
  605. {
  606. m_handleRequestOnUIThread = true;
  607. }
  608. handled = true;
  609. break;
  610. }
  611. default:
  612. {
  613. // Some request types are not handled.
  614. break;
  615. }
  616. };
  617. P3D_request_finish_ptr( request, handled );
  618. }
  619. ////////////////////////////////////////////////////////////////////
  620. // Function: PPInstance::set_failed
  621. // Access: Private
  622. // Description: Called when something has gone wrong that prevents
  623. // the plugin instance from running. Specifically, this
  624. // means it failed to load the core API.
  625. ////////////////////////////////////////////////////////////////////
  626. void PPInstance::
  627. set_failed() {
  628. if (!_failed) {
  629. _failed = true;
  630. nout << "Plugin failed.\n";
  631. string expression;
  632. // Look for the "onpluginfail" token.
  633. for (UINT i = 0; i < m_parentCtrl.m_parameters.size(); i++) {
  634. std::pair<CString, CString> keyAndValue = m_parentCtrl.m_parameters[i];
  635. // Make the token lowercase, since HTML is case-insensitive but
  636. // we're not.
  637. const CString &orig_keyword = m_parentCtrl.m_parameters[i].first;
  638. string keyword;
  639. for (const char *p = orig_keyword; *p; ++p) {
  640. keyword += tolower(*p);
  641. }
  642. if (keyword == "onpluginfail") {
  643. expression = m_parentCtrl.m_parameters[i].second;
  644. break;
  645. }
  646. }
  647. if (!expression.empty()) {
  648. // Now attempt to evaluate the expression.
  649. COleVariant varResult;
  650. CComPtr<IDispatch> pDispatch;
  651. CString evalExpression( expression.c_str() );
  652. HRESULT hr = m_parentCtrl.EvalExpression( pDispatch, evalExpression , varResult );
  653. if (FAILED(hr)) {
  654. nout << "Unable to eval " << expression << "\n";
  655. } else {
  656. nout << "Eval " << expression << "\n";
  657. }
  658. }
  659. }
  660. }