Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

255 lines
7.0 KiB

  1. // NATDPMS.cpp : Implementation of CNATEventManager
  2. #include "stdafx.h"
  3. #pragma hdrstop
  4. #include "NATEM.h"
  5. /////////////////////////////////////////////////////////////////////////////
  6. // CNATEventManager
  7. STDMETHODIMP CNATEventManager::put_ExternalIPAddressCallback(IUnknown * pUnk)
  8. {
  9. NAT_API_ENTER
  10. if (!m_spUPSCP)
  11. return E_UNEXPECTED;
  12. if (!pUnk)
  13. return E_INVALIDARG;
  14. // create a IUPnPServiceCallback
  15. CComObject<CExternalIPAddressCallback> * pEIAC = NULL;
  16. HRESULT hr = CComObject<CExternalIPAddressCallback>::CreateInstance (&pEIAC);
  17. if (pEIAC) {
  18. pEIAC->AddRef();
  19. hr = pEIAC->Initialize (pUnk);
  20. if (SUCCEEDED(hr)) {
  21. CComPtr<IUnknown> spUnk = NULL;
  22. hr = pEIAC->QueryInterface (__uuidof(IUnknown), (void**)&spUnk);
  23. if (spUnk)
  24. hr = AddTransientCallback (spUnk);
  25. }
  26. pEIAC->Release();
  27. }
  28. return hr;
  29. NAT_API_LEAVE
  30. }
  31. STDMETHODIMP CNATEventManager::put_NumberOfEntriesCallback(IUnknown * pUnk)
  32. {
  33. NAT_API_ENTER
  34. if (!m_spUPSCP)
  35. return E_UNEXPECTED;
  36. if (!pUnk)
  37. return E_INVALIDARG;
  38. // create a IUPnPServiceCallback
  39. CComObject<CNumberOfEntriesCallback> * pEIAC = NULL;
  40. HRESULT hr = CComObject<CNumberOfEntriesCallback>::CreateInstance (&pEIAC);
  41. if (pEIAC) {
  42. pEIAC->AddRef();
  43. hr = pEIAC->Initialize (pUnk);
  44. if (SUCCEEDED(hr)) {
  45. CComPtr<IUnknown> spUnk = NULL;
  46. hr = pEIAC->QueryInterface (__uuidof(IUnknown), (void**)&spUnk);
  47. if (spUnk)
  48. hr = AddTransientCallback (spUnk);
  49. }
  50. pEIAC->Release();
  51. }
  52. return hr;
  53. NAT_API_LEAVE
  54. }
  55. // cut-n-pasted from ...\nt\net\upnp\upnp\api\upnpservice.cpp
  56. // fixed up leaks
  57. HRESULT
  58. HrInvokeDispatchCallback(IDispatch * pdispCallback, // user-supplied IDispatch
  59. LPCWSTR pszCallbackType, // L"ServiceDied", or L"StateVariableChanged"
  60. IDispatch * pdispThis, // IDispatch of service
  61. LPCWSTR pszStateVarName, // name of variable
  62. VARIANT * lpvarValue) // new value of variable
  63. {
  64. HRESULT hr = S_OK;
  65. VARIANT ary_vaArgs[4];
  66. ::VariantInit(&ary_vaArgs[0]);
  67. ::VariantInit(&ary_vaArgs[1]);
  68. ::VariantInit(&ary_vaArgs[2]);
  69. ::VariantInit(&ary_vaArgs[3]);
  70. // Fourth argument is the value.
  71. if (lpvarValue)
  72. {
  73. hr = VariantCopy(&ary_vaArgs[0], lpvarValue);
  74. if (FAILED(hr))
  75. {
  76. ::VariantInit(&ary_vaArgs[0]);
  77. goto Cleanup;
  78. }
  79. }
  80. // Third argument is the state variable name.
  81. // Copy this in case our caller parties on it.
  82. if (pszStateVarName)
  83. {
  84. BSTR bstrVarName;
  85. bstrVarName = ::SysAllocString(pszStateVarName);
  86. if (!bstrVarName)
  87. {
  88. hr = E_OUTOFMEMORY;
  89. goto Cleanup;
  90. }
  91. V_VT(&ary_vaArgs[1]) = VT_BSTR;
  92. V_BSTR(&ary_vaArgs[1]) = bstrVarName;
  93. }
  94. // Second argument is the pointer to the service object.
  95. pdispThis->AddRef();
  96. V_VT(&ary_vaArgs[2]) = VT_DISPATCH;
  97. V_DISPATCH(&ary_vaArgs[2]) = pdispThis;
  98. // First argument is the string defining the type
  99. // of callback.
  100. {
  101. BSTR bstrCallbackType;
  102. bstrCallbackType = ::SysAllocString(pszCallbackType);
  103. if (!bstrCallbackType)
  104. {
  105. hr = E_OUTOFMEMORY;
  106. goto Cleanup;
  107. }
  108. V_VT(&ary_vaArgs[3]) = VT_BSTR;
  109. V_BSTR(&ary_vaArgs[3]) = bstrCallbackType;
  110. }
  111. {
  112. VARIANT vaResult;
  113. DISPPARAMS dispParams = {ary_vaArgs, NULL, 4, 0};
  114. VariantInit(&vaResult);
  115. hr = pdispCallback->Invoke(0,
  116. IID_NULL,
  117. LOCALE_USER_DEFAULT,
  118. DISPATCH_METHOD,
  119. &dispParams,
  120. &vaResult,
  121. NULL,
  122. NULL);
  123. if (FAILED(hr))
  124. {
  125. }
  126. }
  127. Cleanup:
  128. if ((VT_ARRAY | VT_UI1) == V_VT(&ary_vaArgs[0]))
  129. {
  130. SafeArrayDestroy(V_ARRAY(&ary_vaArgs[0]));
  131. }
  132. else
  133. {
  134. ::VariantClear(&ary_vaArgs[0]);
  135. }
  136. ::VariantClear(&ary_vaArgs[1]);
  137. ::VariantClear(&ary_vaArgs[2]);
  138. ::VariantClear(&ary_vaArgs[3]);
  139. return hr;
  140. }
  141. HRESULT Callback (IUnknown * punk, IUPnPService *pus, LPCWSTR pcwszStateVarName, VARIANT vaValue)
  142. {
  143. /*
  144. IUnknown is either INATExternalIPAddressCallback,
  145. INATNumberOfEntriesCallback, or an IDispatch.
  146. If the latter, call "Invoke" with dispid 0, and all the rest of
  147. the parameters are the same as for StateVariableChanged.
  148. Er, except there's an extra BSTR parameter specifying whether
  149. it's a variable state change or a service died thingy.
  150. */
  151. CComPtr<IDispatch> spDisp = NULL;
  152. punk->QueryInterface (__uuidof(IDispatch), (void**)&spDisp);
  153. if (spDisp) {
  154. CComPtr<IDispatch> spDispService = NULL;
  155. pus->QueryInterface (__uuidof(IDispatch), (void**)&spDispService);
  156. if (spDispService) {
  157. HrInvokeDispatchCallback (spDisp,
  158. L"VARIABLE_UPDATE",
  159. spDispService,
  160. pcwszStateVarName,
  161. &vaValue);
  162. return S_OK;
  163. }
  164. }
  165. // UPnP ignores the error
  166. return S_OK;
  167. }
  168. HRESULT CExternalIPAddressCallback::StateVariableChanged (IUPnPService *pus, LPCWSTR pcwszStateVarName, VARIANT vaValue)
  169. {
  170. NAT_API_ENTER
  171. if (wcscmp (pcwszStateVarName, L"ExternalIPAddress"))
  172. return S_OK; // not interested
  173. CComPtr<INATExternalIPAddressCallback> spEIAC = NULL;
  174. m_spUnk->QueryInterface (__uuidof(INATExternalIPAddressCallback), (void**)&spEIAC);
  175. if (spEIAC) {
  176. _ASSERT (V_VT (&vaValue) == VT_BSTR);
  177. spEIAC->NewExternalIPAddress (V_BSTR (&vaValue));
  178. return S_OK;
  179. }
  180. return Callback (m_spUnk, pus, pcwszStateVarName, vaValue);
  181. NAT_API_LEAVE
  182. }
  183. HRESULT CExternalIPAddressCallback::ServiceInstanceDied(IUPnPService *pus)
  184. {
  185. return S_OK; // not interested
  186. }
  187. HRESULT CNumberOfEntriesCallback::StateVariableChanged (IUPnPService *pus, LPCWSTR pcwszStateVarName, VARIANT vaValue)
  188. {
  189. NAT_API_ENTER
  190. if (wcscmp (pcwszStateVarName, L"PortMappingNumberOfEntries"))
  191. return S_OK; // not interested
  192. CComPtr<INATNumberOfEntriesCallback> spNOEC = NULL;
  193. m_spUnk->QueryInterface (__uuidof(INATNumberOfEntriesCallback), (void**)&spNOEC);
  194. if (spNOEC) {
  195. _ASSERT ((V_VT (&vaValue) == VT_I4) ||
  196. (V_VT (&vaValue) == VT_UI4) );
  197. spNOEC->NewNumberOfEntries (V_I4 (&vaValue));
  198. return S_OK;
  199. }
  200. return Callback (m_spUnk, pus, pcwszStateVarName, vaValue);
  201. NAT_API_LEAVE
  202. }
  203. HRESULT CNumberOfEntriesCallback::ServiceInstanceDied(IUPnPService *pus)
  204. {
  205. return S_OK; // not interested
  206. }