DispatchProxy.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.ComIntegration
  5. {
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Diagnostics;
  9. using System.Runtime;
  10. using System.Runtime.InteropServices;
  11. using System.ServiceModel.Description;
  12. using System.ServiceModel.Diagnostics;
  13. using System.ServiceModel.Dispatcher;
  14. class DispatchProxy : IPseudoDispatch, IDisposable
  15. {
  16. ContractDescription contract;
  17. IProvideChannelBuilderSettings channelBuilderSettings;
  18. Dictionary<UInt32, string> dispToName = new Dictionary<UInt32, string>();
  19. Dictionary<string, UInt32> nameToDisp = new Dictionary<string, UInt32>();
  20. Dictionary<UInt32, MethodInfo> dispToOperationDescription = new Dictionary<UInt32, MethodInfo>();
  21. private DispatchProxy(ContractDescription contract, IProvideChannelBuilderSettings channelBuilderSettings)
  22. {
  23. if (channelBuilderSettings == null)
  24. {
  25. throw Fx.AssertAndThrow("channelBuilderSettings cannot be null cannot be null");
  26. }
  27. if (contract == null)
  28. {
  29. throw Fx.AssertAndThrow("contract cannot be null");
  30. }
  31. this.channelBuilderSettings = channelBuilderSettings;
  32. this.contract = contract;
  33. ProcessContractDescription();
  34. ComPlusDispatchMethodTrace.Trace(TraceEventType.Verbose, TraceCode.ComIntegrationDispatchMethod,
  35. SR.TraceCodeComIntegrationDispatchMethod, dispToOperationDescription);
  36. }
  37. internal static ComProxy Create(IntPtr outer, ContractDescription contract, IProvideChannelBuilderSettings channelBuilderSettings)
  38. {
  39. DispatchProxy proxy = null;
  40. IntPtr inner = IntPtr.Zero;
  41. ComProxy comProxy = null;
  42. try
  43. {
  44. proxy = new DispatchProxy(contract, channelBuilderSettings);
  45. inner = OuterProxyWrapper.CreateDispatchProxy(outer, proxy);
  46. comProxy = new ComProxy(inner, proxy);
  47. return comProxy;
  48. }
  49. finally
  50. {
  51. if (comProxy == null)
  52. {
  53. if (proxy != null)
  54. {
  55. ((IDisposable)proxy).Dispose();
  56. }
  57. if (inner != IntPtr.Zero)
  58. {
  59. Marshal.Release(inner);
  60. }
  61. }
  62. }
  63. }
  64. [Serializable]
  65. internal class ParamInfo
  66. {
  67. public int inIndex;
  68. public int outIndex;
  69. public string name;
  70. public Type type;
  71. public ParamInfo()
  72. {
  73. inIndex = -1;
  74. outIndex = -1;
  75. }
  76. }
  77. internal class MethodInfo
  78. {
  79. public OperationDescription opDesc;
  80. public List<ParamInfo> paramList;
  81. public Dictionary<uint, ParamInfo> dispIdToParamInfo;
  82. public ParamInfo ReturnVal = null;
  83. public MethodInfo(OperationDescription opDesc)
  84. {
  85. this.opDesc = opDesc;
  86. paramList = new List<ParamInfo>();
  87. dispIdToParamInfo = new Dictionary<uint, ParamInfo>();
  88. }
  89. }
  90. void ProcessContractDescription()
  91. {
  92. UInt32 dispIndex = 10;
  93. Dictionary<string, ParamInfo> paramDictionary = null;
  94. foreach (OperationDescription opDesc in contract.Operations)
  95. {
  96. dispToName[dispIndex] = opDesc.Name;
  97. nameToDisp[opDesc.Name] = dispIndex;
  98. MethodInfo methodInfo = null;
  99. methodInfo = new MethodInfo(opDesc);
  100. dispToOperationDescription[dispIndex++] = methodInfo;
  101. paramDictionary = new Dictionary<string, ParamInfo>();
  102. bool inVars = true;
  103. inVars = true;
  104. int paramCount = 0;
  105. foreach (MessageDescription msgDesc in opDesc.Messages)
  106. {
  107. paramCount = 0;
  108. if (msgDesc.Body.ReturnValue != null)
  109. {
  110. if (string.IsNullOrEmpty(msgDesc.Body.ReturnValue.BaseType))
  111. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.CannotResolveTypeForParamInMessageDescription, "ReturnValue", msgDesc.Body.WrapperName, msgDesc.Body.WrapperNamespace), HR.DISP_E_MEMBERNOTFOUND));
  112. msgDesc.Body.ReturnValue.Type = Type.GetType(msgDesc.Body.ReturnValue.BaseType);
  113. }
  114. foreach (MessagePartDescription param in msgDesc.Body.Parts)
  115. {
  116. UInt32 dispID = 0;
  117. ParamInfo paramInfo = null;
  118. paramInfo = null;
  119. if (!nameToDisp.TryGetValue(param.Name, out dispID))
  120. {
  121. dispToName[dispIndex] = param.Name;
  122. nameToDisp[param.Name] = dispIndex;
  123. dispID = dispIndex;
  124. dispIndex++;
  125. }
  126. if (!paramDictionary.TryGetValue(param.Name, out paramInfo))
  127. {
  128. paramInfo = new ParamInfo();
  129. methodInfo.paramList.Add(paramInfo);
  130. methodInfo.dispIdToParamInfo[dispID] = paramInfo;
  131. if (string.IsNullOrEmpty(param.BaseType))
  132. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.CannotResolveTypeForParamInMessageDescription, param.Name, msgDesc.Body.WrapperName, msgDesc.Body.WrapperNamespace), HR.DISP_E_MEMBERNOTFOUND));
  133. paramInfo.type = Type.GetType(param.BaseType, true);
  134. paramInfo.name = param.Name;
  135. paramDictionary[param.Name] = paramInfo;
  136. param.Index = paramCount;
  137. }
  138. param.Type = paramInfo.type;
  139. if (inVars)
  140. {
  141. paramInfo.inIndex = paramCount;
  142. }
  143. else
  144. {
  145. paramInfo.outIndex = paramCount;
  146. }
  147. paramCount++;
  148. }
  149. inVars = false;
  150. }
  151. }
  152. }
  153. void IPseudoDispatch.GetIDsOfNames(UInt32 cNames, // size_is param for rgszNames
  154. [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 0)] string[] rgszNames,
  155. IntPtr pDispID)
  156. {
  157. for (int index = 0; index < cNames; index++)
  158. {
  159. UInt32 dispID;
  160. if (!nameToDisp.TryGetValue(rgszNames[index], out dispID))
  161. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.OperationNotFound, rgszNames[index]), HR.DISP_E_UNKNOWNNAME));
  162. Marshal.WriteInt32(pDispID, index * sizeof(int), (int)dispID);
  163. }
  164. }
  165. int IPseudoDispatch.Invoke(
  166. UInt32 dispIdMember,
  167. UInt32 cArgs,
  168. UInt32 cNamedArgs,
  169. IntPtr rgvarg,
  170. [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] UInt32[] rgdispidNamedArgs,
  171. IntPtr pVarResult,
  172. IntPtr pExcepInfo,
  173. out UInt32 pArgErr
  174. )
  175. {
  176. pArgErr = 0;
  177. try
  178. {
  179. if (cNamedArgs > 0)
  180. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.NamedArgsNotSupported), HR.DISP_E_BADPARAMCOUNT));
  181. MethodInfo mInfo = null;
  182. if (!dispToOperationDescription.TryGetValue(dispIdMember, out mInfo))
  183. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.BadDispID, dispIdMember), HR.DISP_E_MEMBERNOTFOUND));
  184. object[] ins = null;
  185. object[] outs = null;
  186. string action = null;
  187. if (mInfo.paramList.Count != cArgs)
  188. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.BadDispID, dispIdMember), HR.DISP_E_BADPARAMCOUNT));
  189. ins = new object[mInfo.opDesc.Messages[0].Body.Parts.Count];
  190. outs = new object[mInfo.opDesc.Messages[1].Body.Parts.Count];
  191. if (cArgs > 0)
  192. {
  193. if (mInfo.opDesc.Messages[0].Body.Parts.Count > 0)
  194. {
  195. for (int index = 0; index < mInfo.opDesc.Messages[0].Body.Parts.Count; index++)
  196. ins[index] = null;
  197. }
  198. if (!mInfo.opDesc.IsOneWay && (mInfo.opDesc.Messages[1].Body.Parts.Count > 0))
  199. {
  200. for (int index = 0; index < mInfo.opDesc.Messages[1].Body.Parts.Count; index++)
  201. outs[index] = null;
  202. }
  203. }
  204. action = mInfo.opDesc.Messages[0].Action;
  205. // First we take care of positional arguments
  206. int inCount = 0;
  207. for (int index = 0; index < cArgs; index++)
  208. {
  209. if (mInfo.paramList[index].inIndex != -1)
  210. {
  211. try
  212. {
  213. object val = null;
  214. if (!mInfo.paramList[index].type.IsArray)
  215. val = FetchVariant(rgvarg, (int)(cArgs - index - 1), mInfo.paramList[index].type);
  216. else
  217. val = FetchVariants(rgvarg, (int)(cArgs - index - 1), mInfo.paramList[index].type);
  218. ins[mInfo.paramList[index].inIndex] = val;
  219. inCount++;
  220. }
  221. catch (ArgumentNullException)
  222. {
  223. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(SR.GetString(SR.VariantArrayNull, cArgs - index - 1));
  224. }
  225. }
  226. }
  227. if (inCount != ins.Length)
  228. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.BadParamCount), HR.DISP_E_BADPARAMCOUNT));
  229. object result = null;
  230. try
  231. {
  232. result = SendMessage(mInfo.opDesc, action, ins, outs);
  233. }
  234. catch (Exception e)
  235. {
  236. if (Fx.IsFatal(e))
  237. throw;
  238. if (pExcepInfo != IntPtr.Zero)
  239. {
  240. System.Runtime.InteropServices.ComTypes.EXCEPINFO exceptionInfo = new System.Runtime.InteropServices.ComTypes.EXCEPINFO();
  241. e = e.GetBaseException();
  242. exceptionInfo.bstrDescription = e.Message;
  243. exceptionInfo.bstrSource = e.Source;
  244. exceptionInfo.scode = Marshal.GetHRForException(e);
  245. Marshal.StructureToPtr(exceptionInfo, pExcepInfo, false);
  246. }
  247. return HR.DISP_E_EXCEPTION;
  248. }
  249. if (!mInfo.opDesc.IsOneWay)
  250. {
  251. if (outs != null)
  252. {
  253. bool[] filled = new bool[outs.Length];
  254. for (UInt32 index = 0; index < filled.Length; index++)
  255. filled[index] = false;
  256. for (int index = 0; index < cArgs; index++)
  257. {
  258. if (mInfo.paramList[index].outIndex != -1)
  259. {
  260. try
  261. {
  262. if (IsByRef(rgvarg, (int)(cArgs - index - 1)))
  263. {
  264. PopulateByRef(rgvarg, (int)(cArgs - index - 1), outs[mInfo.paramList[index].outIndex]);
  265. }
  266. }
  267. catch (ArgumentNullException)
  268. {
  269. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(SR.GetString(SR.VariantArrayNull, cArgs - index - 1));
  270. }
  271. filled[mInfo.paramList[index].outIndex] = true;
  272. }
  273. }
  274. }
  275. if ((result != null) && (pVarResult != IntPtr.Zero))
  276. {
  277. if (!result.GetType().IsArray)
  278. Marshal.GetNativeVariantForObject(result, pVarResult);
  279. else
  280. {
  281. Array arr = result as Array;
  282. Array arrDest = Array.CreateInstance(typeof(object), arr.Length);
  283. arr.CopyTo(arrDest, 0);
  284. Marshal.GetNativeVariantForObject(arrDest, pVarResult);
  285. }
  286. }
  287. }
  288. return HR.S_OK;
  289. }
  290. catch (Exception e)
  291. {
  292. if (Fx.IsFatal(e))
  293. throw;
  294. e = e.GetBaseException();
  295. return Marshal.GetHRForException(e);
  296. }
  297. }
  298. object SendMessage(OperationDescription opDesc, string action, object[] ins, object[] outs)
  299. {
  300. ProxyOperationRuntime operationRuntime = channelBuilderSettings.ServiceChannel.ClientRuntime.GetRuntime().GetOperationByName(opDesc.Name);
  301. if (operationRuntime == null)
  302. {
  303. throw Fx.AssertAndThrow("Operation runtime should not be null");
  304. }
  305. return channelBuilderSettings.ServiceChannel.Call(action, opDesc.IsOneWay, operationRuntime, ins, outs);
  306. }
  307. object FetchVariant(IntPtr baseArray, int index, Type type)
  308. {
  309. if (baseArray == IntPtr.Zero)
  310. {
  311. Fx.Assert("baseArray should not be null");
  312. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("baseArrray");
  313. }
  314. uint displacement = (uint)(index * Marshal.SizeOf(typeof(TagVariant)));
  315. object ret = Marshal.GetObjectForNativeVariant(GetDisp(baseArray, displacement));
  316. // this is neccessary because unfortunately the CLR is not very forthcomming when it comes
  317. // to dynamically converting integer types to other integer types due to boxing
  318. // the same goes for the array case
  319. if (type == typeof(Int32))
  320. {
  321. if (ret.GetType() == typeof(Int16))
  322. ret = (Int32)((Int16)ret);
  323. else if (ret.GetType() != typeof(Int32))
  324. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.UnsupportedConversion, ret.GetType(), type.GetElementType()), HR.DISP_E_TYPEMISMATCH));
  325. }
  326. else if (type == typeof(Int64))
  327. {
  328. if (ret.GetType() == typeof(Int16))
  329. ret = (Int64)((Int16)ret);
  330. else if (ret.GetType() == typeof(Int32))
  331. ret = (Int64)((Int32)ret);
  332. else if (ret.GetType() != typeof(Int64))
  333. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.UnsupportedConversion, ret.GetType(), type), HR.DISP_E_TYPEMISMATCH));
  334. }
  335. return ret;
  336. }
  337. object FetchVariants(IntPtr baseArray, int index, Type type)
  338. {
  339. if (baseArray == IntPtr.Zero)
  340. {
  341. Fx.Assert("baseArray should not be null");
  342. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("baseArrray");
  343. }
  344. uint displacement = (uint)(index * Marshal.SizeOf(typeof(TagVariant)));
  345. TagVariant varBase = (TagVariant)Marshal.PtrToStructure(GetDisp(baseArray, displacement), typeof(TagVariant));
  346. if ((varBase.vt & (ushort)(VarEnum.VT_VARIANT | VarEnum.VT_BYREF)) == 0)
  347. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.OnlyVariantAllowedByRef), HR.DISP_E_TYPEMISMATCH));
  348. TagVariant varActualVariant = (TagVariant)Marshal.PtrToStructure(varBase.ptr, typeof(TagVariant));
  349. if ((varActualVariant.vt & (ushort)(VarEnum.VT_VARIANT | VarEnum.VT_BYREF | VarEnum.VT_ARRAY)) == 0)
  350. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.OnlyByRefVariantSafeArraysAllowed), HR.DISP_E_TYPEMISMATCH));
  351. IntPtr ppArray = varActualVariant.ptr;
  352. IntPtr pSafeArray = (IntPtr)Marshal.PtrToStructure(ppArray, typeof(IntPtr));
  353. int dimensionsOfSafeArray = SafeNativeMethods.SafeArrayGetDim(pSafeArray);
  354. if (dimensionsOfSafeArray != 1)
  355. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.OnlyOneDimensionalSafeArraysAllowed), HR.DISP_E_TYPEMISMATCH));
  356. int sizeofElement = SafeNativeMethods.SafeArrayGetElemsize(pSafeArray);
  357. if (sizeofElement != Marshal.SizeOf(typeof(TagVariant)))
  358. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.OnlyVariantTypeElementsAllowed), HR.DISP_E_TYPEMISMATCH));
  359. int lBound = SafeNativeMethods.SafeArrayGetLBound(pSafeArray, 1);
  360. if (lBound > 0)
  361. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.OnlyZeroLBoundAllowed), HR.DISP_E_TYPEMISMATCH));
  362. int uBound = SafeNativeMethods.SafeArrayGetUBound(pSafeArray, 1);
  363. IntPtr pRawData = SafeNativeMethods.SafeArrayAccessData(pSafeArray);
  364. try
  365. {
  366. object[] objects = Marshal.GetObjectsForNativeVariants(pRawData, uBound + 1);
  367. Array arr = Array.CreateInstance(type.GetElementType(), objects.Length);
  368. if (objects.Length == 0)
  369. return arr;
  370. if (type.GetElementType() != typeof(Int32) && type.GetElementType() != typeof(Int64))
  371. {
  372. try
  373. {
  374. objects.CopyTo(arr, 0);
  375. }
  376. catch (Exception e)
  377. {
  378. if (Fx.IsFatal(e))
  379. throw;
  380. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.UnsupportedConversion, objects[0].GetType(), type.GetElementType()), HR.DISP_E_TYPEMISMATCH));
  381. }
  382. }
  383. else
  384. {
  385. if (type.GetElementType() == typeof(Int32))
  386. {
  387. for (int i = 0; i < objects.Length; i++)
  388. {
  389. if (objects[i].GetType() == typeof(Int16))
  390. arr.SetValue((Int32)((Int16)objects[i]), i);
  391. else if (objects[i].GetType() == typeof(Int32))
  392. arr.SetValue(objects[i], i);
  393. else
  394. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.UnsupportedConversion, objects[i].GetType(), type.GetElementType()), HR.DISP_E_TYPEMISMATCH));
  395. }
  396. }
  397. else
  398. {
  399. for (int i = 0; i < objects.Length; i++)
  400. {
  401. if (objects[i].GetType() == typeof(Int16))
  402. arr.SetValue((Int64)((Int16)objects[i]), i);
  403. else if (objects[i].GetType() == typeof(Int32))
  404. arr.SetValue((Int64)((Int32)objects[i]), i);
  405. else if (objects[i].GetType() == typeof(Int64))
  406. arr.SetValue(objects[i], i);
  407. else
  408. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.UnsupportedConversion, objects[i].GetType(), type.GetElementType()), HR.DISP_E_TYPEMISMATCH));
  409. }
  410. }
  411. }
  412. return arr;
  413. }
  414. finally
  415. {
  416. SafeNativeMethods.SafeArrayUnaccessData(pSafeArray);
  417. }
  418. }
  419. IntPtr GetDisp(IntPtr baseAddress, uint disp)
  420. {
  421. long address = (long)baseAddress;
  422. address += disp;
  423. return (IntPtr)address;
  424. }
  425. void PopulateByRef(IntPtr baseArray, int index, object val)
  426. {
  427. if (val != null)
  428. {
  429. if (baseArray == IntPtr.Zero)
  430. {
  431. Fx.Assert("baseArray should not be null");
  432. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("baseArrray");
  433. }
  434. uint displacement = (uint)(index * Marshal.SizeOf(typeof(TagVariant)));
  435. TagVariant var = (TagVariant)Marshal.PtrToStructure(GetDisp(baseArray, displacement), typeof(TagVariant));
  436. if ((var.vt & (ushort)VarEnum.VT_VARIANT) == 0)
  437. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.OnlyVariantAllowedByRef), HR.DISP_E_TYPEMISMATCH));
  438. if (!val.GetType().IsArray)
  439. Marshal.GetNativeVariantForObject(val, var.ptr);
  440. else
  441. {
  442. Array arr = val as Array;
  443. Array arrDest = Array.CreateInstance(typeof(object), arr.Length);
  444. arr.CopyTo(arrDest, 0);
  445. Marshal.GetNativeVariantForObject(arrDest, var.ptr);
  446. }
  447. }
  448. }
  449. bool IsByRef(IntPtr baseArray, int index)
  450. {
  451. if (baseArray == IntPtr.Zero)
  452. {
  453. Fx.Assert("baseArray should not be null");
  454. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("baseArrray");
  455. }
  456. uint displacement = (uint)(index * Marshal.SizeOf(typeof(TagVariant)));
  457. ushort vt = (ushort)Marshal.ReadInt16(GetDisp(baseArray, displacement));
  458. if (0 != (vt & (ushort)(VarEnum.VT_BYREF)))
  459. return true;
  460. else
  461. return false;
  462. }
  463. void IDisposable.Dispose()
  464. {
  465. dispToName.Clear();
  466. nameToDisp.Clear();
  467. dispToOperationDescription.Clear();
  468. }
  469. }
  470. }