dispatchCallback.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. //#include "main.h"
  2. #include "./dispatchCallback.h"
  3. #include <new.h>
  4. DispatchCallback::DispatchCallback()
  5. : ref(1), dispatch(NULL), threadId(0), threadHandle(NULL)
  6. {
  7. }
  8. DispatchCallback::~DispatchCallback()
  9. {
  10. if (NULL != dispatch)
  11. dispatch->Release();
  12. if (NULL != threadHandle)
  13. CloseHandle(threadHandle);
  14. }
  15. HRESULT DispatchCallback::CreateInstance(IDispatch *dispatch, DispatchCallback **instance)
  16. {
  17. if (NULL == instance)
  18. return E_POINTER;
  19. *instance = NULL;
  20. if (NULL == dispatch)
  21. return E_INVALIDARG;
  22. DispatchCallback *self = new DispatchCallback();
  23. if (NULL == self)
  24. return E_OUTOFMEMORY;
  25. self->dispatch = dispatch;
  26. self->dispatch->AddRef();
  27. self->threadId = GetCurrentThreadId();
  28. HANDLE processHandle = GetCurrentProcess();
  29. if (FALSE == DuplicateHandle(processHandle,
  30. GetCurrentThread(),
  31. processHandle,
  32. &self->threadHandle,
  33. 0,
  34. FALSE,
  35. DUPLICATE_SAME_ACCESS))
  36. {
  37. self->threadHandle = NULL;
  38. delete(self);
  39. return E_FAIL;
  40. }
  41. *instance = self;
  42. return S_OK;
  43. }
  44. unsigned long DispatchCallback::AddRef()
  45. {
  46. return InterlockedIncrement((long*)&ref);
  47. }
  48. unsigned long DispatchCallback::Release()
  49. {
  50. if (0 == ref)
  51. return ref;
  52. LONG r = InterlockedDecrement((long*)&ref);
  53. if (0 == r)
  54. delete(this);
  55. return r;
  56. }
  57. IDispatch *DispatchCallback::GetDispatch()
  58. {
  59. return dispatch;
  60. }
  61. unsigned long DispatchCallback::GetThreadId()
  62. {
  63. return threadId;
  64. }
  65. HANDLE DispatchCallback::GetThreadHandle()
  66. {
  67. return threadHandle;
  68. }
  69. DispatchCallbackEnum::DispatchCallbackEnum()
  70. : ref(1), buffer(NULL), size(0), cursor(0)
  71. {
  72. }
  73. DispatchCallbackEnum::~DispatchCallbackEnum()
  74. {
  75. if (NULL != buffer)
  76. {
  77. while(size--)
  78. {
  79. buffer[size]->Release();
  80. }
  81. }
  82. }
  83. HRESULT DispatchCallbackEnum::CreateInstance(DispatchCallback **objects, size_t count, DispatchCallbackEnum **instance)
  84. {
  85. DispatchCallback *callback = NULL;
  86. DispatchCallbackEnum *enumerator = NULL;
  87. if (NULL == instance)
  88. return E_POINTER;
  89. *instance = NULL;
  90. size_t size = sizeof(DispatchCallbackEnum) + (sizeof(DispatchCallback**) * count);
  91. void *storage = calloc(size, 1);
  92. if (NULL == storage)
  93. return E_OUTOFMEMORY;
  94. enumerator = new(storage) DispatchCallbackEnum();
  95. if (NULL == enumerator)
  96. {
  97. free(storage);
  98. return E_FAIL;
  99. }
  100. enumerator->buffer = (DispatchCallback**)(((BYTE*)enumerator) + sizeof(DispatchCallback));
  101. for (size_t index = 0; index < count; index++)
  102. {
  103. callback = objects[index];
  104. if (NULL != callback)
  105. {
  106. enumerator->buffer[enumerator->size] = callback;
  107. callback->AddRef();
  108. enumerator->size++;
  109. }
  110. }
  111. *instance = enumerator;
  112. return S_OK;
  113. }
  114. unsigned long DispatchCallbackEnum::AddRef()
  115. {
  116. return InterlockedIncrement((LONG*)&ref);
  117. }
  118. unsigned long DispatchCallbackEnum::Release()
  119. {
  120. if (0 == ref)
  121. return ref;
  122. LONG r = InterlockedDecrement((LONG*)&ref);
  123. if (0 == r)
  124. delete(this);
  125. return r;
  126. }
  127. HRESULT DispatchCallbackEnum::Next(DispatchCallback **objects, size_t bufferMax, size_t *fetched)
  128. {
  129. if (NULL == objects)
  130. return E_POINTER;
  131. if (0 == bufferMax)
  132. return E_INVALIDARG;
  133. if (cursor >= size)
  134. {
  135. if (NULL != fetched)
  136. *fetched = 0;
  137. return S_FALSE;
  138. }
  139. size_t available = size - cursor;
  140. size_t copied = ((available > bufferMax) ? bufferMax : available);
  141. DispatchCallback **source = buffer + cursor;
  142. CopyMemory(objects, source, copied * sizeof(DispatchCallback*));
  143. for(size_t index = 0; index < copied; index++)
  144. objects[index]->AddRef();
  145. cursor += copied;
  146. if (NULL != fetched)
  147. *fetched = copied;
  148. return (bufferMax == copied) ? S_OK : S_FALSE;
  149. }
  150. HRESULT DispatchCallbackEnum::Reset(void)
  151. {
  152. cursor = 0;
  153. return S_OK;
  154. }
  155. HRESULT DispatchCallbackEnum::Skip(size_t count)
  156. {
  157. cursor += count;
  158. if (cursor > size)
  159. cursor = size;
  160. return (cursor < size) ? S_OK : S_FALSE;
  161. }
  162. HRESULT DispatchCallbackEnum::GetCount(size_t *count)
  163. {
  164. if (NULL == count)
  165. return E_POINTER;
  166. *count = size;
  167. return S_OK;
  168. }
  169. HRESULT DispatchCallbackEnum::Notify(DispatchCallbackNotifyFunc notifyCb, DispatchCallbackFreeFunc freeCb, void *param)
  170. {
  171. DispatchCallbackApc *apc = NULL;
  172. unsigned long threadId = GetCurrentThreadId();
  173. if (NULL == buffer)
  174. return E_UNEXPECTED;
  175. HRESULT hr = DispatchCallbackApc::CreateInstance(notifyCb, freeCb, param, &apc);
  176. if (FAILED(hr) || apc == NULL)
  177. return hr;
  178. for (size_t index = 0; index < size; index++)
  179. {
  180. DispatchCallback *callback = buffer[index];
  181. if (callback)
  182. {
  183. if (callback->GetThreadId() == threadId)
  184. apc->Call(callback->GetDispatch());
  185. else
  186. apc->Queue(callback->GetThreadHandle(), callback->GetDispatch());
  187. }
  188. }
  189. apc->Release();
  190. return hr;
  191. }
  192. DispatchCallbackStore::DispatchCallbackStore()
  193. {
  194. InitializeCriticalSection(&lock);
  195. }
  196. DispatchCallbackStore::~DispatchCallbackStore()
  197. {
  198. UnregisterAll();
  199. DeleteCriticalSection(&lock);
  200. }
  201. void DispatchCallbackStore::Lock()
  202. {
  203. EnterCriticalSection(&lock);
  204. }
  205. void DispatchCallbackStore::Unlock()
  206. {
  207. LeaveCriticalSection(&lock);
  208. }
  209. CRITICAL_SECTION *DispatchCallbackStore::GetLock()
  210. {
  211. return &lock;
  212. }
  213. HRESULT DispatchCallbackStore::Register(IDispatch *dispatch)
  214. {
  215. DispatchCallback *callback = NULL;
  216. if (NULL == dispatch)
  217. return E_INVALIDARG;
  218. Lock();
  219. HRESULT hr = S_OK;
  220. size_t index = list.size();
  221. while(index--)
  222. {
  223. callback = list[index];
  224. if (callback->GetDispatch() == dispatch)
  225. {
  226. hr = S_FALSE;
  227. break;
  228. }
  229. }
  230. if (S_OK == hr)
  231. {
  232. hr = DispatchCallback::CreateInstance(dispatch, &callback);
  233. if (SUCCEEDED(hr))
  234. list.push_back(callback);
  235. }
  236. Unlock();
  237. return hr;
  238. }
  239. HRESULT DispatchCallbackStore::Unregister(IDispatch *dispatch)
  240. {
  241. if (NULL == dispatch)
  242. return E_INVALIDARG;
  243. Lock();
  244. HRESULT hr = S_FALSE;
  245. size_t index = list.size();
  246. while(index--)
  247. {
  248. DispatchCallback *callback = list[index];
  249. if (callback->GetDispatch() == dispatch)
  250. {
  251. list.erase(list.begin() + index);
  252. callback->Release();
  253. hr = S_OK;
  254. break;
  255. }
  256. }
  257. Unlock();
  258. return hr;
  259. }
  260. void DispatchCallbackStore::UnregisterAll()
  261. {
  262. Lock();
  263. size_t index = list.size();
  264. while(index--)
  265. {
  266. DispatchCallback *callback = list[index];
  267. callback->Release();
  268. }
  269. list.clear();
  270. Unlock();
  271. }
  272. HRESULT DispatchCallbackStore::Enumerate(DispatchCallbackEnum **enumerator)
  273. {
  274. if (NULL == enumerator || !(list.size() > 0))
  275. return E_POINTER;
  276. Lock();
  277. HRESULT hr = DispatchCallbackEnum::CreateInstance(&list[0], list.size(), enumerator);
  278. Unlock();
  279. return hr;
  280. }
  281. HRESULT DispatchCallbackStore::RegisterFromDispParam(DISPPARAMS *pdispparams, unsigned int position,
  282. unsigned int *puArgErr)
  283. {
  284. VARIANTARG varg;
  285. VariantInit(&varg);
  286. HRESULT hr = DispGetParam(pdispparams, position, VT_DISPATCH, &varg, puArgErr);
  287. if (SUCCEEDED(hr))
  288. {
  289. hr = Register(V_DISPATCH(&varg));
  290. VariantClear(&varg);
  291. }
  292. return hr;
  293. }
  294. HRESULT DispatchCallbackStore::UnregisterFromDispParam(DISPPARAMS *pdispparams, unsigned int position,
  295. unsigned int *puArgErr)
  296. {
  297. VARIANTARG varg;
  298. VariantInit(&varg);
  299. HRESULT hr = DispGetParam(pdispparams, position, VT_DISPATCH, &varg, puArgErr);
  300. if (SUCCEEDED(hr))
  301. {
  302. hr = Unregister(V_DISPATCH(&varg));
  303. VariantClear(&varg);
  304. }
  305. return hr;
  306. }
  307. HRESULT DispatchCallbackStore::Notify(DispatchCallbackNotifyFunc notifyCb, DispatchCallbackFreeFunc freeCb, void *param)
  308. {
  309. DispatchCallbackEnum *enumerator = NULL;
  310. HRESULT hr = Enumerate(&enumerator);
  311. if (SUCCEEDED(hr))
  312. {
  313. hr = enumerator->Notify(notifyCb, freeCb, param);
  314. enumerator->Release();
  315. }
  316. return hr;
  317. }
  318. DispatchCallbackApc::DispatchCallbackApc()
  319. : ref(1), notifyCb(NULL), freeCb(NULL), param(NULL)
  320. {
  321. }
  322. DispatchCallbackApc::~DispatchCallbackApc()
  323. {
  324. if (NULL != freeCb)
  325. freeCb(param);
  326. }
  327. HRESULT DispatchCallbackApc::CreateInstance(DispatchCallbackNotifyFunc notifyCb, DispatchCallbackFreeFunc freeCb,
  328. void *param, DispatchCallbackApc **instance)
  329. {
  330. if (NULL == instance)
  331. return E_POINTER;
  332. *instance = NULL;
  333. if (NULL == notifyCb)
  334. return E_INVALIDARG;
  335. DispatchCallbackApc *self = new DispatchCallbackApc();
  336. if (NULL == self)
  337. return E_OUTOFMEMORY;
  338. self->notifyCb = notifyCb;
  339. self->freeCb = freeCb;
  340. self->param = param;
  341. *instance = self;
  342. return S_OK;
  343. }
  344. unsigned long DispatchCallbackApc::AddRef()
  345. {
  346. return InterlockedIncrement((LONG*)&ref);
  347. }
  348. unsigned long DispatchCallbackApc::Release()
  349. {
  350. if (0 == ref)
  351. return ref;
  352. LONG r = InterlockedDecrement((LONG*)&ref);
  353. if (0 == r)
  354. delete(this);
  355. return r;
  356. }
  357. HRESULT DispatchCallbackApc::Call(IDispatch *dispatch)
  358. {
  359. if (NULL == notifyCb)
  360. return E_UNEXPECTED;
  361. notifyCb(dispatch, param);
  362. return S_OK;
  363. }
  364. HRESULT DispatchCallbackApc::Queue(HANDLE threadHandle, IDispatch *dispatch)
  365. {
  366. if (NULL == threadHandle || ((unsigned int)dispatch) < 65536)
  367. return E_INVALIDARG;
  368. DispatchCallbackApcParam *apcParam = new DispatchCallbackApcParam(dispatch, this);
  369. if (NULL == apcParam || ((unsigned int)apcParam) < 65536)
  370. return E_OUTOFMEMORY;
  371. if (0 == QueueUserAPC(QueueApcCallback, threadHandle, (ULONG_PTR)apcParam))
  372. {
  373. unsigned long errorCode = GetLastError();
  374. delete(apcParam);
  375. return HRESULT_FROM_WIN32(errorCode);
  376. }
  377. return S_OK;
  378. }
  379. void CALLBACK DispatchCallbackApc::QueueApcCallback(ULONG_PTR user)
  380. {
  381. DispatchCallbackApcParam *apcParam = (DispatchCallbackApcParam*)user;
  382. if (NULL == apcParam)
  383. return;
  384. DispatchCallbackApc *apc = apcParam->GetApc();
  385. if (NULL != apc)
  386. apc->Call(apcParam->GetDispatch()),
  387. delete(apcParam);
  388. }
  389. DispatchCallbackApcParam::DispatchCallbackApcParam(IDispatch *_dispatch, DispatchCallbackApc *_apc)
  390. : dispatch(_dispatch), apc(_apc)
  391. {
  392. if (NULL != dispatch && ((unsigned long)dispatch >= 65536))
  393. dispatch->AddRef();
  394. if (NULL != apc && ((unsigned long)apc >= 65536))
  395. apc->AddRef();
  396. }
  397. DispatchCallbackApcParam::~DispatchCallbackApcParam()
  398. {
  399. if (NULL != dispatch)
  400. dispatch->Release();
  401. if (NULL != apc)
  402. apc->Release();
  403. }
  404. IDispatch *DispatchCallbackApcParam::GetDispatch()
  405. {
  406. return dispatch;
  407. }
  408. DispatchCallbackApc *DispatchCallbackApcParam::GetApc()
  409. {
  410. return apc;
  411. }