<?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>Martin&#039;s Blog &#187; COM</title>
	<atom:link href="http://blog.m-ri.de/index.php/tag/com/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.m-ri.de</link>
	<description>Gesammeltes aus dem Leben eines &#34;normalen&#34; Programmierers... :-)</description>
	<lastBuildDate>Sat, 04 Feb 2012 12:07:16 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>AfxOleInit versus CoInitializeEx in MFC Programmen</title>
		<link>http://blog.m-ri.de/index.php/2009/04/30/afxoleinit-versus-coinitializeex-in-mfc-programmen/</link>
		<comments>http://blog.m-ri.de/index.php/2009/04/30/afxoleinit-versus-coinitializeex-in-mfc-programmen/#comments</comments>
		<pubDate>Thu, 30 Apr 2009 18:50:14 +0000</pubDate>
		<dc:creator>Martin Richter</dc:creator>
				<category><![CDATA[ATL]]></category>
		<category><![CDATA[MFC]]></category>
		<category><![CDATA[Programmieren]]></category>
		<category><![CDATA[COM]]></category>

		<guid isPermaLink="false">http://blog.m-ri.de/?p=445</guid>
		<description><![CDATA[Immer wieder mal, taucht MFC Code auf und es wird CoInitializeEx verwendet. Nicht unbedingt ein Fehler, aber ich denke man sollte auch hier die MFC-Art-und-Weise verwenden: AfxOleInit. Und man sollte sich klar sein, welche Apartment Modes man verwenden darf! AfxOleInit selbst ist ein per Thread Wrapper für ::OleInitialize(NULL);. Zudem sorgt AfxOleInit dafür, dass bei Beenden [...]]]></description>
			<content:encoded><![CDATA[<p>Immer wieder mal, taucht <em>MFC </em>Code auf und es wird <em>CoInitializeEx </em>verwendet.<br />
Nicht unbedingt ein Fehler, aber ich denke man sollte auch hier die MFC-Art-und-Weise verwenden: <em>AfxOleInit</em>. Und man sollte sich klar sein, welche Apartment Modes man verwenden darf!</p>
<p><em>AfxOleInit selbst </em>ist ein per Thread Wrapper für <em><a href="http://msdn.microsoft.com/de-de/library/e91aseaz(VS.80).aspx">::OleInitialize(NULL);</a></em>.<br />
Zudem sorgt <em>AfxOleInit </em>dafür, dass bei Beenden des Threads automatisch <em>AfxOleTerm </em>aufgerufen wird.</p>
<p><em>::OleInitialize(NULL)</em> wiederum ist ein Wrapper für den Aufruf von <em>CoInitializeEx</em> im STA Kontext:<br />
Siehe MSDN <a href="http://msdn.microsoft.com/en-us/library/ms690134(VS.85).aspx">http://msdn.microsoft.com/en-us/library/ms690134(VS.85).aspx</a> </p>
<blockquote><p>OleInitialize calls CoInitializeEx internally to initialize the COM library on the current apartment. Because OLE operations are not thread-safe, OleInitialize specifies the concurrency model as single-thread apartment.</p></blockquote>
<p>Die <em>MFC </em>benutzt und verlangt genau diesen <em>STA </em>Modus. Sofern man also nicht wirklich weiß was man mit <em>CoInitializeEx </em>macht, sollte man es in der <em>MFC </em>vermeiden. Zudem man sich eben auch nicht mehr um den Cleanup kümmern muss, da die MFC dies selber macht.</p>
<p>Siehe auch MSDN Doku zu <em>AfxOleInit</em><br />
<a href="http://msdn.microsoft.com/de-de/library/e91aseaz(VS.80).aspx">http://msdn.microsoft.com/de-de/library/e91aseaz(VS.80).aspx</a></p>
<blockquote><p>MFC applications must be initialized as single threaded apartment (STA). If you call CoInitializeEx in your InitInstance override, specify COINIT_APARTMENTTHREADED (rather than COINIT_MULTITHREADED). For more information, see PRB: MFC Application Stops Responding When You Initialize the Application as a Multithreaded Apartment (828643) at <a href="http://support.microsoft.com/default.aspx?scid=kb;en-us;828643">http://support.microsoft.com/default.aspx?scid=kb;en-us;828643</a>.</p></blockquote>
<p>Aber auch hier sei erwähnt, dass man sicherlich auch andere Apartment Modes verwenden kann. Allerdings muss man dann wirklich wissen was man macht und darf sich nicht auf die <em>MFC</em> Funktionen stützen. Für solche Fälle verwende ich hier komplett ATL in meinen <em>MFC</em> Programmen.<br />
Man sollte aber in diesen Fällen wirklich wissen was man macht <img src='http://blog.m-ri.de/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>BTW: Automatisch aufgeräumt bei einem gestarteten Thread wird nur dann, wenn auch AfxBeginThread verwendet wird. Siehe auch: <a class="l" onmousedown="return clk(this.href,'','','res','1','&amp;sig2=AjTmup5MlQdIipqqmGcT-Q')" href="http://blog.m-ri.de/index.php/2008/02/28/afxbeginthread-versus-_beginthreadex/" target="_blank">AfxBeginThread versus _beginthreadex</a></p>
<hr /><small>Copyright &copy; 2010 Martin Richter<br />Dieser Feed ist nur für den persönlichen, nicht gewerblichen Gebrauch bestimmt. Eine Verwendung dieses Feeds bzw. der hier veröffentlichten Beiträge auf anderen Webseiten bedarf der ausdrücklichen Genehmigung des Autors.<br />(Digital Fingerprint: bdafe67664ea5aacaab71f8c0a581adf)</small>]]></content:encoded>
			<wfw:commentRss>http://blog.m-ri.de/index.php/2009/04/30/afxoleinit-versus-coinitializeex-in-mfc-programmen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Externe und interne COM Zugriffe unterscheiden</title>
		<link>http://blog.m-ri.de/index.php/2008/12/10/externe-und-interne-com-zugriffe-unterscheiden/</link>
		<comments>http://blog.m-ri.de/index.php/2008/12/10/externe-und-interne-com-zugriffe-unterscheiden/#comments</comments>
		<pubDate>Wed, 10 Dec 2008 18:54:01 +0000</pubDate>
		<dc:creator>Martin Richter</dc:creator>
				<category><![CDATA[ATL]]></category>
		<category><![CDATA[Programmieren]]></category>
		<category><![CDATA[Sonstiges]]></category>
		<category><![CDATA[Windows API]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[COM]]></category>
		<category><![CDATA[WinAPI]]></category>

		<guid isPermaLink="false">http://blog.m-ri.de/?p=322</guid>
		<description><![CDATA[Ich benutze als interne Makrosprache gerne VBScript. D.h. ich hoste VBScript. Ich biete dann bestimmte COM-Objekte (IDisptach) an, die es dem Nutzer erlauben mein  Programm anzupassen oder intern zu steuern. Nun macht es aber unter Umständen einen gravierenden Unterschied, ob ein COM-Objekt von einem programminternen Nutzer, oder von extern angesprochen wird. Intern möchte ich zum Beispiel mehr  [...]]]></description>
			<content:encoded><![CDATA[<p>Ich benutze als interne Makrosprache gerne <em>VBScript</em>. D.h. ich hoste <em>VBScript</em>.<br />
Ich biete dann bestimmte <em>COM</em>-Objekte (<em>IDisptach</em>) an, die es dem Nutzer erlauben mein  Programm anzupassen oder intern zu steuern.</p>
<p>Nun macht es aber unter Umständen einen gravierenden Unterschied, ob ein <em>COM</em>-Objekt von einem programminternen Nutzer, oder von extern angesprochen wird. Intern möchte ich zum Beispiel mehr  oder andere Funktionen erlauben als durch einen externen Zugriff von einem anderen Programm oder Skript.</p>
<p>Wie kann man aber unterscheiden von wo ein <em>COM </em>Zugriff erfolgt <img src='http://blog.m-ri.de/wp-includes/images/smilies/icon_question.gif' alt=':?:' class='wp-smiley' /> </p>
<p>Netterweise hat COM die Funktion <a href="http://msdn.microsoft.com/en-us/library/ms691483(VS.85).aspx">CoGetCallContext</a>, die mir genau diese Info liefert. Liefert <em>CoGetCallContext S_OK </em>und damit einen Interfacezeiger auf <em>IServerSecurity</em>, dann wurde der COM Zugriff von einem externen Prozess abgesetzt. Wenn <em>CoGetCallObject E_NOINTERFACE </em>zurück gibt haben wir einen internen Aufruf aus dem eigenen Prozess heraus.</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">bool</span> IsExternalComCall<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
 <span style="color: #666666;">// get context</span>
 CComPtr<span style="color: #000080;">&lt;</span>IServerSecurity<span style="color: #000080;">&gt;</span> spSecurity<span style="color: #008080;">;</span>
 HRESULT hr <span style="color: #000080;">=</span> <span style="color: #008080;">::</span><span style="color: #007788;">CoGetCallContext</span><span style="color: #008000;">&#40;</span>IID_IServerSecurity,
                      <span style="color: #0000ff;">reinterpret_cast</span><span style="color: #000080;">&lt;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">**</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>spSecurity<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
 <span style="color: #0000ff;">return</span> SUCCEEDED<span style="color: #008000;">&#40;</span>hr<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p lang="cpp">Herzlichen Dank an René König für diesen Ansatz, den er mir in microsoft.public.de.vc gab.</p>
<hr /><small>Copyright &copy; 2010 Martin Richter<br />Dieser Feed ist nur für den persönlichen, nicht gewerblichen Gebrauch bestimmt. Eine Verwendung dieses Feeds bzw. der hier veröffentlichten Beiträge auf anderen Webseiten bedarf der ausdrücklichen Genehmigung des Autors.<br />(Digital Fingerprint: bdafe67664ea5aacaab71f8c0a581adf)</small>]]></content:encoded>
			<wfw:commentRss>http://blog.m-ri.de/index.php/2008/12/10/externe-und-interne-com-zugriffe-unterscheiden/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tipps &amp; Tricks: #import durch #include ersetzen</title>
		<link>http://blog.m-ri.de/index.php/2008/08/03/tipps-tricks-import-durch-include-ersetzen/</link>
		<comments>http://blog.m-ri.de/index.php/2008/08/03/tipps-tricks-import-durch-include-ersetzen/#comments</comments>
		<pubDate>Sun, 03 Aug 2008 18:04:14 +0000</pubDate>
		<dc:creator>Martin Richter</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Programmieren]]></category>
		<category><![CDATA[Sonstiges]]></category>
		<category><![CDATA[Windows API]]></category>
		<category><![CDATA[COM]]></category>
		<category><![CDATA[Tipps&Tricks]]></category>

		<guid isPermaLink="false">http://blog.m-ri.de/?p=281</guid>
		<description><![CDATA[Nicht wenige verwenden, wie ich auch COM Komponenten, aus dem eigenen Haus oder von Fremdherstellern. Eingebunden werden diese COM-Komponenten oft genug über das #import Statement, das ja eine wirklich simple Integration erlaubt. Lästig ist nur, dass diese Komponenten nicht auf allen Rechnern in den selben Verzeichnissen liegen. Das macht es nicht leicht Projekte und Entwicklungmaschinen [...]]]></description>
			<content:encoded><![CDATA[<p>Nicht wenige verwenden, wie ich auch COM Komponenten, aus dem eigenen Haus oder von Fremdherstellern. Eingebunden werden diese COM-Komponenten oft genug über das <em>#import </em>Statement, das ja eine wirklich simple Integration erlaubt.</p>
<p>Lästig ist nur, dass diese Komponenten nicht auf allen Rechnern in den selben Verzeichnissen liegen. Das macht es nicht leicht Projekte und Entwicklungmaschinen so auszustatten, dass alle Projekte gleich zu kompilieren sind. Da fängt es schon an, dass ein Entwickler ein englisches OS (<em>C:\Program Files</em>), ein andere ein deutsches (<em>C:\Programme</em>) und der dritte Entwickler benutzt das Installationverzeichnis der zu entwickelnden Komponente (C:\Dev\Project\Bin).</p>
<p>Aus diesem Grund bin ich dazu übergangen das <em>#import </em>Statement nur einmal auszuführen, und die entstehenden <em>.tlh </em>und <em>.tli </em>Dateien direkt in das Projekt aufzunehmen.<br />
Zu schnell? OK, also schrittweise:</p>
<ul>
<li>Ich binde die Komponente also wie gewohnt per #import ein.</li>
<li>Die entstehenden <em>.tlh </em>und evtl. auch die <em>.tli </em>Dateien werden in das Projektverzeichnis kopiert und in das Projekt aufgenommen.</li>
<li>Das das <em>#import </em>Statement wird nun auskommentiert und statt dessen entsprechende <em>#include </em>Statements eingesetzt.</li>
<li>Nachdem man das auch korrekt mit entsprechenden Versionsangaben der Komponente dokumentiert hat und auch dieses Verfahren in die Projektbeschreibung aufgenommen hat ist man fertig!</li>
</ul>
<p>Vor- und Nachteile:</p>
<ul>
<li>Nicht nur, dass dieses Projekt unabhängig kompiliert werden kann. Das Kompilieren ist auch noch schneller, denn die (an sich) statischen <em>.tlh </em>und <em>.tli </em>Dateien werden nicht immer neu erzeugt.</li>
<li>Vorrausetzung ist hier sicherlich, dass es sich hier um Komponenten handelt, deren Interface sich nicht mehr verändert, und man muss bei einem Update der Komponente natürlich auch manuell die neuen <em>.tli </em>und <em>.tlh </em>Dateien einbauen.</li>
<li>Ein weiterer Vorteil ist auch, dass das Interface fest eingebunden wird, das auch für die Auslieferung festgelegt wird und keine alte/oder neuere Version zu Überraschungen führt.</li>
<li>Was auch zu dem genialen Verhalten führt, dass man aus dem Sourcecontrol System eine Software Version erzeugen kann, die noch mit einer älteren/abweichenden COM Komponente erzeugt wurde ohne diese auch noch mal installieren zu müssen!</li>
</ul>
<hr /><small>Copyright &copy; 2010 Martin Richter<br />Dieser Feed ist nur für den persönlichen, nicht gewerblichen Gebrauch bestimmt. Eine Verwendung dieses Feeds bzw. der hier veröffentlichten Beiträge auf anderen Webseiten bedarf der ausdrücklichen Genehmigung des Autors.<br />(Digital Fingerprint: bdafe67664ea5aacaab71f8c0a581adf)</small>]]></content:encoded>
			<wfw:commentRss>http://blog.m-ri.de/index.php/2008/08/03/tipps-tricks-import-durch-include-ersetzen/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Late Binding und schwache Performance durch GetIDsOfNames</title>
		<link>http://blog.m-ri.de/index.php/2008/02/16/late-binding-und-schwache-performance-durch-getidsofnames/</link>
		<comments>http://blog.m-ri.de/index.php/2008/02/16/late-binding-und-schwache-performance-durch-getidsofnames/#comments</comments>
		<pubDate>Sat, 16 Feb 2008 13:45:34 +0000</pubDate>
		<dc:creator>Martin Richter</dc:creator>
				<category><![CDATA[ATL]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[MFC]]></category>
		<category><![CDATA[Programmieren]]></category>
		<category><![CDATA[Windows API]]></category>
		<category><![CDATA[COM]]></category>

		<guid isPermaLink="false">http://blog.m-ri.de/index.php/2008/02/16/late-binding-und-schwache-performance-durch-getidsofnames/</guid>
		<description><![CDATA[Immer wieder sehe ich Entwickler, die über Late Binding COM Komponenten ansprechen. Das ist an sich nur zu unterstützen, denn DISPIDs können sich schnell mal ändern, wenn sich ein Interface ändert. Gerade bei den rasant an Verbreitung zunehmenden .NET Komponenten, die man mal schnell in die eigene Anwendung per COM einbindet, kann das Binding über die Interfaces [...]]]></description>
			<content:encoded><![CDATA[<p>Immer wieder sehe ich Entwickler, die über Late Binding COM Komponenten ansprechen. Das ist an sich nur zu unterstützen, denn <em>DISPIDs </em>können sich schnell mal ändern, wenn sich ein Interface ändert. Gerade bei den rasant an Verbreitung zunehmenden .NET Komponenten, die man mal schnell in die eigene Anwendung per COM einbindet, kann das Binding über die Interfaces und <em>DISPIDs </em>schnell zum Frust werden. Gleiches gilt für Office Komponenten, bei denen man sich nicht zwingend an ein Interface binden will. Zudem ist es der von <a href="http://support.microsoft.com/kb/247579/en-us">Microsoft empfohlene Weg</a> die Office-Automation zu benutzen (siehe auch <a href="http://support.microsoft.com/kb/245115/en-us">hier</a>).</p>
<p>OK! Also man nimmt Late Binding und verwendet z.B. die aktuellen Wrapper, die netterweise von der ATL zur Verfügung gestellt werden,  z.B. die netten Funktionen aus der <a href="http://msdn2.microsoft.com/en-us/library/9yb5s0fk(VS.80).aspx"><em>CComDispatchDriver</em></a> Klasse. <em>GetPropertyByName</em>, <em>PutPropertyByName </em>und auch die Funktionen <em>Invoke0</em>, <em>Invoke1 </em>und <em>InvokeN </em>haben entsprechende Überladungen, die die Verwendung von Funktions-/Eigenschaftsnamen direkt erlauben.</p>
<p>Der Nachteil liegt nicht gleich auf der Hand. Immer wenn solch eine Funktion aufgerufen wird, wird nicht durch der <em>IDispatch::Involke </em>ausgeführt, sondern auch ein Aufruf von <em>IDispatch::GetIDsOfNames</em>. Bei einem Out-Of-Process-Server kann dieser Roundtrip einiges an Performance kosten. Dabei ist es so einfach es besser zu machen.</p>
<p>Die Doku von <em><a href="http://msdn2.microsoft.com/en-us/library/ms221306(VS.85).aspx">IDispatch::GetIDsOfNames</a></em> sagt folgendes:  </p>
<blockquote><p>The member and parameter DISPIDs must remain constant for the lifetime of the object. This allows a client to obtain the DISPIDs once, and cache them for later use.</p></blockquote>
<p>Und wer den oben genannten <a href="http://support.microsoft.com/kb/247579/en-us">KB-Artikel</a> aufmerksam gelesen hat, der hat auch was von DISPID-Caching mitbekommen.</p>
<p>Ich benutze gerne die die Wrapper, die in der MFC automatisch erzeugt werden, wenn man einen <em>Type-Library</em> über den Class View importiert. Hier werden die Funktionen auch in eine nette kleine <em>COleDispatchDriver</em>-Klasse verpackt und man bekommt netterweise ein gutes Exception Handling den Fehlerfall geliefert. Leider werden hier aber auch wieder nur <em>DISPIDs </em>verwendet<em>.<br />
</em>Aber mit einem kleinen Trick, kann man diese Klassen genial einfach für <em>Late Binding </em>nutzen. Ich gehe wie folgt vor:</p>
<ul>
<li>Ich importiere die <em>Type-Library</em> (tlb) mit dem Visual Studio Class View.</li>
<li>D.h. ich habe jetzt alle Wrapper mit DISPIDs, Was ich eigentlich für Late Binding vermeiden will.</li>
<li>Jetzt passe ich einfach die einzelnen Wrapper Funktionen in der folgenden Art und Weise an, ich ersetze die DISPID durch eine statische Variable:</li>
</ul>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;">&nbsp;
<span style="color: #0000ff;">void</span> CMyWrapper<span style="color: #008080;">::</span><span style="color: #007788;">DoSomething</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
  <span style="color: #0000ff;">static</span> CDispIdHolder dispid<span style="color: #008000;">&#40;</span>m_lpDispatch,L<span style="color: #FF0000;">&quot;DoSomething&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
  InvokeHelper<span style="color: #008000;">&#40;</span>dispid, DISPATCH_METHOD, VT_EMPTY, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<ul>
<li>Die kleine Klasse die ich hier verwende macht nun den Rest und besorgt die <em>DISPID</em> und cached sie damit weil die Variable statisch definiert ist:</li>
</ul>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;">&nbsp;
<span style="color: #0000ff;">class</span> CDispIdHolder
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
 CDispIdHolder<span style="color: #008000;">&#40;</span>IDispatch <span style="color: #000040;">*</span>pDispatch,LPCOLESTR pName<span style="color: #008000;">&#41;</span>
  <span style="color: #008080;">:</span> m_dispid<span style="color: #008000;">&#40;</span>DISPID_UNKNOWN<span style="color: #008000;">&#41;</span>
  <span style="color: #008000;">&#123;</span>
   HRESULT hr <span style="color: #000080;">=</span> pDispatch<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>GetIDsOfNames<span style="color: #008000;">&#40;</span>
         IID_NULL,
         <span style="color: #000040;">&amp;</span><span style="color: #0000ff;">const_cast</span><span style="color: #000080;">&lt;</span>LPOLESTR<span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span>pName<span style="color: #008000;">&#41;</span>,
         <span style="color: #0000dd;">1</span>,
         LOCALE_SYSTEM_DEFAULT,
         <span style="color: #000040;">&amp;</span>m_dispid<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
   <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>FAILED<span style="color: #008000;">&#40;</span>hr<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
    AfxThrowOleException<span style="color: #008000;">&#40;</span>hr<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
  <span style="color: #008000;">&#125;</span>
  operator DISPID<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000ff;">return</span> m_dispid<span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
 DISPID m_dispid<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>Die Exception, die man verwendet ist natürlich Implementierungsfrage.</p>
<p> <img src='http://blog.m-ri.de/wp-includes/images/smilies/icon_exclaim.gif' alt=':!:' class='wp-smiley' />  Der Performance Gain ist zum Teil beträchtlich, besonders wnen bestimmte Funktionen sehr oft aufgerufen werden müssen!</p>
<p>Anmerkung (für alle die es ganz genau nehmen):<br />
Wenn man die Doku genau liest, heißt es natürlich hier, dass die Implementierung nur für die Lebenszeit des Objektes konstante <em>DISPIDs</em> garantiert. Wenn man allerdings bei Early Binding schon <em>DISPIDs </em>als konstant annimmt, ist meine Methode für Late Binding sicherlich vertretbar.</p>
<hr /><small>Copyright &copy; 2010 Martin Richter<br />Dieser Feed ist nur für den persönlichen, nicht gewerblichen Gebrauch bestimmt. Eine Verwendung dieses Feeds bzw. der hier veröffentlichten Beiträge auf anderen Webseiten bedarf der ausdrücklichen Genehmigung des Autors.<br />(Digital Fingerprint: bdafe67664ea5aacaab71f8c0a581adf)</small>]]></content:encoded>
			<wfw:commentRss>http://blog.m-ri.de/index.php/2008/02/16/late-binding-und-schwache-performance-durch-getidsofnames/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Wie man sich mit CComDispatchDriver bzw. CComPtr&lt;IDispatch&gt;::InvokeN hereinlegen kann</title>
		<link>http://blog.m-ri.de/index.php/2008/02/02/wie-man-sich-mit-ccomdispatchdriver-bzw-ccomptrinvoken-hereinlegen-kann/</link>
		<comments>http://blog.m-ri.de/index.php/2008/02/02/wie-man-sich-mit-ccomdispatchdriver-bzw-ccomptrinvoken-hereinlegen-kann/#comments</comments>
		<pubDate>Sat, 02 Feb 2008 15:09:29 +0000</pubDate>
		<dc:creator>Martin Richter</dc:creator>
				<category><![CDATA[ATL]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Programmieren]]></category>
		<category><![CDATA[COM]]></category>

		<guid isPermaLink="false">http://blog.m-ri.de/index.php/2008/02/02/wie-man-sich-mit-ccomdispatchdriver-bzw-ccomptrinvoken-hereinlegen-kann/</guid>
		<description><![CDATA[Eigentlich müsste dieser Artikel eine weitere Überschrift bekommen: Wie fatal es ist, dass es keine vollständige ATL Dokumentation gibt! Einige werden CComDispatchDriver kennen. Seit den VS-200x Versionen ist diese Klasse nichts anderes als sie Spezialisierung CComPtr&#60;IDispatch&#62; Ich hatte vor, eine bestimmte .NET Komponente per late binding in ein C++ Programm zu integrieren. Kein Problem. CreateInstance, [...]]]></description>
			<content:encoded><![CDATA[<p>Eigentlich müsste dieser Artikel eine weitere Überschrift bekommen:<br />
<strong>Wie fatal es ist, dass es keine vollständige ATL Dokumentation gibt!</strong></p>
<p>Einige werden <em>CComDispatchDriver </em>kennen. Seit den VS-200x Versionen ist diese Klasse nichts anderes als sie Spezialisierung <em>CComPtr&lt;IDispatch&gt;</em></p>
<p>Ich hatte vor, eine bestimmte .NET Komponente per <em>late binding </em>in ein C++ Programm zu integrieren.<br />
Kein Problem. <em>CreateInstance</em>, hier ein <em>Invoke0</em>, dort ein <em>Invoke2 </em>und da noch ein <em>InvokeN </em> <img src='http://blog.m-ri.de/wp-includes/images/smilies/icon_surprised.gif' alt=':eek:' class='wp-smiley' />  &#8230; und hier geht auf einmal nichts mehr. Dokumentation in der MSDN: Fehlanzeige!</p>
<p>Bestandsaufnahme: Ich habe einen CComVariant Array aufgebaut und die entsprechenden Daten übergeben. Sieht alles richtig aus. Aber ich erhalte immer nur Fehler (immer <em>E_NOINTERFACE</em>).</p>
<ol>
<li>OK, nächster Schritt. Das ganze mal direkt mit dem entsprechenden Interface versuchen. Also <em>CComQIPtr</em> eingebaut und direkter Aufruf über die existierende duale Schnittstelle. Komisch, nun geht es.</li>
<li>Nun denn. Das ganze nun mal als Klasse mit dem Classview importiert und einen MFC Wrapper gebaut. Der verwendet ja auch <em>IDispatch. </em>Jetzt wird es mysteriös: Es geht auch!</li>
</ol>
<p>Dann debuggen wir mal den MFC Wrapper. Schrittweise gehe ich durch den Code im <em>COleDispatchDriver::InvokeHelperV </em>bis Zeile 223 und dort lese ich den folgenden Code und Kommentar:</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">pArg <span style="color: #000040;">+</span><span style="color: #000080;">=</span> dispparams.<span style="color: #007788;">cArgs</span> <span style="color: #000040;">-</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span> <span style="color: #666666;">// params go in opposite order</span></pre></div></div>

<p> <img src='http://blog.m-ri.de/wp-includes/images/smilies/icon_exclaim.gif' alt=':!:' class='wp-smiley' />  Aha! Hier liegt der Hase im Pfeffer. Ich hatte den <em>CComVariant </em>Array natürlich so aufgebaut, dass das erste Argument auch das erste Element im Array war. <em>InvokeN </em>will aber die selbe Reihenfolge wie <em>IDispatch::Invoke</em>, d.h. in umgekehrter Folge. Also beginnt der Array nun mit dem letzten Argument und endet mit dem ersten und siehe da: Es geht <img src='http://blog.m-ri.de/wp-includes/images/smilies/icon_exclaim.gif' alt=':!:' class='wp-smiley' /> </p>
<p>Schade, dass hier die ATL-Doku so lückenhaft ist. Das hätte mir hier, 2 Stunden Arbeit gespart.<br />
Ich hätte es auch schneller haben können, wenn ich mir aufmerksam die Implementierung von <em>CComPtr&lt;IDispatch&gt;::Invoke2</em> angesehen hätte (Man achte auf den Array varArgs):</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">inline</span> HRESULT CComPtr<span style="color: #000080;">&lt;</span>IDispatch<span style="color: #000080;">&gt;</span><span style="color: #008080;">::</span><span style="color: #007788;">Invoke2</span><span style="color: #008000;">&#40;</span>__in DISPID dispid, 
       __in VARIANT<span style="color: #000040;">*</span> pvarParam1, 
       __in VARIANT<span style="color: #000040;">*</span> pvarParam2, 
       __out_opt VARIANT<span style="color: #000040;">*</span> pvarRet<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">throw</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> 
<span style="color: #008000;">&#123;</span> 
 <span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span>pvarParam1 <span style="color: #000080;">==</span> <span style="color: #0000ff;">NULL</span> <span style="color: #000040;">||</span> pvarParam2 <span style="color: #000080;">==</span> <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span> 
   <span style="color: #0000ff;">return</span> E_INVALIDARG<span style="color: #008080;">;</span> 
 CComVariant varArgs<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#123;</span> <span style="color: #000040;">*</span>pvarParam2, <span style="color: #000040;">*</span>pvarParam1 <span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span> 
 DISPPARAMS dispparams <span style="color: #000080;">=</span> <span style="color: #008000;">&#123;</span> <span style="color: #000040;">&amp;</span>varArgs<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000dd;">2</span>, <span style="color: #0000dd;">0</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span> 
 <span style="color: #0000ff;">return</span> p<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>Invoke<span style="color: #008000;">&#40;</span>dispid, IID_NULL, LOCALE_USER_DEFAULT, 
     DISPATCH_METHOD, <span style="color: #000040;">&amp;</span>dispparams, pvarRet, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<hr /><small>Copyright &copy; 2010 Martin Richter<br />Dieser Feed ist nur für den persönlichen, nicht gewerblichen Gebrauch bestimmt. Eine Verwendung dieses Feeds bzw. der hier veröffentlichten Beiträge auf anderen Webseiten bedarf der ausdrücklichen Genehmigung des Autors.<br />(Digital Fingerprint: bdafe67664ea5aacaab71f8c0a581adf)</small>]]></content:encoded>
			<wfw:commentRss>http://blog.m-ri.de/index.php/2008/02/02/wie-man-sich-mit-ccomdispatchdriver-bzw-ccomptrinvoken-hereinlegen-kann/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

