<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>voyce &#187; IDispatch</title>
	<atom:link href="http://www.voyce.com/index.php/tag/idispatch/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.voyce.com</link>
	<description>Programming and debugging tidbits</description>
	<lastBuildDate>Wed, 11 Aug 2010 03:56:45 +0000</lastBuildDate>
	
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Getting .NET type information in the unmanaged world</title>
		<link>http://www.voyce.com/index.php/2008/12/01/getting-net-type-information-in-the-unmanaged-world/</link>
		<comments>http://www.voyce.com/index.php/2008/12/01/getting-net-type-information-in-the-unmanaged-world/#comments</comments>
		<pubDate>Mon, 01 Dec 2008 15:48:33 +0000</pubDate>
		<dc:creator>ian</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[COM]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[ccw]]></category>
		<category><![CDATA[IDispatch]]></category>
		<category><![CDATA[invoke]]></category>
		<category><![CDATA[type]]></category>
		<category><![CDATA[unmanaged]]></category>

		<guid isPermaLink="false">http://www.voyce.com/?p=55</guid>
		<description><![CDATA[One of the tools that I write and maintain displays type information for COM objects hidden behind &#8220;handles&#8221; in Excel spreadsheets. The underlying objects can either support an interface that allows them to be richly rendered to XML, or the viewer will fall-back to using metadata and displaying the supported interfaces and their properties and methods. It [...]]]></description>
			<content:encoded><![CDATA[<p>One of the tools that I write and maintain displays type information for COM objects hidden behind &#8220;handles&#8221; in Excel spreadsheets. The underlying objects can either support an interface that allows them to be richly rendered to XML, or the viewer will fall-back to using metadata and displaying the supported interfaces and their properties and methods. It will also invoke parameterless property getters &#8211; making the assumption that doing so won&#8217;t change the state of the object &#8211; and display the returned value. This is a useful way of getting some visibility on otherwise completely opaque values.</p>
<p>In order to obtain the type information about the COM objects, the tool uses type libraries, and the associated <a href="http://msdn.microsoft.com/en-us/library/ms221549.aspx">ITypeLib </a>and <a href="http://msdn.microsoft.com/en-us/library/ms221696.aspx">ITypeInfo</a> interfaces, which, with a little effort, can be used to iterate over all the coclasses, interfaces and functions in the library. But the difficulty lies in obtaining a type library when all you&#8217;re given is an already-instantiated object. In theory, COM allows you to know no more about an object than what interfaces it supports. But in practice, there are a variety of ways you can circumvent this and get to the type information.</p>
<p>For unmanaged COM objects you can use the information in the registry (or SxS configuration) and obtain the server (DLL) that contain a TLB embedded as a resource, or the type library filename itself. I won&#8217;t go into that now, there&#8217;s plenty of information about the location of these common registry keys elsewhere on the internet.</p>
<p>But for managed COM objects &#8211; well, COM callable wrappers (CCWs) &#8211; you have a different problem: registry scraping will never work and there may not even be an associated type library. The InprocServer32 registry entry always points to mscoree.dll, which obviously doesn&#8217;t have an embedded type library, and unless you&#8217;ve registered the assembly with /tlb (which is a pain) then you won&#8217;t have entries under HKEY_CLASSES_ROOT\Typelib and a TLB file to load.</p>
<p>So, if you&#8217;re in the unmanaged world, and all you&#8217;ve got is a pointer to a live CCW, what can you do?</p>
<p>Well, the easiest thing is to use <a href="http://msdn.microsoft.com/en-us/library/ms687303(VS.85).aspx">IProvideClassInfo</a>. This is supported by all CCWs, and provides a way to get an auto-generated (by the CLR) ITypeInfo implementation for the managed class. In fact, this is what I actually used to implement the solution eventually, but along the way I discovered some other interesting aspects of the CCW.</p>
<p>There is another interface that it supports: _Object, the unmanaged version of System.Object, which supports basic .NET functionality such as ToString and GetType. I couldn&#8217;t find it declared anywhere in the Platform or .NET SDK headers, so I put together a version that I could use from C++:</p>
<div style="font-size: 10pt; background: white; color: black; font-family: Lucida Sans Typewriter;">
<p style="margin: 0px;"><span style="color: #0000ff;">struct</span> <span style="color: #0000ff;">__declspec</span>(<span style="color: #0000ff;">uuid</span>(<span style="color: #800000;">&#8220;{65074F7F-63C0-304E-AF0A-D51741CB4A8D}&#8221;</span>)) Object : <span style="color: #0000ff;">public</span> IDispatch</p>
<p style="margin: 0px;">{</p>
<p style="margin: 0px;"><span style="color: #0000ff;">public</span>:</p>
<p style="margin: 0px;"><span style="color: #008000;">// We don&#8217;t actually call these methods, doing so seems to return</span></p>
<p style="margin: 0px;"><span style="color: #008000;">// COR_E_INVALIDOPERATION. Instead we just use the IDispatch::Invoke</span></p>
<p style="margin: 0px;"><span style="color: #008000;">// and use the DISPID of the methods.</span></p>
<p style="margin: 0px;"><span style="color: #0000ff;">virtual</span> HRESULT STDMETHODCALLTYPE ToString(BSTR *) = 0;</p>
<p style="margin: 0px;"><span style="color: #0000ff;">virtual</span> HRESULT STDMETHODCALLTYPE Equals(VARIANT, VARIANT_BOOL *) = 0;</p>
<p style="margin: 0px;"><span style="color: #0000ff;">virtual</span> HRESULT STDMETHODCALLTYPE GetHashCode(<span style="color: #0000ff;">long</span> *) = 0;</p>
<p style="margin: 0px;"><span style="color: #0000ff;">virtual</span> HRESULT STDMETHODCALLTYPE GetType(mscorlib::_Type **) = 0;</p>
<p style="margin: 0px;">};</p>
</div>
<p><!--EndFragment-->Despite the presence of the virtual functions in this &#8220;interface&#8221;, we&#8217;re not actually going to call them. Instead we&#8217;ll call through the IDispatch that it derives from. It may be possible to use them directly, but see the comment describing what happens when I tried it. Calling via IDispatch may seem slightly odd, because the object itself claims not to support it (QueryInteface returns E_NOINTERFACE).</p>
<p>The methods on the _Object interface have well-known DISPIDs:</p>
<table border="0">
<tbody>
<tr>
<td>ToString</td>
<td>0&#215;00000000</td>
</tr>
<tr>
<td>Equals</td>
<td>0&#215;60020001</td>
</tr>
<tr>
<td>GetHashCode</td>
<td>0&#215;60020002</td>
</tr>
<tr>
<td>GetType</td>
<td>0&#215;60020003</td>
</tr>
</tbody>
</table>
<p>So we can use that to invoke the GetType method:</p>
<div style="font-size: 10pt; background: white; color: black; font-family: Lucida Sans Typewriter;">
<p style="margin: 0px;">DISPPARAMS parms;</p>
<p style="margin: 0px;">parms.cArgs = 0;</p>
<p style="margin: 0px;">parms.cNamedArgs = 0;</p>
<p style="margin: 0px;">_variant_t vType;</p>
<p style="margin: 0px;">hr = pObject-&gt;Invoke(0&#215;60020003, IID_NULL, 0, DISPATCH_METHOD, &amp;parms, &amp;vType, NULL, NULL);</p>
</div>
<p><!--EndFragment-->And we get back a <a href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices._type.aspx">_Type</a> interface that allows us to navigate around the type information in the same way as we can with System.Type! Just #import mscorlib.tlb and you get all the interfaces you need to e.g. iterate over all the interfaces implemented by a type, and invoke a function on them:</p>
<div style="font-size: 10pt; background: white; color: black; font-family: Lucida Sans Typewriter;">
<p style="margin: 0px;"><span style="color: #0000ff;">#import</span> <span style="color: #800000;">&lt;mscorlib.tlb&gt;</span> rename(<span style="color: #800000;">&#8220;ReportEvent&#8221;</span>,<span style="color: #800000;">&#8220;xReportEvent&#8221;</span>)</p>
<p style="margin: 0px;">&#8230;</p>
<p style="margin: 0px;">mscorlib::_TypePtr t(V_UNKNOWN(&amp;vType));</p>
<p style="margin: 0px;">CComSafeArray&lt;LPUNKNOWN&gt; saInterfaces(t-&gt;GetInterfaces());</p>
<p style="margin: 0px;">&#8230;</p>
<p style="margin: 0px;">mscorlib::_TypePtr tInterface((LPUNKNOWN)saInterfaces.GetAt(n));</p>
<p style="margin: 0px;">&#8230;</p>
<p style="margin: 0px;">result = tInterface-&gt;InvokeMember(_bstr_t(<span style="color: #800000;">&#8220;Function&#8221;</span>),</p>
<p style="margin: 0px;">(mscorlib::BindingFlags)</p>
<p style="margin: 0px;">(mscorlib::BindingFlags_GetProperty +</p>
<p style="margin: 0px;">mscorlib::BindingFlags_InvokeMethod +</p>
<p style="margin: 0px;">mscorlib::BindingFlags_Public +</p>
<p style="margin: 0px;">mscorlib::BindingFlags_Instance +</p>
<p style="margin: 0px;">mscorlib::BindingFlags_IgnoreCase),</p>
<p style="margin: 0px;">NULL, _variant_t(punk), NULL, NULL, NULL, NULL);</p>
</div>
<p>So this turns out to be quite nice: you can get rich managed type information even if you&#8217;re running in the unmanaged world.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.voyce.com/index.php/2008/12/01/getting-net-type-information-in-the-unmanaged-world/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Beware cached IDispatch</title>
		<link>http://www.voyce.com/index.php/2008/11/10/beware-cached-idispatch/</link>
		<comments>http://www.voyce.com/index.php/2008/11/10/beware-cached-idispatch/#comments</comments>
		<pubDate>Mon, 10 Nov 2008 11:32:15 +0000</pubDate>
		<dc:creator>ian</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[COM]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[F#]]></category>
		<category><![CDATA[IDispatch]]></category>
		<category><![CDATA[VBA]]></category>
		<category><![CDATA[VBScript]]></category>

		<guid isPermaLink="false">http://www.voyce.com/?p=51</guid>
		<description><![CDATA[I&#8217;ve kinda given it away there with the title, but we had an interesting set of symptoms exhibited the other day while trying to call a function in an Excel workbook via F#. It appeared that the function being called would fail depending on what had been called previously. Very odd.
A bit of background: as you [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve kinda given it away there with the title, but we had an interesting set of symptoms exhibited the other day while trying to call a function in an Excel workbook via F#. It appeared that the function being called would fail depending on what had been called previously. Very odd.</p>
<p>A bit of background: as you may know, if you add functions to the worksheet or workbook code in Excel then they appear as callable methods on the objects themselves. This is achieved with the use of dynamic dispatch and IDispatch. For example, creating a workbook with this function in it&#8217;s VBA code:</p>
<p><code>Public Function Foo() As Double<br />
    Foo = 100<br />
End Function</code></p>
<p>Means you can call it like this:</p>
<p><code>MsgBox CStr(ThisWorkbook.Foo)</code></p>
<p>As well as being able to call it like this from within the Excel session (i.e. in other VBA code in the process), you can also access it externally using the COM object model that Office applications expose. For instance, you can use VBScript:</p>
<p><code>Dim excel, wkb<br />
Set excel = CreateObject("Excel.Application")<br />
Set wkb = excel.Workbooks.Open("a.xls")<br />
WScript.Echo wkb.Foo<br />
</code></p>
<p>Or, more interesting, using F#:</p>
<div style="font-family: Lucida Sans Typewriter; font-size: 10pt; color: black; background: white;">
<p style="margin: 0px;">    <span style="color: #0000ff;">let</span> excel = <span style="color: #0000ff;">new</span> Excel.ApplicationClass()</p>
<p style="margin: 0px;">    <span style="color: #0000ff;">let</span> wkb = excel.Workbooks.Open(<span style="color: #a31515;">@&#8221;c:\a.xls&#8221;</span>)</p>
<p style="margin: 0px;">    wkb.GetType().InvokeMember(<span style="color: #a31515;">&#8220;Foo&#8221;</span>, BindingFlags.InvokeMethod, <span style="color: #0000ff;">null</span>, wkb, <span style="color: #0000ff;">null</span>)</p>
</div>
<p>The key part here is that we&#8217;re using wks.GetType() to get a managed representation of the unmanaged Excel COM interface. Under the covers this is creating a runtime callable wrapper (RCW) to wrap the worksheet COM object.</p>
<p>However, the problem we were seeing was that opening multiple sheets resulted in failures to call the method in certain situations. Although the VBA signature was exactly the same in all of the sheets, it seemed that opening b.xls after a.xls, would fail; returning null when we expected it to return a value. If we opened c.xls after b.xls, it would fail in a different way; never actually making it to the body of the function. Very odd.</p>
<p>My first suspicion was that it was somehow related to COM object vs .NET object lifetime. This is quite a common problem whens invoking Excel using managed code. It&#8217;s bad mixing COM and .NET anyway; generally deterministic, reference-counted lifetime semantics don&#8217;t play well with the garbage collector. Throwing an app with a full-blown UI being managed as COM object into the mix just complicates matters further. Anyway, it&#8217;s been widely discussed, so I won&#8217;t say any more about it here; suffice to say that calling Marshal.ReleaseCOMObject and GC.Collect got us to the point where we could see the Excel process terminating, so we knew that the failure wasn&#8217;t due to some state being cached inside there.</p>
<p>So we concentrated on different aspects of the problem:</p>
<ul>
<li>Given the pattern of failures, it seemed that the order of opening the sheets and calling affected the outcome. This hinted that something was persisting betweeen calls, but not in the client (Excel) site.</li>
<li>The code had previously worked when written in VBScript, so there was nothing intrinsically wrong with the operations we were performing.</li>
</ul>
<p>This seemed to strongly indicate that something was being cached at the .NET level. And the major difference between the .NET code and the VBScript was that the former used Type.GetType() on the worksheet object to get it&#8217;s managed representation, while the latter used the IDispatch directly.</p>
<p>So it looked like GetType() was caching some information about the particular IDispatch implementation that it encountered first, then reusing that for subsequent worksheet implementations which actually had a slightly different layout, i.e. although they also had the Foo function which we were trying to call, they had a different set of other dynamic functions too.</p>
<p>After a bit of digging about I uncovered this gem: <a href="http://blogs.msdn.com/mbend/archive/2007/04/18/the-mapping-between-interface-pointers-and-runtime-callable-wrappers-rcws.aspx">the mapping between interface pointers and runtime callable wrappers</a>. Which seemed to describe exactly what we were seeing. The first time through the loop, the runtime is asked to get the type and is given a COM pointer, for which it creates a RCW that we can use to invoke Foo. The second time through the loop, the runtime thinks it&#8217;s seen the object before, so rather than perform the expensive operation of creating the RCW again, it just returns the original one. The problem is, the underlying COM object is different!</p>
<p>So, in order to prevent the runtime for trying to cache the RCW, we need to use <a href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.getuniqueobjectforiunknown(VS.80).aspx">Marshal.GetUniqueObjectForIUnknown</a> and that does the trick nicely. We first need to get an IUnknown for our object, than convert that back into an object, which is actually a RCW:</p>
<div style="font-family: Lucida Sans Typewriter; font-size: 10pt; color: black; background: white;">
<p style="margin: 0px;">    <span style="color: #0000ff;">let</span> wkb = Marshal.GetUniqueObjectForIUnknown(Marshal.GetIUnknownForObject(wkb))</p>
</div>
<p>Although it&#8217;s less efficent, at least the code works, and it finally allows us to call the dynamic methods on the workbook object from F# .NET.</p>
<p>It will be interesting to see how <code>dynamic</code> in .NET 4.0 addresses this kind of issue.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.voyce.com/index.php/2008/11/10/beware-cached-idispatch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
