jnetcom.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. #include "jnetcom.h"
  2. #include "../nu/AutoChar.h"
  3. /* --- Jnetlib COM object --- */
  4. extern "C" extern HANDLE DuplicateCurrentThread();
  5. JNetCOM::JNetCOM( IDispatch *_dispatch )
  6. {
  7. refCount = 1;
  8. token = 0;
  9. dispatch = _dispatch;
  10. threadId = GetCurrentThreadId();
  11. threadHandle = DuplicateCurrentThread();
  12. retained = false;
  13. if ( NULL != dispatch )
  14. dispatch->AddRef();
  15. }
  16. JNetCOM::~JNetCOM()
  17. {
  18. if ( retained )
  19. {
  20. if ( NULL != WAC_API_DOWNLOADMANAGER )
  21. WAC_API_DOWNLOADMANAGER->ReleaseDownload( token );
  22. }
  23. CloseHandle( threadHandle );
  24. if ( NULL != dispatch )
  25. dispatch->Release();
  26. }
  27. enum
  28. {
  29. DISP_JNETCOM_ABORT,
  30. DISP_JNETCOM_ADDHEADER,
  31. DISP_JNETCOM_CONNECT,
  32. DISP_JNETCOM_GETCONTENT,
  33. DISP_JNETCOM_GETCONTENTASSTRING,
  34. DISP_JNETCOM_GETERRORSTRING,
  35. DISP_JNETCOM_GETHEADER,
  36. DISP_JNETCOM_GETREPLY,
  37. DISP_JNETCOM_GETREPLYCODE,
  38. DISP_JNETCOM_GETURL,
  39. DISP_JNETCOM_SETPOSTSTRING,
  40. };
  41. #define CHECK_ID(str, id)\
  42. if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
  43. { rgdispid[i] = id; continue; }
  44. HRESULT JNetCOM::GetIDsOfNames( REFIID riid, OLECHAR FAR *FAR *rgszNames, unsigned int cNames, LCID lcid, DISPID FAR *rgdispid )
  45. {
  46. bool unknowns = false;
  47. for ( unsigned int i = 0; i != cNames; i++ )
  48. {
  49. CHECK_ID( "Abort", DISP_JNETCOM_ABORT );
  50. CHECK_ID( "AddHeader", DISP_JNETCOM_ADDHEADER );
  51. CHECK_ID( "Connect", DISP_JNETCOM_CONNECT );
  52. CHECK_ID( "GetContent", DISP_JNETCOM_GETCONTENT );
  53. CHECK_ID( "GetContentAsString", DISP_JNETCOM_GETCONTENTASSTRING );
  54. CHECK_ID( "GetErrorString", DISP_JNETCOM_GETERRORSTRING );
  55. CHECK_ID( "GetHeader", DISP_JNETCOM_GETHEADER );
  56. CHECK_ID( "GetReply", DISP_JNETCOM_GETREPLY );
  57. CHECK_ID( "GetReplyCode", DISP_JNETCOM_GETREPLYCODE );
  58. CHECK_ID( "GetURL", DISP_JNETCOM_GETURL );
  59. CHECK_ID( "SetPOSTString", DISP_JNETCOM_SETPOSTSTRING );
  60. rgdispid[ i ] = DISPID_UNKNOWN;
  61. unknowns = true;
  62. }
  63. if ( unknowns )
  64. return DISP_E_UNKNOWNNAME;
  65. else
  66. return S_OK;
  67. }
  68. HRESULT JNetCOM::GetTypeInfo( unsigned int itinfo, LCID lcid, ITypeInfo FAR *FAR *pptinfo )
  69. {
  70. return E_NOTIMPL;
  71. }
  72. HRESULT JNetCOM::GetTypeInfoCount( unsigned int FAR *pctinfo )
  73. {
  74. return E_NOTIMPL;
  75. }
  76. HRESULT JNetCOM::Invoke( DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR *pexecinfo, unsigned int FAR *puArgErr )
  77. {
  78. switch ( dispid )
  79. {
  80. case DISP_JNETCOM_ABORT:
  81. return Abort();
  82. case DISP_JNETCOM_ADDHEADER:
  83. return AddHeader( pdispparams->rgvarg[ 0 ].bstrVal );
  84. case DISP_JNETCOM_CONNECT:
  85. if ( pdispparams->cArgs == 2 )
  86. return Connect( pdispparams->rgvarg[ 1 ].bstrVal, pdispparams->rgvarg[ 0 ].bstrVal );
  87. else
  88. return Connect( pdispparams->rgvarg[ 0 ].bstrVal, L"GET" );
  89. case DISP_JNETCOM_GETCONTENT:
  90. return GetContent( pvarResult );
  91. case DISP_JNETCOM_GETCONTENTASSTRING:
  92. return GetContentAsString( pvarResult );
  93. case DISP_JNETCOM_GETERRORSTRING:
  94. return GetErrorString( pvarResult );
  95. case DISP_JNETCOM_GETHEADER:
  96. return GetHeader( pdispparams->rgvarg[ 0 ].bstrVal, pvarResult );
  97. case DISP_JNETCOM_GETREPLY:
  98. return GetReply( pvarResult );
  99. case DISP_JNETCOM_GETREPLYCODE:
  100. return GetReplyCode( pvarResult );
  101. case DISP_JNETCOM_GETURL:
  102. return GetUrl( pvarResult );
  103. case DISP_JNETCOM_SETPOSTSTRING:
  104. break;
  105. }
  106. return DISP_E_MEMBERNOTFOUND;
  107. }
  108. STDMETHODIMP JNetCOM::QueryInterface( REFIID riid, PVOID *ppvObject )
  109. {
  110. if ( !ppvObject )
  111. return E_POINTER;
  112. else if ( IsEqualIID( riid, IID_IDispatch ) )
  113. *ppvObject = (IDispatch *)this;
  114. else if ( IsEqualIID( riid, IID_IUnknown ) )
  115. *ppvObject = this;
  116. else
  117. {
  118. *ppvObject = NULL;
  119. return E_NOINTERFACE;
  120. }
  121. AddRef();
  122. return S_OK;
  123. }
  124. ULONG JNetCOM::AddRef( void )
  125. {
  126. return InterlockedIncrement( &refCount );
  127. }
  128. ULONG JNetCOM::Release( void )
  129. {
  130. LONG lRef = InterlockedDecrement( &refCount );
  131. if ( lRef == 0 )
  132. delete this;
  133. return lRef;
  134. }
  135. /* ---- */
  136. HRESULT JNetCOM::Abort()
  137. {
  138. if ( NULL != WAC_API_DOWNLOADMANAGER )
  139. WAC_API_DOWNLOADMANAGER->CancelDownload( token );
  140. return S_OK;
  141. }
  142. HRESULT JNetCOM::AddHeader( LPCWSTR header )
  143. {
  144. if ( NULL == WAC_API_DOWNLOADMANAGER )
  145. return E_POINTER;
  146. api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
  147. if ( http )
  148. http->addheader( AutoChar( header, CP_UTF8 ) );
  149. return S_OK;
  150. }
  151. HRESULT JNetCOM::Connect( LPCWSTR url, LPCWSTR requestMethod )
  152. {
  153. if ( NULL == WAC_API_DOWNLOADMANAGER )
  154. return E_POINTER;
  155. AddRef();
  156. token = WAC_API_DOWNLOADMANAGER->DownloadEx( AutoChar( url, CP_UTF8 ), this, api_downloadManager::DOWNLOADEX_BUFFER );
  157. return S_OK;
  158. }
  159. HRESULT JNetCOM::GetContent( VARIANT *variant )
  160. {
  161. char dummy[ 1 ] = { 0 };
  162. size_t sourcelen = 0;
  163. void *source = 0;
  164. if ( NULL == WAC_API_DOWNLOADMANAGER )
  165. return E_POINTER;
  166. WAC_API_DOWNLOADMANAGER->GetBuffer( token, &source, &sourcelen );
  167. if ( !sourcelen || !source )
  168. {
  169. source = dummy;
  170. sourcelen = 1;
  171. }
  172. SAFEARRAY *bufferArray = SafeArrayCreateVector( VT_UI1, 0, (ULONG)sourcelen );
  173. void *data;
  174. SafeArrayAccessData( bufferArray, &data );
  175. memcpy( data, source, sourcelen );
  176. SafeArrayUnaccessData( bufferArray );
  177. VariantInit( variant );
  178. V_VT( variant ) = VT_ARRAY | VT_UI1;
  179. V_ARRAY( variant ) = bufferArray;
  180. return S_OK;
  181. }
  182. HRESULT JNetCOM::GetContentAsString( VARIANT *variant )
  183. {
  184. // TODO: try to determine character encoding
  185. size_t sourcelen = 0;
  186. void *source = 0;
  187. if ( NULL == WAC_API_DOWNLOADMANAGER )
  188. return E_POINTER;
  189. if ( WAC_API_DOWNLOADMANAGER->GetBuffer( token, &source, &sourcelen ) == 0 )
  190. {
  191. if ( source && sourcelen )
  192. {
  193. int len = MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)source, (int)sourcelen, 0, 0 );
  194. BSTR str = SysAllocStringLen( 0, len );
  195. MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)source, (int)sourcelen, str, len );
  196. VariantInit( variant );
  197. V_VT( variant ) = VT_BSTR;
  198. V_BSTR( variant ) = str;
  199. return S_OK;
  200. }
  201. else
  202. {
  203. VariantInit( variant );
  204. V_VT( variant ) = VT_BSTR;
  205. V_BSTR( variant ) = SysAllocString( L"" );
  206. return S_OK;
  207. }
  208. }
  209. else
  210. return E_FAIL;
  211. }
  212. HRESULT JNetCOM::GetErrorString( VARIANT *variant )
  213. {
  214. const char *source = 0;
  215. if ( NULL == WAC_API_DOWNLOADMANAGER )
  216. return E_POINTER;
  217. api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
  218. if ( http )
  219. source = http->geterrorstr();
  220. if ( !source )
  221. source = "";
  222. int sourcelen = (int)strlen( source );
  223. int len = MultiByteToWideChar( CP_ACP, 0, source, sourcelen, 0, 0 );
  224. BSTR str = SysAllocStringLen( 0, len );
  225. MultiByteToWideChar( CP_ACP, 0, source, sourcelen, str, len );
  226. VariantInit( variant );
  227. V_VT( variant ) = VT_BSTR;
  228. V_BSTR( variant ) = str;
  229. return S_OK;
  230. }
  231. HRESULT JNetCOM::GetHeader( LPCWSTR header, VARIANT *variant )
  232. {
  233. const char *source = 0;
  234. if ( NULL == WAC_API_DOWNLOADMANAGER )
  235. return E_POINTER;
  236. api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
  237. if ( http )
  238. source = http->getheader( AutoChar( header, CP_UTF8 ) );
  239. if ( !source )
  240. source = "";
  241. int sourcelen = (int)strlen( source );
  242. int len = MultiByteToWideChar( CP_ACP, 0, source, sourcelen, 0, 0 );
  243. BSTR str = SysAllocStringLen( 0, len );
  244. MultiByteToWideChar( CP_ACP, 0, source, sourcelen, str, len );
  245. VariantInit( variant );
  246. V_VT( variant ) = VT_BSTR;
  247. V_BSTR( variant ) = str;
  248. return S_OK;
  249. }
  250. HRESULT JNetCOM::GetReply( VARIANT *variant )
  251. {
  252. const char *source = 0;
  253. if ( NULL == WAC_API_DOWNLOADMANAGER )
  254. return E_POINTER;
  255. api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
  256. if ( http )
  257. source = http->GetReply();
  258. if ( !source )
  259. source = "";
  260. int sourcelen = (int)strlen( source );
  261. int len = MultiByteToWideChar( CP_ACP, 0, source, sourcelen, 0, 0 );
  262. BSTR str = SysAllocStringLen( 0, len );
  263. MultiByteToWideChar( CP_ACP, 0, source, sourcelen, str, len );
  264. VariantInit( variant );
  265. V_VT( variant ) = VT_BSTR;
  266. V_BSTR( variant ) = str;
  267. return S_OK;
  268. }
  269. HRESULT JNetCOM::GetReplyCode( VARIANT *variant )
  270. {
  271. if ( NULL == WAC_API_DOWNLOADMANAGER )
  272. return E_POINTER;
  273. int code = 0;
  274. api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
  275. if ( http )
  276. code = http->getreplycode();
  277. VariantInit( variant );
  278. V_VT( variant ) = VT_UI4;
  279. V_UI4( variant ) = code;
  280. return S_OK;
  281. }
  282. HRESULT JNetCOM::GetUrl( VARIANT *variant )
  283. {
  284. if ( NULL == WAC_API_DOWNLOADMANAGER )
  285. return E_POINTER;
  286. const char *source = 0;
  287. api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
  288. if ( http )
  289. source = http->get_url();
  290. if ( !source )
  291. source = "";
  292. int sourcelen = (int)strlen( source );
  293. int len = MultiByteToWideChar( 1252, 0, source, sourcelen, 0, 0 );
  294. BSTR str = SysAllocStringLen( 0, len );
  295. MultiByteToWideChar( 1252, 0, source, sourcelen, str, len );
  296. VariantInit( variant );
  297. V_VT( variant ) = VT_BSTR;
  298. V_BSTR( variant ) = str;
  299. return S_OK;
  300. }
  301. extern void CallDispatchMethod( IDispatch *dispatch, DISPPARAMS &params, OLECHAR *name );
  302. struct APCWait
  303. {
  304. IDispatch *dispatch;
  305. HANDLE hEvent;
  306. };
  307. #define AutoAPC(name) \
  308. static VOID CALLBACK name ## APC(ULONG_PTR param) {\
  309. APCWait *wait = (APCWait *)param;\
  310. \
  311. DISPPARAMS params;\
  312. params.cArgs = 0;\
  313. params.cNamedArgs = 0;\
  314. params.rgdispidNamedArgs = 0;\
  315. params.rgvarg = 0;\
  316. if (wait->dispatch != NULL)\
  317. CallDispatchMethod(wait->dispatch, params, L ## #name);\
  318. if (wait->hEvent)\
  319. SetEvent(wait->hEvent);\
  320. }
  321. AutoAPC( OnFinish );
  322. AutoAPC( OnTick );
  323. AutoAPC( OnError );
  324. AutoAPC( OnCancel );
  325. AutoAPC( OnConnect );
  326. AutoAPC( OnInit );
  327. void JNetCOM::Call( PAPCFUNC func )
  328. {
  329. DWORD curThreadId = GetCurrentThreadId();
  330. if ( curThreadId == threadId )
  331. {
  332. APCWait wait;
  333. wait.dispatch = dispatch;
  334. wait.hEvent = 0;
  335. func( (ULONG_PTR)&wait );
  336. }
  337. else
  338. {
  339. if ( threadHandle )
  340. {
  341. APCWait wait;
  342. wait.dispatch = dispatch;
  343. wait.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  344. if ( QueueUserAPC( func, threadHandle, (ULONG_PTR)&wait ) != 0 )
  345. WaitForSingleObject( wait.hEvent, INFINITE );
  346. CloseHandle( wait.hEvent );
  347. }
  348. }
  349. }
  350. void JNetCOM::OnFinish( DownloadToken token )
  351. {
  352. if ( NULL != WAC_API_DOWNLOADMANAGER )
  353. WAC_API_DOWNLOADMANAGER->RetainDownload( token );
  354. retained = true;
  355. Call( OnFinishAPC );
  356. token = 0;
  357. Release();
  358. }
  359. void JNetCOM::OnTick( DownloadToken token )
  360. {
  361. //Call(OnTickAPC);
  362. }
  363. void JNetCOM::OnError( DownloadToken token, int error )
  364. {
  365. if ( NULL != WAC_API_DOWNLOADMANAGER )
  366. WAC_API_DOWNLOADMANAGER->RetainDownload( token );
  367. retained = true;
  368. Call( OnErrorAPC );
  369. token = 0;
  370. Release();
  371. }
  372. void JNetCOM::OnCancel( DownloadToken token )
  373. {
  374. if ( NULL != WAC_API_DOWNLOADMANAGER )
  375. WAC_API_DOWNLOADMANAGER->RetainDownload( token );
  376. retained = true;
  377. Call( OnCancelAPC );
  378. token = 0;
  379. Release();
  380. }
  381. void JNetCOM::OnConnect( DownloadToken token )
  382. {
  383. Call( OnConnectAPC );
  384. }
  385. void JNetCOM::OnInit( DownloadToken token )
  386. {
  387. Call( OnInitAPC );
  388. }
  389. size_t JNetCOM::Dispatchable_AddRef()
  390. {
  391. return InterlockedIncrement( &refCount );
  392. }
  393. size_t JNetCOM::Dispatchable_Release()
  394. {
  395. LONG lRef = InterlockedDecrement( &refCount );
  396. if ( lRef == 0 )
  397. delete this;
  398. return lRef;
  399. }
  400. #define CBCLASS JNetCOM
  401. START_DISPATCH;
  402. CB( ADDREF, Dispatchable_AddRef )
  403. CB( RELEASE, Dispatchable_Release )
  404. VCB( IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, OnFinish )
  405. VCB( IFC_DOWNLOADMANAGERCALLBACK_ONTICK, OnTick )
  406. VCB( IFC_DOWNLOADMANAGERCALLBACK_ONERROR, OnError )
  407. VCB( IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL, OnCancel )
  408. VCB( IFC_DOWNLOADMANAGERCALLBACK_ONCONNECT, OnConnect )
  409. VCB( IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit )
  410. END_DISPATCH;
  411. #undef CBCLASS