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.

478 lines
12 KiB

  1. #include "priv.h"
  2. #include "dspsprt.h"
  3. #include "msieftp.h"
  4. #define TF_IDISPATCH 0
  5. /*
  6. * CImpIDispatch::CImpIDispatch
  7. * CImpIDispatch::~CImpIDispatch
  8. *
  9. * Parameters (Constructor):
  10. * piid guid this IDispatch implementation is for
  11. * we call QueryInterface to get the interface
  12. */
  13. CImpIDispatch::CImpIDispatch(const IID * piid)
  14. {
  15. // TraceMsg(TF_ALWAYS, "ctor CImpIDispatch %x", this);
  16. m_piid = piid;
  17. ASSERT(NULL==m_pITINeutral);
  18. ASSERT(NULL==m_pdisp);
  19. return;
  20. }
  21. CImpIDispatch::~CImpIDispatch(void)
  22. {
  23. // TraceMsg(TF_ALWAYS, "dtor CImpIDispatch %x", this);
  24. if (m_pITINeutral)
  25. {
  26. m_pITINeutral->Release();
  27. m_pITINeutral = NULL;
  28. }
  29. return;
  30. }
  31. /*
  32. * CImpIDispatch::GetTypeInfoCount
  33. *
  34. * Purpose:
  35. * Returns the number of type information (ITypeInfo) interfaces
  36. * that the object provides (0 or 1).
  37. *
  38. * Parameters:
  39. * pctInfo UINT * to the location to receive
  40. * the count of interfaces.
  41. *
  42. * Return Value:
  43. * HRESULT NOERROR or a general error code.
  44. */
  45. STDMETHODIMP CImpIDispatch::GetTypeInfoCount(UINT *pctInfo)
  46. {
  47. //We implement GetTypeInfo so return 1
  48. *pctInfo=1;
  49. return NOERROR;
  50. }
  51. //
  52. // helper function for pulling ITypeInfo out of our typelib
  53. //
  54. HRESULT MSIEFTPGetTypeInfo(LCID lcid, UUID uuid, ITypeInfo **ppITypeInfo)
  55. {
  56. HRESULT hr;
  57. ITypeLib *pITypeLib;
  58. // Just in case we can't find the type library anywhere
  59. *ppITypeInfo = NULL;
  60. /*
  61. * The type libraries are registered under 0 (neutral),
  62. * 7 (German), and 9 (English) with no specific sub-
  63. * language, which would make them 407 or 409 and such.
  64. * If you are sensitive to sub-languages, then use the
  65. * full LCID instead of just the LANGID as done here.
  66. */
  67. hr=LoadRegTypeLib(LIBID_MSIEFTPLib, 1, 0, PRIMARYLANGID(lcid), &pITypeLib);
  68. /*
  69. * If LoadRegTypeLib fails, try loading directly with
  70. * LoadTypeLib, which will register the library for us.
  71. * Note that there's no default case here because the
  72. * prior switch will have filtered lcid already.
  73. *
  74. * NOTE: You should prepend your DIR registry key to the
  75. * .TLB name so you don't depend on it being it the PATH.
  76. * This sample will be updated later to reflect this.
  77. */
  78. if (FAILED(hr))
  79. {
  80. OLECHAR wszPath[MAX_PATH];
  81. #ifdef UNICODE
  82. GetModuleFileName(HINST_THISDLL, wszPath, ARRAYSIZE(wszPath));
  83. #else
  84. TCHAR szPath[MAX_PATH];
  85. GetModuleFileName(HINST_THISDLL, szPath, ARRAYSIZE(szPath));
  86. MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, ARRAYSIZE(wszPath));
  87. #endif
  88. switch (PRIMARYLANGID(lcid))
  89. {
  90. case LANG_NEUTRAL:
  91. case LANG_ENGLISH:
  92. hr=LoadTypeLib(wszPath, &pITypeLib);
  93. break;
  94. }
  95. }
  96. if (SUCCEEDED(hr))
  97. {
  98. //Got the type lib, get type info for the interface we want
  99. hr=pITypeLib->GetTypeInfoOfGuid(uuid, ppITypeInfo);
  100. pITypeLib->Release();
  101. }
  102. return(hr);
  103. }
  104. /*
  105. * CImpIDispatch::GetTypeInfo
  106. *
  107. * Purpose:
  108. * Retrieves type information for the automation interface. This
  109. * is used anywhere that the right ITypeInfo interface is needed
  110. * for whatever LCID is applicable. Specifically, this is used
  111. * from within GetIDsOfNames and Invoke.
  112. *
  113. * Parameters:
  114. * itInfo UINT reserved. Must be zero.
  115. * lcid LCID providing the locale for the type
  116. * information. If the object does not support
  117. * localization, this is ignored.
  118. * ppITypeInfo ITypeInfo ** in which to store the ITypeInfo
  119. * interface for the object.
  120. *
  121. * Return Value:
  122. * HRESULT NOERROR or a general error code.
  123. */
  124. STDMETHODIMP CImpIDispatch::GetTypeInfo(UINT itInfo, LCID lcid
  125. , ITypeInfo **ppITypeInfo)
  126. {
  127. ITypeInfo **ppITI;
  128. *ppITypeInfo=NULL;
  129. if (0!=itInfo)
  130. return(TYPE_E_ELEMENTNOTFOUND);
  131. #if 1
  132. // docs say we can ignore lcid if we support only one LCID
  133. // we don't have to return DISP_E_UNKNOWNLCID if we're *ignoring* it
  134. ppITI = &m_pITINeutral;
  135. #else
  136. /*
  137. * Since we returned one from GetTypeInfoCount, this function
  138. * can be called for a specific locale. We support English
  139. * and neutral (defaults to English) locales. Anything
  140. * else is an error.
  141. *
  142. * After this switch statement, ppITI will point to the proper
  143. * member pITypeInfo. If *ppITI is NULL, we know we need to
  144. * load type information, retrieve the ITypeInfo we want, and
  145. * then store it in *ppITI.
  146. */
  147. switch (PRIMARYLANGID(lcid))
  148. {
  149. case LANG_NEUTRAL:
  150. case LANG_ENGLISH:
  151. ppITI=&m_pITINeutral;
  152. break;
  153. default:
  154. return(DISP_E_UNKNOWNLCID);
  155. }
  156. #endif
  157. //Load a type lib if we don't have the information already.
  158. if (NULL==*ppITI)
  159. {
  160. HRESULT hr;
  161. ITypeInfo *pITIDisp;
  162. hr = MSIEFTPGetTypeInfo(lcid, *m_piid, &pITIDisp);
  163. if (SUCCEEDED(hr))
  164. {
  165. HRESULT hrT;
  166. HREFTYPE hrefType;
  167. // All our IDispatch implementations are DUAL. GetTypeInfoOfGuid
  168. // returns the ITypeInfo of the IDispatch-part only. We need to
  169. // find the ITypeInfo for the dual interface-part.
  170. //
  171. hrT = pITIDisp->GetRefTypeOfImplType(0xffffffff, &hrefType);
  172. if (SUCCEEDED(hrT))
  173. {
  174. hrT = pITIDisp->GetRefTypeInfo(hrefType, ppITI);
  175. }
  176. ASSERT(SUCCEEDED(hrT));
  177. if (FAILED(hrT))
  178. {
  179. // I suspect GetRefTypeOfImplType may fail if someone uses
  180. // CImpIDispatch on a non-dual interface. In this case the
  181. // ITypeInfo we got above is just fine to use.
  182. //
  183. *ppITI = pITIDisp;
  184. }
  185. else
  186. {
  187. pITIDisp->Release();
  188. }
  189. }
  190. if (FAILED(hr))
  191. return hr;
  192. }
  193. /*
  194. * Note: the type library is still loaded since we have
  195. * an ITypeInfo from it.
  196. */
  197. (*ppITI)->AddRef();
  198. *ppITypeInfo=*ppITI;
  199. return NOERROR;
  200. }
  201. /*
  202. * CImpIDispatch::GetIDsOfNames
  203. *
  204. * Purpose:
  205. * Converts text names into DISPIDs to pass to Invoke
  206. *
  207. * Parameters:
  208. * riid REFIID reserved. Must be IID_NULL.
  209. * rgszNames OLECHAR ** pointing to the array of names to be
  210. * mapped.
  211. * cNames UINT number of names to be mapped.
  212. * lcid LCID of the locale.
  213. * rgDispID DISPID * caller allocated array containing IDs
  214. * corresponging to those names in rgszNames.
  215. *
  216. * Return Value:
  217. * HRESULT NOERROR or a general error code.
  218. */
  219. STDMETHODIMP CImpIDispatch::GetIDsOfNames(REFIID riid
  220. , OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispID)
  221. {
  222. HRESULT hr;
  223. ITypeInfo *pTI;
  224. if (IID_NULL!=riid)
  225. return(DISP_E_UNKNOWNINTERFACE);
  226. //Get the right ITypeInfo for lcid.
  227. hr=GetTypeInfo(0, lcid, &pTI);
  228. if (SUCCEEDED(hr))
  229. {
  230. hr=pTI->GetIDsOfNames(rgszNames, cNames, rgDispID);
  231. pTI->Release();
  232. }
  233. #ifdef DEBUG
  234. char szParam[MAX_PATH] = "";
  235. if (cNames >= 1)
  236. {
  237. WideCharToMultiByte(CP_ACP, 0,
  238. *rgszNames, -1,
  239. szParam, ARRAYSIZE(szParam), NULL, NULL);
  240. }
  241. TraceMsg(TF_IDISPATCH, "CImpIDispatch::GetIDsOfNames(%s = %x) called hres(%x)",
  242. szParam, *rgDispID, hr);
  243. #endif
  244. return hr;
  245. }
  246. /*
  247. * CImpIDispatch::Invoke
  248. *
  249. * Purpose:
  250. * Calls a method in the dispatch interface or manipulates a
  251. * property.
  252. *
  253. * Parameters:
  254. * dispID DISPID of the method or property of interest.
  255. * riid REFIID reserved, must be IID_NULL.
  256. * lcid LCID of the locale.
  257. * wFlags USHORT describing the context of the invocation.
  258. * pDispParams DISPPARAMS * to the array of arguments.
  259. * pVarResult VARIANT * in which to store the result. Is
  260. * NULL if the caller is not interested.
  261. * pExcepInfo EXCEPINFO * to exception information.
  262. * puArgErr UINT * in which to store the index of an
  263. * invalid parameter if DISP_E_TYPEMISMATCH
  264. * is returned.
  265. *
  266. * Return Value:
  267. * HRESULT NOERROR or a general error code.
  268. */
  269. STDMETHODIMP CImpIDispatch::Invoke(DISPID dispID, REFIID riid
  270. , LCID lcid, unsigned short wFlags, DISPPARAMS *pDispParams
  271. , VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
  272. {
  273. ITypeInfo *pTI;
  274. HRESULT hr;
  275. //riid is supposed to be IID_NULL always
  276. if (IID_NULL!=riid)
  277. return(DISP_E_UNKNOWNINTERFACE);
  278. // make sure we have an interface to hand off to Invoke
  279. if (NULL == m_pdisp)
  280. {
  281. hr=QueryInterface(*m_piid, (LPVOID*)&m_pdisp);
  282. if (!EVAL(SUCCEEDED(hr)))
  283. return hr;
  284. // don't hold a refcount on ourself
  285. m_pdisp->Release();
  286. }
  287. //Get the ITypeInfo for lcid
  288. hr=GetTypeInfo(0, lcid, &pTI);
  289. if (SUCCEEDED(hr))
  290. {
  291. //Clear exceptions
  292. SetErrorInfo(0L, NULL);
  293. //This is exactly what DispInvoke does--so skip the overhead.
  294. hr=pTI->Invoke(m_pdisp, dispID, wFlags
  295. , pDispParams, pVarResult, pExcepInfo, puArgErr);
  296. pTI->Release();
  297. }
  298. return hr;
  299. }
  300. /*
  301. * CImpIDispatch::Exception
  302. *
  303. * Purpose:
  304. * Raises an exception for CImpIDispatch::Invoke from within
  305. * ITypeInfo::Invoke using the CreateErrorInfo API and the
  306. * ICreateErrorInfo interface.
  307. *
  308. * Note that this method doesn't allow for deferred filling
  309. * of an EXCEPINFO structure.
  310. *
  311. * Parameters:
  312. * wException WORD exception code.
  313. */
  314. void CImpIDispatch::Exception(WORD wException)
  315. {
  316. #if 0 // nobody calls this
  317. ICreateErrorInfo *pICreateErr;
  318. BOOL fSuccess;
  319. LPTSTR psz;
  320. LPOLESTR pszHelp;
  321. UINT idsSource;
  322. UINT idsException;
  323. DWORD dwHelpID;
  324. /*
  325. * Thread-safe exception handling means that we call
  326. * CreateErrorInfo which gives us an ICreateErrorInfo pointer
  327. * that we then use to set the error information (basically
  328. * to set the fields of an EXCEPINFO structure. We then
  329. * call SetErrorInfo to attach this error to the current
  330. * thread. ITypeInfo::Invoke will look for this when it
  331. * returns from whatever function was invokes by calling
  332. * GetErrorInfo.
  333. */
  334. //Not much we can do if this fails.
  335. if (FAILED(CreateErrorInfo(&pICreateErr)))
  336. return;
  337. psz=(LPTSTR)LocalAlloc(LPTR, 1024*sizeof(TCHAR));
  338. // psz is a buffer to do LoadString()s into -- if we didn't
  339. // get one then we won't get our error strings, so bail.
  340. if (NULL==psz)
  341. {
  342. pICreateErr->Release();
  343. return;
  344. }
  345. fSuccess=TRUE;
  346. // typically you'd do a switch here on all the exception ids wException
  347. // and fill in pszHelp, dwHelpID, idsSource, and idsException.
  348. // if you mapped the exception id to valid strings, the code
  349. // below will fill in the ICreateErr interface
  350. //
  351. switch (wException)
  352. {
  353. default:
  354. fSuccess = FALSE;
  355. }
  356. if (fSuccess)
  357. {
  358. HRESULT hr;
  359. IErrorInfo *pIErr;
  360. /*
  361. * If you have a help file, call the functions
  362. * ICreateErrorInfo::SetHelpFile and
  363. * ICreateErrorInfo::SetHelpContext as well. If you
  364. * set the help file to NULL the context is ignored.
  365. */
  366. pICreateErr->SetHelpFile(pszHelp);
  367. pICreateErr->SetHelpContext(dwHelpID);
  368. #ifndef UNICODE
  369. OLECHAR szTemp[256];
  370. LoadString(HINST_THISDLL, idsSource, psz, 256);
  371. MultiByteToWideChar(CP_ACP, 0, psz, -1, szTemp, 256);
  372. pICreateErr->SetSource(szTemp);
  373. LoadString(HINST_THISDLL, idsException, psz, 256);
  374. MultiByteToWideChar(CP_ACP, 0, psz, -1, szTemp, 256);
  375. pICreateErr->SetDescription(szTemp);
  376. #else
  377. LoadString(HINST_THISDLL, idsSource, psz, 1024);
  378. pICreateErr->SetSource(psz);
  379. LoadString(HINST_THISDLL, idsException, psz, 1024);
  380. pICreateErr->SetDescription(psz);
  381. #endif
  382. hr=pICreateErr->QueryInterface(IID_IErrorInfo
  383. , (LPVOID*)&pIErr);
  384. if (SUCCEEDED(hr))
  385. {
  386. SetErrorInfo(0L, pIErr);
  387. pIErr->Release();
  388. }
  389. }
  390. LocalFree(psz);
  391. //SetErrorInfo holds the object's IErrorInfo
  392. pICreateErr->Release();
  393. #endif
  394. }