<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>cristib</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/cristib/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/cristib/feed.xml</link>
    <description>Office Development Blog</description>
    <lastBuildDate>Wed, 17 Apr 2019 03:21:26 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>C++ / VBA - How to send a COM object from VBA to a C++ DLL via PInvoke</title>
      <link>https://docs.microsoft.com/archive/blogs/cristib/send_com_object_from_vba_to_dll_via_pinvoke</link>
      <pubDate>Fri, 21 Oct 2016 18:05:39 GMT</pubDate>
      <dc:creator><![CDATA[Cristian.Berescu]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cristib/?p=615</guid>
      <description><![CDATA[Today I would like to present a quite uncommon scenario, which involves requesting a COM object from...]]></description>
      <content:encoded><![CDATA[<span style="font-size: 14px">Today I would like to present a quite uncommon scenario, which involves requesting a<strong> COM object</strong> from VBA and forwarding it
through <strong>PInvoke</strong> to another <strong>C++ DLL</strong>.</span>

<span style="font-size: 14px">The puzzling part is that if we work with managed <strong>COM</strong> DLLs, everything runs properly, but if we're using <strong>C++</strong> DLLs, </span><span style="font-size: 14px;background-color: #daffb4">Office will
crash with an  <strong>Access Violation</strong>!</span>

<!--HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->

<span style="font-size: 14px">
Here's some background info. about the components involved ...</span>

<span style="font-family: Calibri;font-size: 17px">
<span style="color: #0000ff"><strong>COM object originates from a simple C++ COM DLL</strong></span></span>

<span style="font-size: 14px">This is the <strong>Interface</strong> from which VBA gets its <strong>COM </strong>object. I created it based on based on a MSDN sample: <a href="https://code.msdn.microsoft.com/vstudio/CppDllCOMServer-27b87d03">In-process C++ </a><span style="font-size: 14px">
<a href="https://code.msdn.microsoft.com/vstudio/CppDllCOMServer-27b87d03">COM server (CppDllComServer)</a>.
</span></span>

<span style="font-size: 14px">Besides the usual <strong>COM interfaces</strong> (<strong>IUnknown</strong>, <strong>IDispatch</strong>), it exposes an <strong>interface</strong> named <strong>ISimpleObject</strong> and a <strong>COM Class</strong>
that implements it.</span>

<!--CODE TABLE #1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="width: 800px;height: 48px" border="1">
<tbody>
<tr>
<td style="border: 1px solid #dedede;line-height: 0.8em;background-color: #2b91af"><span style="color: #339966"></span>
<pre><span style="font-family: Courier New;font-size: 12px"><span style="color: #008000">/****************************** Module Header ******************************\
Module Name: SimpleObject.h
Project:     CppDllCOMServer
Copyright (c) Microsoft Corporation.

This source is subject to the Microsoft Public License.
See https://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
All other rights reserved.

THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
\***************************************************************************/</span>

#pragma once

#include 
#include "CppDllCOMServer_h.h" 

class SimpleObject : public ISimpleObject
{
public:
<span style="color: #008000"><strong>// IUnknown</strong></span>
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
IFACEMETHODIMP_(ULONG) AddRef();
IFACEMETHODIMP_(ULONG) Release();

<span style="color: #008000"><strong>// IDispatch</strong></span>
IFACEMETHODIMP GetTypeInfoCount(UINT *pctinfo);
IFACEMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo);
IFACEMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid);
IFACEMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pdispParams,   
</span><span style="font-family: Courier New;font-size: 12px">                      VARIANT *pvarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);

<span style="color: #008000"><strong>// ISimpleObject</strong></span>
IFACEMETHODIMP get_FloatProperty(FLOAT *pVal);
IFACEMETHODIMP put_FloatProperty(FLOAT newVal);
IFACEMETHODIMP HelloWorld(BSTR *pRet);
IFACEMETHODIMP GetProcessThreadID(LONG *pdwProcessId, LONG *pdwThreadId);

SimpleObject();
</span></pre>
</td>
</tr>
</tbody>
</table>
<!--CODE TABLE #1 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->

<!--PICT TABLE #1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="border-width: 3px 0px;border-style: solid;border-color: #cecece;width: 544px;height: auto" border="1">
<tbody>
<tr>
<td style="border-style: solid;border-color: #ffffff"><a href="https://msdnshared.blob.core.windows.net/media/2016/10/189.png"><img width="801" height="527" class="alignnone wp-image-625" alt="1" src="https://msdnshared.blob.core.windows.net/media/2016/10/189-1024x674.png" /></a></td>
</tr>
</tbody>
</table>
<!--PIC TABLE #1 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->

&nbsp;

&nbsp;

<strong><span style="color: #0000ff">VBA accesses the COM DLL via add Tools &gt; Reference</span></strong>
<!--CODE TABLE #2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="width: 800px;height: 48px" border="1">
<tbody>
<tr>
<td style="border: 1px solid #dedede;line-height: 0.8em;background-color: #2b91af"><span style="color: #339966"></span>
<pre><span style="color: #000000;font-family: Courier New;font-size: 12px">Sub test()
Dim comObj As CppDllCOMServerLib.SimpleObject
Set comObj = New SimpleObject

Debug.Print comObj.HelloWorld

End Sub
</span></pre>
</td>
</tr>
</tbody>
</table>
<!--CODE TABLE #2 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<!--PICT TABLE #2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="border-width: 3px 0px;border-style: solid;border-color: #cecece;width: 97px;height: 38px" border="1">
<tbody>
<tr>
<td style="border-style: solid;border-color: #ffffff"><a href="https://msdnshared.blob.core.windows.net/media/2016/10/259.png"><img width="637" height="469" class="alignnone size-full wp-image-635" alt="2" src="https://msdnshared.blob.core.windows.net/media/2016/10/259.png" /></a></td>
</tr>
</tbody>
</table>
<!--CHAPTER #3 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<span style="font-family: Calibri;font-size: 17px">
<span style="color: #0000ff"><strong>Finally, VBA forwards the COM Object to a different C++ DLL via PInvoke</strong></span></span>
<span style="font-size: 14px">
It's just a simple C++ DLL which exposes a function that takes in an <strong>ISimpleObject</strong> <strong>COM</strong> pointer.</span>
<!--CODE TABLE #3 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="width: 800px;height: 48px" border="1">
<tbody>
<tr>
<td style="border: 1px solid #dedede;line-height: 0.8em"><span style="color: #339966"></span>
<strong><span style="font-family: Courier New;font-size: 12px">Pinvoke_CppDllCOMServer.h</span></strong>
<pre><span style="color: #000000;font-family: Courier New;font-size: 12px">#include 
#include 
namespace SimplePInvokeDLL
{
  <span style="font-size: 12px;background-color: #daffb4">#import "C:\\..\\C++ COM DLL\Debug\\CppDllCOMServer.dll"</span>
  using namespace CppDllCOMServerLib;
  extern "C"
  {
   __declspec(dllexport) int __stdcall API_DummyCOMCall(ISimpleObject* iso);
   // Returns random number
   __declspec(dllexport) long API_DummyCall();
  }
}
</span></pre>
<strong><span style="font-family: Courier New;font-size: 12px">
Pinvoke_CppDllCOMServer.cpp</span></strong>
<pre><span style="color: #000000;font-family: Courier New;font-size: 12px">
#include "stdafx.h"
#include "Pinvoke_CppDllCOMServer.h"
#include &lt;stdlib.h&gt; 
#include &lt;time.h&gt;  

using namespace std;
namespace SimplePInvokeDLL
{
  __declspec(dllexport) long SimplePInvokeDLL::API_DummyCall()
 {
  <span style="font-family: Courier New;font-size: 12px"><span style="color: #008000">/* initialize random seed: */</span>
  srand(GetTickCount());

  <span style="font-family: Courier New;font-size: 12px"><span style="color: #008000">/* generate a random number*/</span>
  return rand();
 }

 __declspec(dllexport) int __stdcall API_DummyCOMCall(ISimpleObject* iso)
 {
  <span style="font-family: Courier New;font-size: 12px"><span style="color: #008000">//_bstr_t Class  https://msdn.microsoft.com/en-us/library/zthfhkd6.aspx
  /*
  A _bstr_t object encapsulates the BSTR data type. The class manages resource
  allocation and deallocation through function calls to SysAllocString and SysFreeString
  and other BSTR APIs when appropriate. The _bstr_t class uses reference counting to
  avoid excessive overhead.
  */</span>
		
  _bstr_t strComResult = iso-&gt;HelloWorld();
  _bstr_t strLocal = _bstr_t(L"HelloWorld");
 
  return strComResult == strLocal;
 }
}</span></span></span></span></pre>
</td>
</tr>
</tbody>
</table>
<!--CODE TABLE #3 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="border-width: 3px 0px;border-style: solid;border-color: #cecece;width: 100px;height: 22px" border="1">
<tbody>
<tr>
<td style="border-style: solid;border-color: #ffffff"><a href="https://msdnshared.blob.core.windows.net/media/2016/10/334.png"><img width="801" height="462" class="alignnone wp-image-645" alt="3" src="https://msdnshared.blob.core.windows.net/media/2016/10/334-1024x591.png" /></a></td>
</tr>
</tbody>
</table>
<span style="font-size: 14px"></span>
As I wrote before, the goal of our exercise is to obtain a <strong>COM pointer</strong> from the 1st DLL and forward it to the 2nd DLL, via VBA ..

<!--CODE TABLE #4 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="width: 800px;height: 48px" border="0">
<tbody>
<tr>
<td style="border: 1px solid #dedede;line-height: 0.8em;background-color: #2b91af"><span style="color: #339966"></span>
<pre><span style="color: #000000;font-family: Courier New;font-size: 12px">Declare Function <span style="background-color: #daffb4;font-family: Courier New;font-size: 12px">API_DummyCOMCall</span> Lib "C:\...\Debug\Pinvoke_CppDllCOMServer.dll" _
                </span><span style="color: #000000;font-family: Courier New;font-size: 12px">(simpleObj As <span style="font-size: small">CppDllCOMServerLib.SimpleObject</span>) As Integer

Sub test()
</span>
<span style="color: #000000;font-family: Courier New;font-size: 12px">Dim comObj As CppDllCOMServerLib.SimpleObject
Set comObj = New SimpleObject

Debug.Print comObj.HelloWorld

Debug.Print <span style="background-color: #b4daff;font-family: Courier New;font-size: 12px">API_DummyCOMCall</span>(<span style="background-color: #b4ffff;font-family: Courier New;font-size: 12px">comObj</span>)

End Sub
</span></pre>
</td>
</tr>
</tbody>
</table>
&nbsp;

<!--CODE TABLE #4 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->... the first part works, and we're getting a valid <strong>COM object </strong>from <strong>CppDllCOMServerLib</strong>:
<!--PICT TABLE #5 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="border-width: 3px 0px;border-style: solid;border-color: #cecece;width: 97px;height: 38px" border="1">
<tbody>
<tr>
<td style="border-style: solid;border-color: #ffffff"><a href="https://msdnshared.blob.core.windows.net/media/2016/10/519.png"><img width="800" height="566" class="alignnone wp-image-655" alt="5" src="https://msdnshared.blob.core.windows.net/media/2016/10/519.png" /></a><a href="https://msdnshared.blob.core.windows.net/media/2016/10/259.png"></a></td>
</tr>
</tbody>
</table>
<!--PICT TABLE #5 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->

&nbsp;

Now, if we attempt to send this <strong>COM object</strong> via a <strong>Pinvoke</strong> call...
<!--PICT TABLE #5 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="border-width: 3px 0px;border-style: solid;border-color: #cecece;width: 97px;height: 38px" border="1">
<tbody>
<tr>
<td style="border-style: solid;border-color: #ffffff"><a href="https://msdnshared.blob.core.windows.net/media/2016/10/614.png"><img width="800" height="562" class="alignnone wp-image-665" alt="6" src="https://msdnshared.blob.core.windows.net/media/2016/10/614.png" /></a></td>
</tr>
</tbody>
</table>
<!--PICT TABLE #5 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->

&nbsp;

<span style="font-family: Calibri;font-size: 17px">
<span style="color: #0000ff"><strong>Let's attach to the PInvoke DLL and see why we crash</strong></span></span>

First, we need to restart Excel, and pause the code just before we make the <strong>PInvoke</strong> call.
<!--PICT TABLE #6 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="border-width: 3px 0px;border-style: solid;border-color: #cecece;width: 97px;height: 38px" border="1">
<tbody>
<tr>
<td style="border-style: solid;border-color: #ffffff"><a href="https://msdnshared.blob.core.windows.net/media/2016/10/79.png"><img width="800" height="322" class="alignnone wp-image-675" alt="7" src="https://msdnshared.blob.core.windows.net/media/2016/10/79.png" /></a><a href="https://msdnshared.blob.core.windows.net/media/2016/10/614.png"></a></td>
</tr>
</tbody>
</table>
<!--PICT TABLE #6 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
Then we have to open the Visual Studio <strong>PInvoke</strong> <strong>C++ DLL</strong> <strong>project</strong>, and attach to the running instance of Excel. You'll also need to add a breakpoint on the PInvoke function which is used by VBA to send the COM pointer.
<!--PICT TABLE #7 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="border-width: 3px 0px;border-style: solid;border-color: #cecece;width: 97px;height: 38px" border="1">
<tbody>
<tr>
<td style="border-style: solid;border-color: #ffffff"><a href="https://msdnshared.blob.core.windows.net/media/2016/10/87.png"><img width="800" height="411" class="alignnone wp-image-676" alt="8" src="https://msdnshared.blob.core.windows.net/media/2016/10/87-1024x526.png" /></a><a href="https://msdnshared.blob.core.windows.net/media/2016/10/614.png"></a></td>
</tr>
</tbody>
</table>
<!--PICT TABLE #7 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->

&nbsp;

Finally, we switch back to Excel and resume executing the code. We'll soon hit the <strong>PInvoke C++</strong> callback function and if we
take a closer look at the input parameter, we'll see it points at an <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms680509(v=vs.85).aspx"><strong>IUnknown</strong> </a><strong>VTable</strong>.

The only problem here is that this <strong>VTable</strong> has a couple of <strong>NULL</strong> pointers inside ... now I don't know enough about COM to say
for sure that those bad addresses are the cause, but if we step through the code, we'll see that when trying to execute the
COM call, we end up trying to execute code from address zero, which is not very nice.
<!--PICT TABLE #8 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="border-width: 3px 0px;border-style: solid;border-color: #cecece;width: 790px;height: 731px" border="1">
<tbody>
<tr>
<td style="border-style: solid;border-color: #ffffff"><a href="https://msdnshared.blob.core.windows.net/media/2016/10/97.png"><img width="800" height="343" class="alignnone wp-image-686" alt="9" src="https://msdnshared.blob.core.windows.net/media/2016/10/97-1024x439.png" /></a><a href="https://msdnshared.blob.core.windows.net/media/2016/10/614.png"></a>
<a href="https://msdnshared.blob.core.windows.net/media/2016/10/108.png"><img width="801" height="369" class="alignnone wp-image-695" alt="10" src="https://msdnshared.blob.core.windows.net/media/2016/10/108-1024x472.png" /></a><a href="https://msdnshared.blob.core.windows.net/media/2016/10/614.png"></a></td>
</tr>
</tbody>
</table>
<!--PICT TABLE #8 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->

&nbsp;

&nbsp;

My idea was to find a proper way of sending <strong>COM pointers</strong> from VBA, and avoid <strong>NULL</strong> <strong>VTable</strong> pointers inside the <strong>PInvoke</strong> DLL
callback function. After asking around, I was told that VBA has a special operator which returns the address of an object:
<!--CODE TABLE #9 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="border-width: 1px 1px 0px;border-color: #000000;width: 800px;background-color: #ededed" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1px solid #000000;line-height: 0.8em"><a href="https://support.microsoft.com/en-us/kb/199824"><span style="font-family: courier new,courier;font-size: 12px"><strong>How To Get the Address of Variables in Visual Basic</strong></span></a>

<!--EndFragment--><span style="font-family: courier new,courier;font-size: x-small">[...]</span><span style="font-family: courier new,courier"> <span style="color: #000000;font-family: Times New Roman"> </span></span>

<b><span style="color: black;font-family: 'Courier New';font-size: 10pt">ObjPtr</span></b>
<table align="center" style="border-width: 3px 0px;border-style: solid;border-color: #7a7a7a;width: 746px;height: 168px" border="1">
<tbody>
<tr>
<td valign="top" style="border-style: solid;border-color: #dadada;line-height: 0.8em">
<pre><span style="color: #000000;font-family: Courier New;font-size: 12px">ObjPtr takes an object variable name as a parameter and obtains the address of the interface referenced by
this object variable. One scenario of using this function is when you need to do a collection of objects. 
By indexing the object using its address as t</span><span style="color: #000000;font-family: Courier New;font-size: 12px">he key, you can get faster access to the object than walking
the collection and using the Is operator. In many cases, the address of an object is the only reliable 
thing to use as a key.

Example:
objCollection.Add MyObj1, CStr(ObjPtr(MyObj1))
objCollection.Remove CStr(ObjPtr(MyObj1))</span></pre>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<!--CODE TABLE #9 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->

&nbsp;

&nbsp;

So, we will have to modify our <strong>PInvoke</strong> declaration and the way we send the <strong>COM object</strong> like this. <span style="background-color: #ffffb4;font-size: 14px">Notice that since <strong>ObjPtr</strong>
returns an address, we need to change the <strong>PInvoke</strong> method's input parameter's type from <strong>SimpleObject</strong> to <strong>LongPtr</strong></span>.
<!--CODE TABLE #10 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="width: 800px;height: 48px" border="0">
<tbody>
<tr>
<td style="border: 1px solid #dedede;line-height: 0.8em;background-color: #2b91af"><span style="color: #339966"></span>
<pre><span style="color: #000000;font-family: Courier New;font-size: 12px">Declare Function API_DummyCOMCall Lib "C:\...\Debug\Pinvoke_CppDllCOMServer.dll" _
                </span><span style="color: #000000;font-family: Courier New;font-size: 12px">(<span style="background-color: #ffffb4;font-family: Courier New;font-size: 12px">ByVal simpleObj</span> As <span style="background-color: #daffb4;font-family: Courier New;font-size: 12px">LongPtr</span>) As Integer

Sub test()
</span>
<span style="color: #000000;font-family: Courier New;font-size: 12px">Dim comObj As CppDllCOMServerLib.SimpleObject
Set comObj = New SimpleObject

Debug.Print comObj.HelloWorld

Debug.Print <span style="background-color: #b4daff;font-family: Courier New;font-size: 12px">API_DummyCOMCall</span>(<span style="background-color: #ffffb4;font-family: Courier New;font-size: 12px">ObjPtr</span><span style="background-color: #b4ffff;font-family: Courier New;font-size: 12px">(comObj)</span>)

End Sub
</span></pre>
</td>
</tr>
</tbody>
</table>
&nbsp;

<!--CODE TABLE #10 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->

What's that? VBA complains about the <a href="https://msdn.microsoft.com/en-us/library/984x0h58.aspx">calling convention </a>... hmmm.

<!--PICT TABLE #11 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="border-width: 3px 0px;border-style: solid;border-color: #cecece;width: 800px;height: 582px" border="1">
<tbody>
<tr>
<td style="border-style: solid;border-color: #ffffff"><a href="https://msdnshared.blob.core.windows.net/media/2016/10/1115.png"><img width="801" height="584" class="alignnone wp-image-705" alt="11" src="https://msdnshared.blob.core.windows.net/media/2016/10/1115.png" /></a></td>
</tr>
</tbody>
</table>
<!--PICT TABLE #11 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->

&nbsp;

After some research I found that <strong>PInvoke  C++ DLL</strong> functions which take parameters must have the "<strong>__stdcall</strong>" <a href="https://msdn.microsoft.com/en-us/library/zxk0tw93.aspx">calling </a>
<a href="https://msdn.microsoft.com/en-us/library/zxk0tw93.aspx">convention</a>, so that cleaning up the <strong>Stack </strong>gets done by the callee. With this occasion we're losing our nicely formatted function
names and we'll get <a href="https://msdn.microsoft.com/en-us/library/56h2zst2.aspx">decorated names</a> instead …

<!--PICT TABLE #12 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="border-width: 3px 0px;border-style: solid;border-color: #cecece;width: 800px;height: 23px" border="1">
<tbody>
<tr>
<td style="border-style: solid;border-color: #ffffff"><a href="https://msdnshared.blob.core.windows.net/media/2016/10/1212.png"><img width="800" height="664" class="alignnone wp-image-715" alt="12" src="https://msdnshared.blob.core.windows.net/media/2016/10/1212.png" /></a><a href="https://msdnshared.blob.core.windows.net/media/2016/10/1115.png"></a></td>
</tr>
</tbody>
</table>
<!--PICT TABLE #12 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->

&nbsp;

Let's fix the VBA code to reflect that change in calling conventions.
<!--CODE TABLE #13 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="width: 800px;height: 48px" border="0">
<tbody>
<tr>
<td style="border: 1px solid #dedede;line-height: 0.8em;background-color: #2b91af"><span style="color: #339966"></span>
<pre>Declare Function API_DummyCOMCall Lib "C:\...\Debug\Pinvoke_CppDllCOMServer.dll" _
                 <span style="background-color: #daffb4;font-family: Courier New;font-size: 12px">Alias "_API_DummyCOMCall@4"</span>(ByVal simpleObj As LongPtr) As Integer

Sub test()

<span style="color: #000000;font-family: Courier New;font-size: 12px">Dim comObj As CppDllCOMServerLib.SimpleObject
Set comObj = New SimpleObject

Debug.Print comObj.HelloWorld

Debug.Print API_DummyCOMCall(ObjPtr<span style="background-color: #b4ffff;font-family: Courier New;font-size: 12px">(comObj)</span>)

End Sub
</span></pre>
</td>
</tr>
</tbody>
</table>
<!--CODE TABLE #13 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
Success! We can now send <strong>COM objects</strong> from <strong>VBA</strong> to <strong>C++</strong> DLLs and not crash Office in the process :).

<strong>Source code download link:</strong> <span style="font-size: 14px"><a href="https://msdnshared.blob.core.windows.net/media/2016/10/Example-C-COM-DLL-send-COM-pointer-from-VBA-with-PInvoke.zip">Example - C++ COM DLL send COM pointer from VBA with PInvoke</a></span>

&nbsp;

&nbsp;

<span><strong>Thank you for reading my article! If you have liked it, please use the rating button.</strong></span>

<strong>P.S. </strong><span>I can’t always manage to reply to your comments as fast as I’d like. Just drop me an email at cristib-at-microsoft-dot-com,
should you need help with understanding or getting </span><span>something in my blog to work. </span>

<!--CODE TABLE #14 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<table style="width: 800px;height: 383px" border="1">
<tbody>
<tr>
<td style="border: 1px solid #dedede;line-height: 0.7em;background-color: #000000"><span style="color: #339966"></span>
<pre><span style="color: #000000;font-family: Courier New;font-size: 12px">
DISCLAIMER:

Please note that the code I have offered is just a proof of concept and should not be put into 
production without a thorough testing! 

Microsoft is not responsible if your users will lose data because of this programming solution. 
It’s your responsibility to test it before deployment in your organization.

THIS SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESSED OR </span><span style="color: #000000;font-family: Courier New;font-size: 12px">IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR 
FITNESS FOR A PARTICULAR PURPOSE.

We grant You a nonexclusive, royalty-free right to use and modify the Sample Code and to reproduce and
distribute the object code form of the Sample Code, provided that. You agree: 
(i) to not use Our name, logo, or trademarks to market Your software product in which the Sample Code 
is embedded; 
(ii) to include a valid copyright notice on Your software product in which the Sample Code is embedded;
and 
(iii) to indemnify, hold harmless, and defend Us and Our suppliers from and against any claims or lawsuits,
including attorneys’ fees, that arise or result from the use or distribution of the Sample Code.
</span></pre>
</td>
</tr>
</tbody>
</table>
<!--CODE TABLE #14 END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->]]></content:encoded>
    </item>
    <item>
      <title>MSI - Generate SHA2 certificate with OpenSSL and sign a MSI installer project, use 'Application Control Policies'-'AppLocker' to block unsigned code</title>
      <link>https://docs.microsoft.com/archive/blogs/cristib/msi-generate-sha2-certificate-with-openssl-and-sign-a-msi-installer-project-use-application-control-policies-applocker-to-block-unsigned-code</link>
      <pubDate>Fri, 24 Oct 2014 01:57:00 GMT</pubDate>
      <dc:creator><![CDATA[Cristian.Berescu]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cristib/2014/10/24/msi-generate-sha2-certificate-with-openssl-and-sign-a-msi-installer-project-use-application-control-policies-applocker-to-block-unsigned-code/</guid>
      <description><![CDATA[Some time ago I had to troubleshoot an issue with signed native C++ XLL&nbsp;add-ins for Excel,...]]></description>
      <content:encoded><![CDATA[<p>Some time ago I had to troubleshoot an issue with signed native C++ XLL&nbsp;add-ins for Excel, which didn't get <br />loaded with certain combinations of Excel and Windows.</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 590px; background-color: #ededed;" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<div class="itemDetail"><span style="font-family: courier new,courier;"><strong>Symptom</strong></span>
<pre><span style="font-family: courier new,courier;">- A client has developed an unmanaged XLL add-in for Excel, which has been<br /> signed with a code signing certificate that uses SHA2 as hashing algorithm.<br /><br />- Everything works as expected when the XLL is deployed to Windows XP + Excel 2007<br /> machines.<br /><br />- However, when loaded in Windows 7 + Excel 2007 environments, Office will flag<br /> the add-in signature&rsquo;s as invalid and it refuses to load this extension. The <br /> security settings are set to allow only signed add-ins to load. <br /><br />- On the other hand, the same XLL works fine in Excel 2010 and 2013. <br /><br />- This issue seems to reproduce even when using simple workbooks which contain<br /> macros, if these files get signed with paid certificates, as well as with free<br /> versions (as long as they use a SHA2 encryption) obtained from OpenSSL.com<br /> (<a href="https://www.openssl.org/docs/HOWTO/certificates.txt">https://www.openssl.org/docs/HOWTO/certificates.txt</a>). </span></pre>
</div>
<div class="itemDetail"><span style="font-family: courier new,courier;"><strong>Cause</strong></span>
<pre><span style="font-family: courier new,courier;">- Our developers found that it was a flaw in Office 2007, where an internal buffer<br /> length issue causes the error in Windows 7. <br /><br />- Office 2010 had been affected by this problem as well, but it got addressed in a<br /> hotfix: <a href="https://support.microsoft.com/kb/2598139">https://support.microsoft.com/kb/2598139</a>. Unfortunately since Office<br /> 2007 is out of mainstream support, its code remained unpatched.</span> </pre>
</div>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;<br />Initially I tried to narrow the problem down, as&nbsp;we needed to understand if the Office client or Windows OS&nbsp;was <br />responsible for the aforementioned behavior. <br /><br />The simplest test&nbsp;would have been&nbsp;to generate a SHA2 certificate and check if Windows allows a signed <br />executable&nbsp;(it can be anything as long as it has no connection&nbsp;with Office) to run. <br /><br />For the executable, I decided to use a basic&nbsp;<strong>MSI&nbsp;Installer</strong> project and for the SHA2 signature&nbsp;validation I used a<br />built-in security&nbsp;feature&nbsp;named '<span style="background-color: #eaeaea;"><strong>AppLocker</strong></span>', which <a title="How does AppLocker differ from Software Restriction Policies?" href="https://technet.microsoft.com/en-us/library/ee619725(v=ws.10).aspx#BKMK_SRPdifferences" target="_blank">extends</a> the&nbsp;'<span style="background-color: #eaeaea;"><strong>Software Restriction Policies</strong></span>'.<br /><br />Because I couldn't find a very clear set of instructions on how one can generate its own&nbsp;certificates with&nbsp;<strong>OpenSSL</strong><br />and&nbsp;apply&nbsp;<strong>AppLocker</strong>&nbsp;restrictions&nbsp;for MSI projects, I&nbsp;decided to share this info with you.&nbsp;<br /><strong><br /><br /><br /><span style="font-size: small;">Generate a self-signed&nbsp;Root&nbsp;CA, an Intermediate CA and&nbsp;a&nbsp;SHA2 certificate&nbsp;</span></strong></p>
<p><strong>1.</strong>&nbsp;&nbsp;&nbsp; Download the compiled OpenSSL&nbsp;binaries from this&nbsp;page: <a href="https://www.openssl.org/related/binaries.html">https://www.openssl.org/related/binaries.html</a>;<br /><strong>2.</strong>&nbsp;&nbsp;&nbsp; Install&nbsp;<strong>Microsoft Visual C++ 2008 Redistributable Package (x86)</strong>;<br /><strong>3.</strong>&nbsp;&nbsp;&nbsp; Extract the OpenSSL archive and run the installer project&nbsp;(for my test I used this path: <span style="background-color: #cecece;">C:\OpenSSL-Win32</span>);<br /><strong>4.&nbsp;&nbsp;&nbsp; </strong>Create another folder to keep track on the output files you are going to generate (<span style="background-color: #cecece;">C:\OpenSSL</span>);<br /><strong>5.</strong>&nbsp;&nbsp;&nbsp; Open a CMD window and change directory to the location where <strong>OpenSSL.exe</strong> is found<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;(<span style="background-color: #cecece;">C:\OpenSSL-Win32\bin</span>);<br /><strong>6.</strong>&nbsp;&nbsp;&nbsp; Run this command create a root&nbsp;CA key file:</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 562px; height: 47px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><strong><span style="font-family: courier new,courier;">openssl genrsa -out&nbsp;"C:\OpenSSL\Test_CertAuthority.key" 4096</span></strong></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3343.1.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3343.1.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3343.1.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3343.1.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><strong>7.</strong>&nbsp;&nbsp;&nbsp;&nbsp;Now run&nbsp;this command to generate a root CA certificate based on the key file created at the previous<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;step;&nbsp;You will be prompted to enter some details;<br /><br /><span style="background-color: #ffff99;">&nbsp;Note</span>:&nbsp; <strong>OpenSSL.exe</strong> will complain that it can't find a required <strong>.cfg</strong> file; Use an additional <strong><span style="background-color: #ccffcc;">-config</span></strong> parameter<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;to provide a valid path;</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 562px; height: 47px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><strong><span style="font-family: courier new,courier;"><span id="#h1" class="KeywordHighlight">openssl req -new -x509</span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -days&nbsp;365 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -key "C:\OpenSSL\Test_CertAuthority.key"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;-out "C:\OpenSSL\Test_CertAuthority.crt" <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="background-color: #ccffcc;">-config "C:\OpenSSL-Win32\bin\openssl.cfg"</span></span></strong></p>
</td>
</tr>
</tbody>
</table>
<p>... fill-in this info. when prompted:</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 562px; height: 47px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier;">Country Name (2 letter code) [AU]:<span style="background-color: #ccffcc;">US</span></span><br /><span style="font-family: courier new,courier;">State or Province Name (full name) [Some-State]:<span style="background-color: #ccffcc;">.</span></span><br /><span style="font-family: courier new,courier;">Locality Name (eg, city) []:<span style="background-color: #ccffcc;">.</span></span><br /><span style="font-family: courier new,courier;">Organization Name (eg, company) [Internet Widgits Pty Ltd]:<span style="background-color: #ccffcc;">TestMS</span></span><br /><span style="font-family: courier new,courier;">Organizational Unit Name (eg, section) []:<span style="background-color: #ccffcc;">TestOrgUnit</span></span><br /><span style="font-family: courier new,courier;">Common Name (e.g. server FQDN or YOUR name) []:<span style="background-color: #ccffcc;">CristiB</span></span><br /><span style="font-family: courier new,courier;">Email Address []:<span style="background-color: #ccffcc;">cristib@microsoft.com</span></span></p>
<p><span style="font-family: courier new,courier;">Please enter the following 'extra' attributes</span><br /><span style="font-family: courier new,courier;">to be sent with your certificate request</span><br /><span style="font-family: courier new,courier;">A challenge password []:<span style="background-color: #ccffcc;">.</span></span><br /><span style="font-family: courier new,courier;">An optional company name []:<span style="background-color: #ccffcc;">.</span></span></p>
</td>
</tr>
</tbody>
</table>
<p><br /><span style="background-color: #ffff99;">&nbsp;Note</span>:&nbsp; I could have linked my certificate directly to the <strong>Root CA</strong>, but it would be safer to keep&nbsp;it isolated&nbsp;and<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;introduce an intermediate CA layer in between .. for more details,&nbsp;please read these articles:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt; &nbsp;<strong>Certification Authority Trust Model&nbsp;</strong>(<a title="https://technet.microsoft.com/en-us/library/cc962065.aspx" href="https://blogs.msdn.com/controlpanel/blogs/posteditor.aspx/link" target="_blank">link</a>)&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp; <strong>Benefits of Multiple-Level Certification Hierarchies</strong>&nbsp;(<a title="https://technet.microsoft.com/en-us/library/cc962078.aspx" href="https://blogs.msdn.com/controlpanel/blogs/posteditor.aspx/link" target="_blank">link</a>);<br /><br /><strong>8.</strong>&nbsp;&nbsp;&nbsp; Create an IA key and a CSR file:&nbsp;</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 562px; height: 47px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><strong><span style="font-family: courier new,courier;"><span class="KeywordHighlight">openssl genrsa -out "C:\OpenSSL\Test_IntermediateCertAuthority.key" 4096<br /><br />openssl req -new <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -key "C:\OpenSSL\Test_IntermediateCertAuthority.key"&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -out "C:\OpenSSL\Test_IntermediateCertAuthority.csr" <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -config "C:\OpenSSL-Win32\bin\openssl.cfg"</span></span></strong></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;.. and fill-in this info. when prompted:</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 562px; height: 47px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier;">Country Name (2 letter code) [AU]:<span style="background-color: #ccffcc;">US</span></span><br /><span style="font-family: courier new,courier;">State or Province Name (full name) [Some-State]:<span style="background-color: #ccffcc;">.</span></span><br /><span style="font-family: courier new,courier;">Locality Name (eg, city) []:<span style="background-color: #ccffcc;">.</span></span><br /><span style="font-family: courier new,courier;">Organization Name (eg, company) [Internet Widgits Pty Ltd]:<span style="background-color: #ccffcc;">TestMS</span></span><br /><span style="font-family: courier new,courier;">Organizational Unit Name (eg, section) []:<span style="background-color: #ccffcc;">TestOrgUnit_IntermediateAuthority</span></span><br /><span style="font-family: courier new,courier;">Common Name (e.g. server FQDN or YOUR name) []:<span style="background-color: #ccffcc;">CristiB_IntermediateAuthority</span></span><br /><span style="font-family: courier new,courier;">Email Address []:<span style="background-color: #ccffcc;">cristib@microsoft.com</span></span></p>
<p><span style="font-family: courier new,courier;">Please enter the following 'extra' attributes</span><br /><span style="font-family: courier new,courier;">to be sent with your certificate request</span><br /><span style="font-family: courier new,courier;">A challenge password []:<span style="background-color: #ccffcc;">.</span></span><br /><span style="font-family: courier new,courier;">An optional company name []:<span style="background-color: #ccffcc;">.</span></span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1581.3.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1581.3.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1581.3.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1581.3.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><br /><strong>9.</strong>&nbsp;&nbsp;&nbsp; Generate an <strong>IA certificate</strong> based on the <strong>root CA</strong> and the <strong>CSR</strong> file:&nbsp;</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 562px; height: 47px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><strong><span style="font-family: courier new,courier;"><span id="#h1" class="KeywordHighlight">openssl x509 -req&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -days 365 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -in "C:\OpenSSL\Test_IntermediateCertAuthority.csr"&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-CA "C:\OpenSSL\Test_CertAuthority.crt" <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -CAkey "C:\OpenSSL\Test_CertAuthority.key"&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -set_serial 01 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -sha256 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -out "C:\OpenSSL\Test_IntermediateCertAuthority.crt"</span></span></strong></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;">&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7522.4.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7522.4.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7522.4.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7522.4.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><strong>10.</strong>&nbsp;&nbsp; Now&nbsp;that we have the <strong>intermediate CA</strong> key and certificate we can package them inside a <strong>PKCS12</strong> type of<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;file:</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 562px; height: 47px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><strong><span style="font-family: courier new,courier;"><span id="#h1" class="KeywordHighlight">openssl&nbsp;pkcs12 -export<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -out&nbsp;"C:\OpenSSL\SHA2_IA_Cert.p12"&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-inkey "C:\OpenSSL\Test_IntermediateCertAuthority.key" <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -in "C:\OpenSSL\Test_IntermediateCertAuthority.cer"&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-chain -CAfile "C:\OpenSSL\Test_CertAuthority.crt"&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -passout pass:123456&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -name My_SHA2_Cert</span></span></strong></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;">&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7838.5.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7838.5.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7838.5.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7838.5.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br />&nbsp;<br />Before you can use&nbsp;these certificates, you need to import them (<strong>Start</strong> &gt; <strong>Run</strong> &gt; <strong>certmgr.msc</strong>):<br />&gt;&nbsp;the top-level CA file (<span style="background-color: #eaeaea;"><strong>Test_CertAuthority.crt</strong></span>) goes into <strong>Trusted Root Certification Authorities</strong>;<br />&gt; the intermediate CA (<span style="background-color: #eaeaea;"><strong>Test_IntermediateCertAuthority.crt</strong></span>) gets imported into the <strong>Intermediate <br />&nbsp;&nbsp; Certification Authorities</strong>;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;">
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4540.6.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4540.6.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4540.6.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4540.6.jpg" alt="" border="0" /></a></p>
<p><br /><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3005.7.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3005.7.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3005.7.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3005.7.jpg" alt="" border="0" /></a></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;&nbsp;</p>
<p>&nbsp;<br /><strong><span style="font-size: small;">Build a very simple MSI Installer project using Visual Studio 2010 and sign its&nbsp;output</span><br /></strong></p>
<p><strong>1.</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Open a new&nbsp;<strong>Visual Studio Command Prompt</strong> and change directory to&nbsp;the&nbsp;'Debug' output folder where<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;the&nbsp;MSI project was compiled;<br /><strong>2.&nbsp;</strong>&nbsp;&nbsp;&nbsp;&nbsp;Use the 'SignTool' utility (<a href="https://msdn.microsoft.com/en-us/library/8s9b9yaz(v=vs.110).aspx">https://msdn.microsoft.com/en-us/library/8s9b9yaz(v=vs.110).aspx</a> - SignTool.exe),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;which ships with&nbsp;Visual Studio to sign the '<strong>Setup.exe</strong>' and '<strong>.MSI</strong>' file;</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 560px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier;">signtool sign /v /t <a href="https://timestamp.verisign.com/scripts/timestamp.dll">https://timestamp.verisign.com/scripts/times</a></span><span style="font-family: courier new,courier;"><a>tamp.dll</a><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;/f "C:\OpenSSL\SHA2_IA_Cert.p12"&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/p 123456&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="background-color: #ccffcc;">MSI_Signed_Installer.msi&nbsp;</span></span></p>
</td>
</tr>
</tbody>
</table>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 560px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier;">signtool sign /v /t <a href="https://timestamp.verisign.com/scripts/timestamp.dll">https://timestamp.verisign.com/scripts/times</a></span><span style="font-family: courier new,courier;"><a>tamp.dll</a><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;/f "C:\OpenSSL\SHA2_IA_Cert.p12"&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/p 123456&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="background-color: #ccffcc;">Setup.exe</span></span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4617.8.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4617.8.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4617.8.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4617.8.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><strong>3.&nbsp;</strong>&nbsp;&nbsp;&nbsp;&nbsp;Validate the&nbsp;signature by right-clicking on the files in <strong>Windows Explorer</strong> &gt; <strong>Properties</strong> &gt;<strong> Digital<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Signatures </strong>...</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7652.9.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7652.9.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7652.9.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7652.9.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;<br />... or by using the&nbsp;<strong>SignTool&nbsp;</strong>utility:</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 560px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier;">signtool verify /v /a setup.exe</span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7762.10.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7762.10.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7762.10.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7762.10.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p><span style="font-size: small;"><strong><br />Customize AppLocker to block all other installers except those signed with our certificate</strong></span></p>
<p><strong><br />1.&nbsp;</strong>&nbsp;&nbsp;&nbsp;&nbsp;Copy the output files form the MSI installer project&nbsp;to a&nbsp;machine;<br /><strong>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</strong>Copy the <strong>root&nbsp;CA</strong> (<span style="background-color: #eaeaea;"><strong>Test_CertAuthority.crt</strong></span>) and the<strong> intermediate CA</strong> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (<span style="background-color: #eaeaea;"><strong>Test_IntermediateCertAuthority.crt</strong></span>) certificates&nbsp;in the same environment (<span style="background-color: #ffff99;">make sure you do not</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="background-color: #ffff99;">accidentally copy the key files, which should be safely stored in a secure environment</span>);</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 560px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="background-color: #ffff99;">Note:</span>&nbsp;&nbsp;<span style="background-color: #ccffcc;">It is very important to deploy your certificates in the correct place.</span> Double-clicking on them will<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;get&nbsp;them installed into your <strong>Local&nbsp;User</strong>'s store which&nbsp;is not going to be seen by&nbsp;<strong>AppLocker</strong>.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="background-color: #ffff99;">If you're not careful,&nbsp;</span><span style="background-color: #ffff99;">you&nbsp;might spend&nbsp;hours troubleshooting <strong>Rules</strong> that would otherwise&nbsp;work<br /><span style="background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background-color: #ffff99;">perfectly&nbsp;</span></span>fine</span>.&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="background-color: #ccffcc;">For <strong>AppLocker</strong> to work properly and let you&nbsp;block <strong>.MSI</strong> installers based on <strong>Publishers</strong>, you will</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="background-color: #ccffcc;">have to&nbsp;deploy any certificate referenced in&nbsp;your <strong>Rules</strong>&nbsp;into the <strong>Local Computer</strong> store.</span></p>
</td>
</tr>
</tbody>
</table>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 560px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="background-color: #ffff99;">Note:</span>&nbsp;&nbsp;<span style="background-color: #ccffcc;">For the following steps you will need to be logged on using an Administrative account</span><span style="background-color: #ccffcc;">.</span></p>
</td>
</tr>
</tbody>
</table>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 560px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="background-color: #ffff99;">Note:</span>&nbsp;&nbsp;<span style="background-color: #ccffcc;">AppLocker only applies to normal user accounts, so members of the <strong>Administrators</strong> group will<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; not be blocked from running any MSI installers!</span></p>
</td>
</tr>
</tbody>
</table>
<p><strong><br />3.</strong>&nbsp;&nbsp;&nbsp;&nbsp; Deploy your certificates in the <strong>Local Computer</strong> certificate store: Open a&nbsp;new MMC console&nbsp;by going<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to <strong>Start&nbsp;</strong>&gt; <strong>Run</strong>&nbsp;&gt; <strong>MMC.msc </strong>&gt;<strong> File</strong> &gt;<strong> Add/Remove Snap-in...</strong>, find the <strong>Certificates</strong> entry in the snap-ins<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list &gt; click <strong>Add </strong>&gt; select '<strong>Computer account</strong>';</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1537.15.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1537.15.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1537.15.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1537.15.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><strong>4.</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Deploy the&nbsp;<strong>root CA</strong> into&nbsp;the <strong>Trusted Root Certification Authorities</strong> and the <strong>intermediate CA</strong> into&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;the <strong>Intermediate&nbsp;Certification Authorities</strong>;&nbsp;&nbsp;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1104.16.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1104.16.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1104.16.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1104.16.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><br /><strong>5.</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Open a&nbsp;new MMC console&nbsp;&gt; <strong>Start&nbsp;</strong>&gt; <strong>Run</strong>&nbsp;&gt; <strong>MMC.msc </strong>&gt;<strong> File</strong> &gt;<strong> Add/Remove Snap-in...</strong> and add the <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>Local Computer Policy</strong> management&nbsp;console as shown&nbsp;below:</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2211.11.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2211.11.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2211.11.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2211.11.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><strong>6.</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Inside the <strong>Local Computer Policy</strong> management console, expand these nodes:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; '<strong>Local Computer Policy</strong>'&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; '<strong>Windows Settings</strong>'&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&gt; '<strong>Security Settings</strong>'&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp;'<strong>Application Control Policies</strong>'&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; '<strong>AppLocker</strong>'&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt; '<strong>Windows Installer Rules</strong>' <br /><strong>7.</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Select '<strong>Create New Rule..</strong>' from the right-hand side <strong>Actions</strong> panel;<br /><strong>8.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</strong>Apply&nbsp;the following settings:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; '<strong>Action</strong>':&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<span style="background-color: #ccffcc;">Allow</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; '<strong>User or group</strong>': <span style="background-color: #ccffcc;">Everyone<span style="background-color: #ffffff;">;</span></span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; '<strong>Conditions</strong>':&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<span style="background-color: #ccffcc;">Publisher</span>;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3582.18.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3582.18.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3582.18.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3582.18.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; click '<strong>Browse</strong>'&nbsp;and&nbsp;select the signed <strong>.MSI</strong> file;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4617.13.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4617.13.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4617.13.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4617.13.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><strong></strong>&nbsp;</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 560px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="background-color: #ffff99;">Note:</span>&nbsp;&nbsp;In case you haven't installed the <strong>root CA</strong> and <strong>intermediate CA</strong>, the <strong>AppLocker</strong> Wizard will <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; display the&nbsp;following&nbsp;error when you will attempt&nbsp;to browse for a <strong>.MSI</strong> file:<br />&nbsp;<br /><span style="background-color: #ccffcc;"><strong><span style="font-family: courier new,courier;">The publisher information cannot be extracted from the specified file &lt;path&gt;. Reason: The object identifier does not represent&nbsp;a valid object. (Exception from HRESULT: 0x800710D8);</span></strong></span></p>
</td>
</tr>
</tbody>
</table>
<p><strong><br />9.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</strong>Customize the <strong>Publisher</strong> rule, to allow only our certificate to run. You do this by&nbsp;dragging the slider up<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;to&nbsp;'<strong>Publisher</strong>';</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6087.19.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6087.19.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6087.19.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6087.19.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;<br /><strong>10.</strong>&nbsp;&nbsp;&nbsp;&nbsp;Type&nbsp;a description in the <strong>Name&nbsp;</strong>field to complete the Wizard.&nbsp;&nbsp;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/5481.20.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/5481.20.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/5481.20.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/5481.20.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><strong>11.</strong>&nbsp;&nbsp;&nbsp;&nbsp;In case&nbsp;<strong>AppLocker</strong> wasn't used until now, you will be prompted to create a few default rules. Go ahead<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;and click <strong>YES</strong>.</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4442.21.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4442.21.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4442.21.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4442.21.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><strong>12.</strong>&nbsp;&nbsp;&nbsp;&nbsp;It seems that <strong>AppLocker</strong> will not enable your rules unless you explicitly enforce them.&nbsp;Inside the <strong>Local <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Computer Policy</strong> management console, expand&nbsp;these nodes:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; '<strong>Local Computer Policy</strong>'&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; '<strong>Windows Settings</strong>'&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&gt; '<strong>Security Settings</strong>'&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp;'<strong>Application Control Policies</strong>'&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; select the '<strong>AppLocker</strong>'&nbsp;node;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; click on '<strong>Configure rule enforcement</strong>';<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; mark the <strong>Windows Installer: Configured</strong>&nbsp;check-box;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; select <strong>Enforce rules </strong>and click <strong>OK</strong>;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4456.22.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4456.22.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4456.22.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4456.22.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><strong>13.</strong>&nbsp;&nbsp;&nbsp;&nbsp;Turn on the&nbsp;'<strong>Application Identity</strong>' service (<strong>Start</strong> &gt; <strong>Run</strong> &gt; type <strong>SERVICES.msc </strong>and hit<strong> ENTER</strong>); Find<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the aforementioned item and start it:</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0820.23.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0820.23.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0820.23.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0820.23.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><strong>14.</strong>&nbsp;&nbsp;&nbsp;&nbsp;Open CMD prompt and run '<strong>gpupdate /force</strong>';</p>
<p><br /><br /><span style="font-size: small;"><strong>Test that everything works</strong></span><br /><br /><strong></strong><strong>1.&nbsp;</strong>&nbsp;&nbsp;&nbsp;&nbsp; Switch to a non-privileged user account on that machine;<br /><strong>2.&nbsp;&nbsp;&nbsp;&nbsp; </strong>&nbsp;Check your user's certificates to verify that the <strong>root</strong> and <strong>intermediate&nbsp;CA</strong> are present; Notice that the<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; certificates inherited from the <strong>Local Machine</strong> store are marked with <strong>Status</strong> <strong>R</strong> (read-only);</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3582.24.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3582.24.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3582.24.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3582.24.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><strong><br />3.&nbsp;&nbsp;&nbsp;&nbsp; </strong>&nbsp;Check that the <strong>Setup.exe</strong> is signed and its certificate is valid;<br /><strong>4.&nbsp;</strong>&nbsp;&nbsp;&nbsp;&nbsp; Execute the installer;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/5873.25.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/5873.25.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/5873.25.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/5873.25.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><strong><br />5.&nbsp;</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Try to execute an unsigned installer package (notice that the <strong>Digital Signatures</strong> tab is missing in the<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>Properties</strong> window); You should get this error:</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 560px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="background-color: #ffffff;"><strong><span style="font-family: courier new,courier;">The system administrator has set policies to prevent this installation.</span></strong></span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3223.26.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3223.26.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3223.26.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3223.26.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;<strong><br />6.&nbsp;</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Also, the error gets logged in <strong>Event Viewer</strong>:</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4338.27.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4338.27.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4338.27.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4338.27.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 560px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="background-color: #ffffff;"><strong><span style="font-family: courier new,courier;">The installation of &lt;MSI package&gt; is not permitted by software restriction<br />policy. The Windows Installer only allows installation of unrestricted<br />items. The authorization level returned by software restriction policy was<br />0x0.</span></strong></span></p>
</td>
</tr>
</tbody>
</table>
<p><br /><br />I&nbsp;would have liked to mention&nbsp;some interesting topics related to&nbsp;how <strong>Certificate Authorities</strong> and <strong>AppLocker<br /></strong> rules work, but my article is already&nbsp;too long to bore you with additional stuff.&nbsp;But if you&nbsp;want to learn more,&nbsp;<br />you may find these links useful:<br /><br /><strong>Certification Authority Guidance</strong> <a href="https://technet.microsoft.com/en-us/library/hh831574.aspx">https://technet.microsoft.com/en-us/library/hh831574.aspx</a>;<br /><strong>Understanding AppLocker Rules </strong><a href="https://technet.microsoft.com/en-us/library/dd759068.aspx">https://technet.microsoft.com/en-us/library/dd759068.aspx</a>;</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 590px; background-color: #ededed;" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier; font-size: x-small;"><span style="font-size: small;"><strong><strong>Understanding AppLocker Rules (<span style="font-family: courier new,courier; font-size: x-small;"><a title="Understanding AppLocker Rules" href="https://technet.microsoft.com/en-us/library/dd759068.aspx" target="_blank">LINK</a></span></strong></strong></span></span><span style="font-family: courier new,courier; font-size: small;"><strong>)</strong><br />-------------------------------------------------------------------</span> <!--EndFragment--></p>
<p><span style="font-family: courier new,courier; font-size: x-small;">[...]</span></p>
<p><span style="font-size: small;"><strong><span style="font-family: courier new,courier;">AppLocker rule behavior</span></strong></span></p>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;">If no <strong>AppLocker</strong> rules for a specific rule collection exist, all files</span><br /><span style="background-color: #ccffcc;"> with that file format are allowed to run.</span> <span style="background-color: #ffff99;">However, when an <strong>AppLocker</strong> </span><br /><span style="background-color: #ffff99;">rule for a specific rule collection is created, only the files </span><br /><span style="background-color: #ffff99;">explicitly allowed in a rule are permitted to run</span>. For example, if you<br /> create an executable rule that allows .exe files in <br />%SystemDrive%\FilePath to run, only executable files located in that <br />path are allowed to run.</span></p>
<p><span style="font-family: courier new,courier;">A rule can be configured to use either an allow or deny action:</span></p>
<ul>
<li><span style="font-family: courier new,courier;">Allow. You can specify which files are allowed to run in your<br /> environment and for which users or groups of users. You can also<br /> configure exceptions to identify files that are excluded from the<br /> rule.<br /></span></li>
<li><span style="font-family: courier new,courier;">Deny. You can specify which files are not allowed to run in your<br /> environment and for which users or groups of users. You can also<br /> configure exceptions to identify files that are excluded from the<br /> rule.</span></li>
</ul>
<p>&nbsp;<span style="font-family: courier new,courier; font-size: x-small;">[...]</span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p><span style="font-family: courier new,courier;"><strong><span style="background-color: #ffffff;">Thank you for reading my article! If you have liked it, please use the rating<br /> button.<br /><br /></span></strong></span><span style="font-family: courier new,courier;">I can't always&nbsp;manage to reply to your comments as&nbsp;fast&nbsp;as I'd like. Just&nbsp;drop me<br />an&nbsp;email at&nbsp;cristib-at-microsoft-dot-com, should&nbsp;you&nbsp;need&nbsp;help&nbsp;with understanding<br /> or&nbsp;getting </span><span style="font-family: courier new,courier;">something in my blog to work.&nbsp;</span></p>
<p><strong><span style="font-family: courier new,courier;">Bye :-)&nbsp;</span></strong></p>]]></content:encoded>
    </item>
    <item>
      <title>VBA - Access 2013 - Programmatically assigning a Form's (DAO RecordSet) Record Source to the result of Stored Procedure (ADO RecordSet) executed on a remote SQL Server triggers “Run time error 31 – Data provider could not be initialized” error message.</title>
      <link>https://docs.microsoft.com/archive/blogs/cristib/vba-access-2013-programmatically-assigning-a-forms-dao-recordset-record-source-to-the-result-of-stored-procedure-ado-recordset-executed-on-a-remote-sql-server-triggers-run-time-error-3</link>
      <pubDate>Thu, 28 Aug 2014 04:35:00 GMT</pubDate>
      <dc:creator><![CDATA[Cristian.Berescu]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cristib/2014/08/28/vba-access-2013-programmatically-assigning-a-forms-dao-recordset-record-source-to-the-result-of-stored-procedure-ado-recordset-executed-on-a-remote-sql-server-triggers-run-time-error-3/</guid>
      <description><![CDATA[Suppose we have this scenario where a local Access database uses Forms bound to SQL serverdata...]]></description>
      <content:encoded><![CDATA[<p><!--EndFragment--><strong><br />Suppose we have this scenario where a local Access database uses Forms bound to SQL server</strong><br /><strong>data sources:</strong></p>
<p>-&nbsp; a company has developed a front-end application based on MS Access 2007 and VBA, which has been<br />&nbsp; &nbsp;distributed&nbsp;to end-users as an ADP file;</p>
<p>-&nbsp; its back-end data source runs on SQL Server;</p>
<p>-&nbsp; on the client side, the front-end Access application contains <strong>Forms</strong> and they are programmatically bound to<br />&nbsp; &nbsp;<strong>ADO&nbsp;RecordSets</strong>; <br /><br />-&nbsp; in turn, those <strong>RecordSet</strong> objects get populated with data when Access is&nbsp;invoking a <strong>Stored Procedure&nbsp;</strong>on the<br />&nbsp; &nbsp;SQL&nbsp;Server;<br /><br />-&nbsp; end-users can sort the&nbsp;client-side Access <strong>Forms</strong> without any problems in Access 2007 and 2010;&nbsp;&nbsp;</p>
<p>-&nbsp; however,&nbsp;when migrating to&nbsp;Office&nbsp;2013 it was&nbsp;found that&nbsp;attempting to sort the&nbsp;bound <strong>Forms</strong> triggers&nbsp;this<br />&nbsp; &nbsp;runtime&nbsp;error:</p>
<table style="width: 250px; height: 48px; margin-left: 10px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #dedede;">
<p>&nbsp;"Data provider could not be initialized"<span style="font-family: courier new,courier; font-size: x-small;">&nbsp;</span>&nbsp;</p>
</td>
</tr>
</tbody>
</table>
<p><br />-&nbsp; on the other side, if those <strong>Forms&nbsp;</strong>are bound to a&nbsp; <strong>ADO RecordSets</strong>&nbsp;which&nbsp;retrieve&nbsp;their values directly&nbsp;from a<br />&nbsp; &nbsp;SQL&nbsp;<strong>Table</strong>,&nbsp;then sorting also&nbsp;works as expected in Access 2013;<br /><br /><br /><strong><strong>Steps to reproduce the issue</strong><strong>:</strong></strong></p>
<p>&nbsp;&nbsp;<strong>1.</strong>&nbsp; create a new SQL database;<br />&nbsp;&nbsp;<strong>2.</strong> &nbsp;insert a new <strong>Table</strong> and save it with some name&nbsp;(example: '<span style="background-color: #eaeaea;">dbo.tblSourceData</span>');<br />&nbsp;<strong> 3.</strong>&nbsp; populate the <strong>Table</strong> with&nbsp;values:</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1374.1.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1374.1.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1374.1.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1374.1.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><strong>4.&nbsp;</strong>&nbsp;create a new <strong>Stored Procedure</strong> named '<span style="background-color: #eaeaea;">dbo.TestSP_SQLServer</span>'; Paste this code:</p>
<table style="width: 552px; height: 86px; margin-left: 10px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #dedede;">
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp;CREATE</strong> <strong>PROCEDURE</strong></span> <strong><span style="color: #000000;">TestSP_SQLServer</span></strong></span><br /><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; AS</span></strong></span><br /><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; BEGIN</span></strong></span><br /><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp; SET NOCOUNT ON;</span></strong></span><br /><span style="font-family: courier new,courier;"><strong><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; SELECT </span><span style="color: #000000;">*</span><span style="color: #0000ff;"> FROM</span></strong> <strong>dbo.tblSourceData</strong>;</span><br /><strong><span style="color: #0000ff; font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; END</span></strong><br /><strong><span style="color: #0000ff; font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; GO</span></strong></p>
</td>
</tr>
</tbody>
</table>
<p><strong><br />5. &nbsp;</strong>test your <strong>Stored Procedure</strong> to verify that it returns the expected results:</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6431.2.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6431.2.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6431.2.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6431.2.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><strong><br />6.&nbsp; </strong>make sure your SQL server is accessible from the outside: enable SQL Server Browser service, create Firewall<br />&nbsp;&nbsp;&nbsp;&nbsp; rules to allow SQL to be visible on the network,&nbsp;grant remote access to&nbsp;your account;</p>
<p>&nbsp; [these steps are for preparing the client-side Form]</p>
<p><strong>7.</strong>&nbsp;&nbsp;switch to a client machine running Office 2010; Create a new Access <strong>Database</strong>;<br /><strong>8.</strong> &nbsp;create a blank <strong>Form</strong>, then save it as: '<span style="background-color: #eaeaea;">frmSQL_StoredProc_SourceData</span>';</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2500.3.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2500.3.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2500.3.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2500.3.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><strong><br />9.</strong>&nbsp;&nbsp;we want to display our&nbsp;<strong>Form</strong> in a tabular layout, so we'll have to enter&nbsp;<strong>Design</strong> mode, then select the top-level<br />&nbsp;&nbsp;&nbsp; &nbsp;window border, go to its '<strong>Property Sheet</strong>',&nbsp;and&nbsp;from&nbsp;the '<strong>Format</strong>' tab&nbsp;click on the&nbsp;'<strong>Default View</strong>' drop-down<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;and&nbsp;select '<strong>Datasheet</strong>';&nbsp;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2772.4.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2772.4.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2772.4.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2772.4.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Alternatively, you&nbsp;can&nbsp;create a <strong>Table</strong> with the '<strong>DataSheet</strong>' view selected by default by&nbsp;going to&nbsp;the&nbsp;'<strong>Create</strong>' <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tab,&nbsp;then to '<strong>More Forms</strong>'&nbsp;drop-down and selecting&nbsp;'<strong>Datasheet</strong>';</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3817.5.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3817.5.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3817.5.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3817.5.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><strong><br />10.&nbsp; </strong>at this point we'll need to add a few <strong>TextBox</strong> controls into our blank <strong>Form</strong>; Our SQL table has 7 columns<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; therefore we'll add 7&nbsp;items;<br /><strong>11.</strong>&nbsp;&nbsp;these controls are currently&nbsp;not bound to any data source, so&nbsp;we&nbsp;have to&nbsp;bring up the <strong>Property Sheet</strong> for<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;each&nbsp;of them,&nbsp;then&nbsp;go to the '<strong>Data</strong>' tab&nbsp;where&nbsp;we have to write a string value corresponding to the name<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; of the SQL <strong>Table</strong> column a particular&nbsp;<strong>TextBox&nbsp;</strong>control&nbsp;is bound to;&nbsp;&nbsp;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2476.6.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2476.6.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2476.6.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2476.6.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><strong>12.</strong>&nbsp;&nbsp;from the VBA code editor window, go to&nbsp;'<strong>Tools</strong>', '<strong>References</strong>'&nbsp;and&nbsp;insert a reference to '<span style="background-color: #eaeaea;">Microsoft ActiveX</span><span style="background-color: #eaeaea;">&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Data Objects 6.1 Library</span><span style="background-color: #ffffff;">'</span>, then paste this code inside a new <strong>Module</strong>:&nbsp;&nbsp;<br /><br /><strong>Note</strong>: I am using <span style="background-color: #eaeaea;">SQL Native Client 2012</span> to connect to a SQL 2012 back-end server.</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 590px; background-color: #ededed;" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier;">Sub Test()</span></p>
<p><span style="font-family: courier new,courier;">Dim o_rs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As New ADODB.Recordset</span><br /><span style="font-family: courier new,courier;">Dim connectionStr As String</span><br /><span style="font-family: courier new,courier;">Dim connection&nbsp;&nbsp;&nbsp; As ADODB.connection</span><br /><span style="font-family: courier new,courier;">Dim cmd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As ADODB.Command</span></p>
<p><span style="color: #008000; font-family: courier new,courier;">'https://msdn.microsoft.com/en-us/library/ms130822.aspx (Using Connection <br />'String Keywords with SQL Server Native Client)</span></p>
<p><span style="font-family: courier new,courier;">connectionStr = "Provider=SQLNCLI11.1;" &amp; _</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Server=CRISTISQL2;" &amp; _</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Initial Catalog=<span style="background-color: #ffff99;">TestStoredProcedure</span>;" &amp; _</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "User ID=sa;" &amp; _</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Password=123;" </span></p>
<p><span style="font-family: courier new,courier;">Set connection = New ADODB.connection</span><br /><span style="font-family: courier new,courier;">connection.ConnectionString = connectionStr</span><br /><span style="font-family: courier new,courier;">connection.Open</span></p>
<p><span style="font-family: courier new,courier;">Set cmd = New ADODB.Command</span><br /><span style="font-family: courier new,courier;">cmd.ActiveConnection = connection</span><br /><span style="font-family: courier new,courier;">cmd.CommandType = adCmdStoredProc</span><br /><span style="font-family: courier new,courier;">cmd.CommandText = "<span style="background-color: #ffff99;">TestSP_SQLServer</span>"</span></p>
<p><span style="font-family: courier new,courier;">Set o_rs = New ADODB.Recordset<br /><br /></span><span style="color: #008000; font-family: courier new,courier;">'https://www.access-programmers.co.uk/forums/showthread.php?t=62482<br />'the following line is needed to avoid a runtime error when attempting<br />'to programmatically bind the Form to the&nbsp;'o_rs' RecordSet object:<br />'_________________________________________________________________<br />' Run-time error '7965':<br />' The object you entered is not a valid Recordset property.<br /></span><span style="color: #008000; font-family: courier new,courier;">'_________________________________________________________________<br /></span><br /><span style="font-family: courier new,courier; background-color: #ccffcc;">o_rs.CursorLocation = adUseClient</span><br /><br /><span style="font-family: courier new,courier;">o_rs.Open "TestSP_SQLServer", connection, adOpenKeyset, adLockOptimistic</span></p>
<p><span style="font-family: courier new,courier;">DoCmd.OpenForm "frmSQL_StoredProc_SourceData", acFormDS, , , acFormEdit, acWindowNormal</span></p>
<p><span style="font-family: courier new,courier;">Set [Form_frmSQL_StoredProc_SourceData].Recordset = o_rs</span><br /><span style="font-family: courier new,courier;">DoCmd.OpenForm "frmSQL_StoredProc_SourceData", acFormDS</span></p>
<p><span style="color: #008000; font-family: courier new,courier;">'-------------------------------------------------------------------------<br />'Display the data we fetched from SQL in the VBA Immediate window:<br /></span><br /><span style="font-family: courier new,courier;">Dim item_fld As Variant</span><br /><span style="font-family: courier new,courier;">Dim strCols As String</span><br /><span style="font-family: courier new,courier;">strCols = ""</span><br /><span style="font-family: courier new,courier;">For Each item_fld In o_rs.Fields</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; strCols = strCols &amp; item_fld.Name &amp; vbTab</span><br /><span style="font-family: courier new,courier;">Next</span><br /><span style="font-family: courier new,courier;">Debug.Print strCols</span></p>
<p><span style="font-family: courier new,courier;">Dim strItems As String</span><br /><span style="font-family: courier new,courier;">strItems = ""</span><br /><span style="font-family: courier new,courier;">Do While Not o_rs.EOF</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; strItems = o_rs(0).Value &amp; vbTab &amp; o_rs(1).Value &amp; vbTab &amp; o_rs(2).Value</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; Debug.Print strItems</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; strItems = ""</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; o_rs.MoveNext</span><br /><span style="font-family: courier new,courier;">Loop</span></p>
<p><span style="font-family: courier new,courier;">End Sub</span></p>
</td>
</tr>
</tbody>
</table>
<p><strong><br />13.</strong>&nbsp; execute the code .. your <strong>Form</strong> should&nbsp;display these records:</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0218.7.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0218.7.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0218.7.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0218.7.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><strong>14.&nbsp;</strong>&nbsp;right-click on any <strong>Column</strong>, then click on '<strong>Sort A to Z</strong>' or '<strong>Sort Z to A</strong>';</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/5670.8.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/5670.8.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/5670.8.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/5670.8.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br />Everything works in Office 2010 ... however step <strong>#14</strong> fails when running Access 2013&nbsp;our action will&nbsp;result in <br />this error message:</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: auto;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2248.9.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2248.9.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2248.9.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2248.9.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p><strong><strong>Why do we get this error?<br /></strong></strong><br />It seems that this is not supposed to work ... <br /><br />I have discussed with&nbsp;a senior Escalation resource&nbsp;from the&nbsp;MS Access support team and&nbsp;I've been told that<br /> internally an Access <strong>Form</strong>'s <strong>RecordSet</strong> object is&nbsp;built&nbsp;on&nbsp;a design inherited from&nbsp;<strong>DAO </strong>(for more information<br />see: <a href="https://msdn.microsoft.com/en-us/library/ms810810.aspx">https://msdn.microsoft.com/en-us/library/ms810810.aspx</a> - <em>Data Access Technologies Road Map</em>).<br /><br />In our scenario, we are working with&nbsp;<strong>ADO</strong> <strong>Recordsets</strong>&nbsp;connected to SQL, therefore these are not native <br />Access data objects. Our internal database contains lots of entries for the "<span style="background-color: #eaeaea;">Data provider could not be <br />initialized</span>" error when sorting, filtering, refreshing or&nbsp;requerying <strong>ADO Recordsets</strong> pointing at SQL <strong>Tables<br /></strong> and over the course of time customers&nbsp;have requested a fix.<br /><br />The Access Product Group carefully evaluated this behavior and decided not to&nbsp;provide a fix&nbsp;up to this in point<br /> in time. This&nbsp;is&nbsp;due to the&nbsp;complexity of the changes that would have to be made in the product&nbsp;(very high dev<br />and test costs) to fully support&nbsp;<strong>ADO Recordsets</strong>.</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 590px; background-color: #ededed;" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier;"><a href="https://msdn.microsoft.com/en-us/library/aa261340(v=vs.60).aspx">https://msdn.microsoft.com/en-us/library/aa261340(v=vs.60).aspx<br /></a></span><br /><span style="font-family: courier new,courier; font-size: small;"><strong>ADO Compared with RDO and DAO</strong></span><br /><span style="font-family: courier new,courier;">------------------------------------------------------------------------------</span><br /><span style="font-family: courier new,courier;"><br /><span style="background-color: #ccffcc;"><strong>ADO</strong> isn't automatically code-compatible with your existing data access applications</span>. While ADO encapsulates the <em>functionality</em> of DAO and RDO, you must convert many of the language elements over to ADO syntax. In some cases, this will mean only a simple conversion of some functions of your existing code. In other cases, it might be best to rewrite the application using ADO's new features.</span></p>
<p><span style="font-family: courier new,courier;"><strong>DAO</strong> (Data Access Objects) was the first object-oriented interface that exposed the Microsoft Jet database engine (used by Microsoft Access) and allowed Visual Basic developers to directly connect to Access tables - as well as other databases - through ODBC. DAO is suited best for either single-system applications or for small, local deployments.</span></p>
<p><span style="font-family: courier new,courier;"><strong>RDO</strong> (Remote Data Objects) is an object-oriented data access interface to ODBC combined with the easy-to-use style of DAO, providing an interface that exposes virtually all of ODBC�s low-level power and flexibility. RDO is limited, though, in that it doesn't access Jet or ISAM databases very well, and that it can access relational databases only through existing ODBC drivers. However, RDO has proven to be the interface of choice for a large number of SQL Server, Oracle, and other large relational database developers. RDO provides the objects, properties, and methods needed to access the more complex aspects of stored procedures and complex resultsets.</span></p>
<p><span style="font-family: courier new,courier;"><strong>ADO</strong> is the successor to DAO/RDO. Functionally ADO 2.0 is most similar to RDO, and there's generally a similar mapping between the two models. ADO "flattens" the object model used by DAO and RDO, meaning that it contains fewer objects and more properties, methods (and arguments), and events. For example, ADO has no equivalents to the rdoEngine and rdoEnvironment objects, which exposed the ODBC driver manager and hEnv interfaces. Nor can you currently create ODBC data sources from ADO, despite the fact that your interface might be through the ODBC OLE DB service provider.</span></p>
<p><span style="font-family: courier new,courier;">Much of the functionality contained in the DAO and RDO models was consolidated into single objects, making for a much simpler object model. Because of this, however, you might initially find it difficult to find the appropriate ADO object, collection, property, method, or event. Unlike DAO and RDO, although ADO objects are hierarchical, they are also creatable outside the scope of the hierarchy.</span></p>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;">It should be noted, however, that ADO currently doesn't support all of DAO's functionality</span>. ADO mostly includes RDO-style functionality to interact with OLE DB data sources, plus remoting and DHTML technology.</span></p>
<p><span style="font-family: courier new,courier;">In general, it's probably too early in the evolution of ADO to migrate most DAO applications (except possibly ones using ODBCDirect) to ADO right now, since ADO doesn't currently support data definition (DDL), users, groups, and so forth. If you use DAO only for client-server applications and don't rely on the Jet database engine or use DDL, however, then you can probably migrate to ADO now. Eventually, Microsoft will provide an ADO DDL component to aid in DAO-to-ADO migration and provide generic DDL support for OLE DB providers.</span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p><strong><strong>Finding&nbsp;a workaround...<br /></strong></strong><br />There are&nbsp;two possible solutions:<br />&nbsp;&nbsp;&gt; use DAO instead of ADO to connect to SQL (but this is not a very good&nbsp;long term approach since DAO is<br />&nbsp;&nbsp;&nbsp; &nbsp;deprecated);&nbsp;&nbsp;<br />&nbsp; &gt;&nbsp;use&nbsp;linked Access <strong>Tables</strong> (on the client-side database application)&nbsp;and bind the <strong>Forms</strong> to those local data<br />&nbsp;&nbsp;&nbsp; &nbsp;sources&nbsp;(<a href="https://support.microsoft.com/kb/281998">https://support.microsoft.com/kb/281998</a> - <em>How to bind Microsoft Access forms to ADO recordsets<!--EndFragment--></em>);<br /><br /><br /><strong><strong><strong>Designing and implementing the fix</strong></strong></strong><br /><br />We are going to implement the second workaround and for this purpose we will need to introduce these <br />changes:<br /><br /><span style="color: #0000ff;"><strong>[Server side]</strong></span><br /><br />&nbsp;&nbsp; -&nbsp;a temporary&nbsp;<strong>Table</strong>&nbsp;has to be created dynamically in SQL; It will&nbsp;contain the&nbsp;output&nbsp;data obtained&nbsp;by running<br />&nbsp;&nbsp;&nbsp; &nbsp;the <strong>Stored&nbsp;Procedure</strong>;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; <span style="background-color: #ffff99;">Note:</span>&nbsp;&nbsp;I started this article with the assumption that we were using a simple Access <strong>Form</strong> bound to a simple<br />&nbsp;&nbsp;&nbsp; &nbsp;SQL&nbsp;<strong>Stored&nbsp;</strong><strong>Procedure</strong> data source. But as you can imagine,&nbsp;in real life this scenario is&nbsp;more&nbsp;complex. The <br />&nbsp;&nbsp;&nbsp;&nbsp; <strong>Stored Procedure</strong>&nbsp;takes several input&nbsp;<strong>Parameters</strong>&nbsp;and it executes a complex&nbsp;<strong>JOIN</strong> on several SQL <strong>Tables<br />&nbsp;&nbsp;&nbsp; </strong>&nbsp;to return some results. Different users will work with&nbsp;different <strong>Parameter</strong> combinations, so we cannot&nbsp;store<br />&nbsp;&nbsp;&nbsp;&nbsp; the&nbsp;<strong>Stored&nbsp;Procedure</strong>&nbsp;output values in an unique temp. SQL <strong>Table&nbsp;</strong>... instead, each Access client will have<br />&nbsp;&nbsp;&nbsp; &nbsp;its own&nbsp;unique temporary <strong>Table </strong>in SQL and will be responsible for cleaning it up when done; <br /><br />&nbsp;&nbsp; -&nbsp;since each Access client will have its own corresponding temporary <strong>Table</strong> in SQL, clients&nbsp;must&nbsp;have a way to<br />&nbsp;&nbsp;&nbsp; &nbsp;send a&nbsp;<strong>String</strong>&nbsp;that uniquely identifies&nbsp;their data source; This means that the <strong>Stored Procedure</strong> will&nbsp;receive an<br />&nbsp;&nbsp;&nbsp; &nbsp;input&nbsp;<strong>Parameter</strong>: [<span style="background-color: #eaeaea;"><strong><span style="font-family: courier new,courier;">strSqlOutputTempTableName</span></strong></span>];<br /><br />&nbsp;&nbsp; -&nbsp;an additional input <strong>Parameter</strong> added to the SQL&nbsp;<strong>Stored Procedure</strong> will allow&nbsp;Access clients to select the SQL<br />&nbsp;&nbsp;&nbsp; &nbsp;<strong>Table</strong> that is being queried: [<strong><span style="font-family: courier new,courier; background-color: #eaeaea;">strSqlSourceTableName</span></strong>]; As I wrote in the <span style="background-color: #ffff99;">Note</span> above, in real life scenarios&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lots of other input <strong>Parameters</strong> may be added, since clients may want&nbsp;to execute <strong>JOINS&nbsp;</strong>between several<br />&nbsp;&nbsp;&nbsp; &nbsp;<strong>Tables</strong>,&nbsp;use&nbsp;filter criteria ..etc;<br /><br />&nbsp;&nbsp;&nbsp;-&nbsp; the <strong>Stored Procedure</strong> will be resaved as '<span style="background-color: #eaeaea;">dbo.TestSP_SQLServer2</span>';&nbsp;</p>
<table style="width: 570px; height: 415px; margin-left: 20px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #dedede;">
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><strong>USE</strong></span> <span style="color: #008080;">TestStoredProcedure</span><br /></span><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier;">GO</span></strong></span></p>
<p><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier;">SET ANSI_NULLS ON<br /></span><span style="font-family: courier new,courier;">GO<br /><br /></span><span style="font-family: courier new,courier;">SET QUOTED_IDENTIFIER ON<br /></span><span style="font-family: courier new,courier;">GO</span></strong></span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><strong>CREATE PROCEDURE</strong></span> <span style="color: #008080;">TestSP_SQLServer2</span><br /></span><span style="font-family: courier new,courier;"><span style="color: #008080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @strSqlOutputTempTableName NVARCHAR(<span style="color: #000000;">100</span>)</span>,<br /></span><span style="color: #008080; font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @strSqlSourceTableName NVARCHAR(<span style="color: #000000;">100</span>)<br /></span><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier;">AS</span></strong></span><br /><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier;">BEGIN</span></strong></span><br /><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><strong>&nbsp;DECLARE</strong></span> <span style="color: #008080;">@SQLQuery NVARCHAR(<span style="color: #000000;">100</span>)</span>;</span><br /><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><strong>&nbsp;DECLARE</strong></span> <span style="color: #008080;">@NewLineChar <span style="color: #0000ff;"><strong>AS CHAR(</strong><span style="color: #000000;">2</span><strong>)</strong></span> <span style="color: #000000;">=</span> <span style="color: #0000ff;"><strong>CHAR(</strong><span style="color: #000000;">13</span><strong>) <span style="color: #000000;">+</span> CHAR(</strong><span style="color: #000000;">10</span><strong>)</strong></span></span></span><br /><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier;">&nbsp;SET nocount on</span></strong></span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><strong>&nbsp;SET</strong></span> <span style="color: #008080;">@SQLQuery</span> =&nbsp;<strong><span style="color: #ff0000;">'SELECT * INTO '</span></strong>&nbsp;+&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #ff00ff;"><strong>CAST</strong></span>(<span style="color: #008080;">@strTmpOutputTableName</span> <span style="color: #0000ff;"><strong>As NVARCHAR</strong></span>) +&nbsp;<span style="color: #008080;">@NewLineChar</span> +</span><br /><span style="font-family: courier new,courier;"><span style="color: #ff0000;"><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'FROM '</strong></span> + <span style="color: #ff00ff;"><strong>CAST</strong></span>(<span style="color: #008080;">@strSourceTableName</span> <span style="color: #0000ff;"><strong>As NVARCHAR</strong></span>) + <span style="color: #ff0000;"><strong>';'</strong></span></span><br /><span style="font-family: courier new,courier;">&nbsp;PRINT <span style="color: #008080;">@SQLQuery</span></span><br /><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;">&nbsp;EXEC (<span style="color: #008080;">@SQLQuery</span>)</span><br /><strong><span style="color: #008000;">&nbsp;-- <span style="background-color: #ccffcc;">EXEC parameter needs to be enclosed in "( )"</span>, else we get this error:</span></strong></span><br /><strong><span style="color: #008000; font-family: courier new,courier;">&nbsp;-- "Could not find stored procedure 'CREATE TABLE ..."</span></strong></p>
<p><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier;">END</span></strong></span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Before switching to the client side, go ahead and execute the new <strong>Stored Procedure</strong> in SQL&nbsp;to make sure <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; everything is OK ..</p>
<table style="width: 575px; height: 17px; margin-left: 20px;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #dedede;">
<p><span style="color: #0000ff;"><strong>exec</strong></span> <span style="color: #008080;">dbo.TestSP_SQLServer2</span> <span style="color: #008080;">@strTmpOutputTableName</span> =<span style="color: #ff0000;"><strong> 'tmpTbl'</strong></span>,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #008080;">@strSourceTableName&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;=<span style="color: #ff0000;"><strong> 'tblSourceData'</strong></span>;</p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.. this should be&nbsp;your output:</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: 100%; margin-left: 20px;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6204.10.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6204.10.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6204.10.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6204.10.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;<span style="color: #0000ff;"><strong><br /><br />[Client side]<br /><br /></strong></span>&nbsp;&nbsp; - we'll start by generating&nbsp;an unique name to be able to identify the temporary <strong>Table</strong> from SQL (for <br />&nbsp;&nbsp;&nbsp;&nbsp; demonstration purposes my code uses the machine name and a time stamp):&nbsp;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: 100%; margin-left: 20px;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;">&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6457.13.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6457.13.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6457.13.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6457.13.jpg" alt="" width="409" height="461" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 590px; background-color: #ededed;" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier;">Dim oShell As Object</span></p>
<p><span style="font-family: courier new,courier;">Set oShell = CreateObject("WScript.Shell")<br /><br /></span><span style="font-family: courier new,courier;">strSqlOutputTempTableName = "tmp_" &amp; _</span><span style="font-family: courier new,courier;">&nbsp;<br />Replace(oShell.ExpandEnvironmentStrings("%ComputerName%"), "-", "_") &amp; "_" &amp; _<br /></span><span style="font-family: courier new,courier;">Format(Now, "yyyymmddhhms")</span></p>
<p><span style="font-family: courier new,courier;">Set oShell = Nothing</span></p>
</td>
</tr>
</tbody>
</table>
<p><br />&nbsp;&nbsp; -&nbsp;the temporary&nbsp;SQL <strong>Table</strong> gets created when we invoke our SQL <strong>Stored Procedure</strong> using this VBA function:</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 590px; background-color: #ededed;" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;"><strong>Module1</strong><br />---------------------------------------------------------------------------------</span><br />Sub Execute_SQL_StoredProc(strSqlStoredProcName As String, </span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strSqlOutputTempTableName As String,&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strSqlSourceTableName As S</span><span style="font-family: courier new,courier;">tring)</span></p>
<p><span style="font-family: courier new,courier;">Dim </span><span style="font-family: courier new,courier;">m_cnnStr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As String<br /></span><span style="font-family: courier new,courier;">Dim </span><span style="font-family: courier new,courier;">m_cnn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As New ADODB.Connection<br /></span><span style="font-family: courier new,courier;">Dim </span><span style="font-family: courier new,courier;">m_cmd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As New ADODB.Command<br /></span><span style="font-family: courier new,courier;">Dim </span><span style="font-family: courier new,courier;">m_rst&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;As New ADODB.Recordset<br /></span><span style="font-family: courier new,courier;">Dim t</span><span style="font-family: courier new,courier;">mpRowsAffected As Long</span></p>
<p><strong><span style="color: #008000;"><span style="font-family: courier new,courier;">'SQL </span><span style="font-family: courier new,courier;">Native Client 2012<br /></span><span style="font-family: courier new,courier;">'----------------------------------------------------------------<br /></span></span></strong><span style="font-family: courier new,courier;">m_cnnStr = </span><span style="font-family: courier new,courier;">"Provider=SQLNCLI11.1;" &amp; _<br />&nbsp;</span><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Data </span><span style="font-family: courier new,courier;">Source=CRISTISQL2;" &amp; _<br /></span><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Persist Security </span><span style="font-family: courier new,courier;">Info=False;" &amp; _<br /></span><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Initial </span><span style="font-family: courier new,courier;">Catalog=TestStoredProcedure;" &amp; _<br /></span><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "User ID=sa;" </span><span style="font-family: courier new,courier;">&amp; _<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-family: courier new,courier;">"Password=123;"</span></p>
<p><strong><span style="color: #008000;"><span style="font-family: courier new,courier;">'"Integrated Security=false;" </span><span style="font-family: courier new,courier;"><a href="https://support.microsoft.com/kb/269495"><span style="color: #008000;">https://support.microsoft.com/kb/269495</span></a></span></span></strong></p>
<p><strong><span style="color: #008000;"><span style="font-family: courier new,courier;">'When you try to open an </span><span style="font-family: courier new,courier;">ActiveX Data Objects (ADO) connection, you may receive<br /></span><span style="font-family: courier new,courier;">'the f</span><span style="font-family: courier new,courier;">ollowing error message:<br /></span><span style="font-family: courier new,courier;">' </span><span style="font-family: courier new,courier;">&gt; Run-time error '-2147217887 (80040e21):'<br /></span><span style="font-family: courier new,courier;">' </span><span style="font-family: courier new,courier;">&gt; Multiple-step OLE DB operation generated errors. Check each OLE DB <br />'&nbsp;&nbsp; status </span><span style="font-family: courier new,courier;">value,&nbsp;</span><span style="font-family: courier new,courier;">if available. No work was done.<br /></span><span style="font-family: courier new,courier;">'----------------------------------------------------------------</span></span></strong></p>
<p><span style="font-family: courier new,courier;">m_cnn.Open </span><span style="font-family: courier new,courier;">m_cnnStr<br /></span><span style="font-family: courier new,courier;">m_cmd.ActiveConnection = </span><span style="font-family: courier new,courier;">m_cnn</span>&nbsp;</p>
<p><span style="font-family: courier new,courier;">m_cmd.CommandText = </span><span style="font-family: courier new,courier;">strSqlStoredProcName <br /></span><span style="font-family: courier new,courier;">m_cmd.CommandType = </span><span style="font-family: courier new,courier;">adCmdStoredProc</span></p>
<p><strong><span style="color: #008000; font-family: courier new,courier;">'https://msdn.microsoft.com/en-us/library/windows/desktop/ms675318(v=vs.85).aspx </span></strong><br /><strong><span style="color: #008000; font-family: courier new,courier;">- DataTypeEnum</span></strong></p>
<p><strong><span style="color: #008000; font-family: courier new,courier;">'https://msdn.microsoft.com/en-us/library/windows/desktop/ms677209(v=vs.85).aspx </span></strong><br /><strong><span style="color: #008000; font-family: courier new,courier;">- CreateParameter Method (ADO)</span></strong>&nbsp;</p>
<p><span style="font-family: courier new,courier;">m_cmd.Parameters.Append </span><span style="font-family: courier new,courier;">m_cmd.CreateParameter("<span style="background-color: #ffff99;">@strSqlOutputTempTableName</span>", <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adWChar,&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adParamInput, <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 100, </span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strSqlOutputTempTableName)<br /></span><span style="font-family: courier new,courier;"><br />m_cmd.Parameters.Append </span><span style="font-family: courier new,courier;">m_cmd.CreateParameter("<span style="background-color: #ffff99;">@strSqlSourceTableName</span>",&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adWChar,&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adParamInput, <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 100, </span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strSqlSourceTableName)<br /></span><span style="font-family: courier new,courier;"><span style="font-family: Arial;"><br /></span>m_cmd.Execute </span><span style="font-family: courier new,courier;">tmpRowsAffected</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p><span style="color: #008000;"><strong><span style="font-family: courier new,courier;">'https://support.microsoft.com/kb/195048 </span><span style="font-family: courier new,courier;">- How To Determine Number of Records Affected by an ADO </span><span style="font-family: courier new,courier;">UPDATE</span></strong></span></p>
<p><span style="font-family: courier new,courier;">Debug.Print </span><span style="font-family: courier new,courier;">vbNewLine<br /></span><span style="font-family: courier new,courier;">Debug.Print </span><span style="font-family: courier new,courier;">"[Execute_SQL_StoredProc] SQL stored procedure completed."<br /></span><span style="font-family: courier new,courier;">Debug.Print " &gt; SQL </span><span style="font-family: courier new,courier;">StoredProc name:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; " &amp; strSqlStoredProcName<br /></span><span style="font-family: courier new,courier;">Debug.Print " &gt; SQL output </span><span style="font-family: courier new,courier;">Temp table name: " &amp; strSqlOutputTempTableName<br /></span><span style="font-family: courier new,courier;">Debug.Print " &gt; SQL source </span><span style="font-family: courier new,courier;">table name:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; " &amp; strSqlSourceTableName<br /></span><span style="font-family: courier new,courier;">Debug.Print " &gt; Rows </span><span style="font-family: courier new,courier;">affected:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; " &amp; tmpRowsAffected</span></p>
<p><span style="font-family: courier new,courier;">End </span><span style="font-family: courier new,courier;">Sub</span></p>
</td>
</tr>
</tbody>
</table>
<p><br />&nbsp;&nbsp; -&nbsp;&nbsp;for the next step, we are&nbsp;linking the temporary SQL&nbsp;<strong>Table&nbsp;</strong>to a local one created inside the&nbsp;Access client;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; In turn the local <strong>Table</strong> gets programmatically set as data source (<strong>ADO RecordSet</strong>)&nbsp;for&nbsp;a local Access&nbsp;<strong>Form<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</strong>using this VBA function:</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 590px; background-color: #ededed;" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier;"><strong>Module1</strong><br />---------------------------------------------------------------------------------<br />Sub CreateLocal_SQL_TempLinkedTable(strSqlOutputTempTableName As </span><span style="font-family: courier new,courier;">String)</span></p>
<p><span style="font-family: courier new,courier;">If </span><span style="font-family: courier new,courier;">Len(strSqlOutputTempTableName) = 0 Then<br /></span><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; MsgBox "Error!</span><span style="font-family: courier new,courier;">[CreateLocal_SQL_TempLinkedTable] function didn't receive" &amp; _&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"a valid SQL server </span><span style="font-family: courier new,courier;">table name!"<br /></span><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; Exit </span><span style="font-family: courier new,courier;">Sub<br /></span><span style="font-family: courier new,courier;">End If</span></p>
<p><span style="font-family: courier new,courier;">Dim dbCurr As Database, </span><span style="font-family: courier new,courier;">dbLink As Database<br /></span><span style="font-family: courier new,courier;">Dim tdfLocal As </span><span style="font-family: courier new,courier;">TableDef</span></p>
<p><strong><span style="color: #008000;"><span style="font-family: courier new,courier;">'https://support.microsoft.com/kb/892490 </span><span style="font-family: courier new,courier;">How to create a DSN-less connection to SQL Server for linked tables in </span><span style="font-family: courier new,courier;">Access</span></span></strong></p>
<p><span style="font-family: courier new,courier;">Dim td&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As </span><span style="font-family: courier new,courier;">TableDef<br /></span><span style="font-family: courier new,courier;">Dim stConnect&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As </span><span style="font-family: courier new,courier;">String<br /></span><span style="font-family: courier new,courier;"><br />Dim stLocalTableName As </span><span style="font-family: courier new,courier;">String </span><strong><span style="color: #008000;"><span style="font-family: courier new,courier;">'</span><span style="font-family: courier new,courier;">Name of the table that you are creating in<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'the&nbsp;local Access&nbsp;</span></span></strong><strong><span style="color: #008000; font-family: courier new,courier;">database</span></strong></p>
<p><span style="font-family: courier new,courier;">Dim stRemoteTableName As </span><span style="font-family: courier new,courier;">String&nbsp;<span style="color: #008000;"><strong>'</strong></span></span><span style="color: #008000;"><strong><span style="font-family: courier new,courier;">Name of the table that you are linking to on<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'the SQL Server </span><span style="font-family: courier new,courier;">database</span></strong></span></p>
<p><span style="font-family: courier new,courier;">stLocalTableName&nbsp;&nbsp;= </span><span style="font-family: courier new,courier;">strSqlOutputTempTableName &amp; "_ExternalLink"<br /></span><span style="font-family: courier new,courier;">stRemoteTableName = </span><span style="font-family: courier new,courier;">strSqlOutputTempTableName</span>&nbsp;</p>
<p><span style="color: #008000;"><strong><span style="font-family: courier new,courier;"><span style="color: #000000; font-family: Arial;"><br /></span>'delete any existing linked </span><span style="font-family: courier new,courier;">SQL tables</span></strong></span></p>
<p><span style="font-family: courier new,courier;">For Each td In </span><span style="font-family: courier new,courier;">CurrentDb.TableDefs<br /></span><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; Debug.Print "&nbsp; &gt; </span><span style="font-family: courier new,courier;">Checking table [" &amp; td.Name &amp; "] .."</span></p>
<p><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; If td.Name = </span><span style="font-family: courier new,courier;">stLocalTableName Then<br /></span><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Debug.Print "&nbsp;&nbsp;&nbsp; Table </span><span style="font-family: courier new,courier;">found and deleted!"</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CurrentDb.TableDefs.Delete stLocalTableName<br /></span><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; End </span><span style="font-family: courier new,courier;">If<br /></span><span style="font-family: courier new,courier;">Next</span>&nbsp;</p>
<p><strong><span style="color: #008000;"><span style="font-family: courier new,courier;">'//WARNING: This will save </span><span style="font-family: courier new,courier;">the username and the password with the linked table </span></span></strong><br /><strong><span style="color: #008000; font-family: courier new,courier;">information.</span></strong></p>
<p><span style="color: #008000;"><strong><span style="font-family: courier new,courier;">'SQL Native Client </span><span style="font-family: courier new,courier;">2012<br /></span><span style="font-family: courier new,courier;">'----------------------------------------------------------------</span></strong></span></p>
<p><span style="font-family: courier new,courier;">stConnect = "ODBC;DRIVER=SQL </span><span style="font-family: courier new,courier;">Server Native Client 11.0;" &amp; _<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">"SERVER=CRISTISQL2;" &amp; _<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">"APP=Microsoft </span><span style="font-family: courier new,courier;">Office 2013;" &amp; _<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">"DATABASE=TestStoredProcedure;" &amp; _<br />&nbsp;</span><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "User ID=sa;" </span><span style="font-family: courier new,courier;">&amp; _<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">"Password=123;"</span></p>
<p><strong><span style="color: #008000;"><span style="font-family: courier new,courier;">'Microsoft OLEDB Provider for </span><span style="font-family: courier new,courier;">SQL Server<br /></span><span style="font-family: courier new,courier;">'----------------------------------------------------------------<br /></span></span><span style="color: #008000;"><span style="font-family: courier new,courier;">'stConnect = "ODBC;DRIVER=SQL </span><span style="font-family: courier new,courier;">Server;" &amp; _<br /></span><span style="font-family: courier new,courier;">'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "S</span><span style="font-family: courier new,courier;">ERVER=CRISTISQL2;" &amp; _<br /></span><span style="font-family: courier new,courier;">'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">"DATABASE=TestStoredProcedure;" &amp; _<br /></span><span style="font-family: courier new,courier;">'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">"UID=sa;" &amp; _<br /></span><span style="font-family: courier new,courier;">'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">"PWD=123;"</span></span></strong></p>
<p><span style="font-family: courier new,courier;">Set td = </span><span style="font-family: courier new,courier;">CurrentDb.CreateTableDef(stLocalTableName,&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbAttachSavePWD,&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stRemoteTableName, </span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stConnect)</span></p>
<p><span style="font-family: courier new,courier;">CurrentDb.TableDefs.Append </span><span style="font-family: courier new,courier;">td</span></p>
<p><span style="background-color: #ffff99;"><span style="font-family: courier new,courier;">Set </span><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;">Form_frmSQL_StoredProc_SourceData</span>.<span style="background-color: #ffcc99;">Recordset</span> = </span></span><br /><span style="font-family: courier new,courier; background-color: #ffff99;">CurrentDb.TableDefs(stLocalTableName).OpenRecordset</span></p>
<p><span style="font-family: courier new,courier;">Set td = </span><span style="font-family: courier new,courier;">Nothing</span></p>
<p><span style="font-family: courier new,courier;">End </span><span style="font-family: courier new,courier;">Sub</span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;<span style="color: #0000ff;"><strong><br /></strong></span>&nbsp;&nbsp; - all we need now is a way to trigger our code and to cleanup the temporary <strong>Tables</strong> when we are done; We will<br />&nbsp;&nbsp;&nbsp; &nbsp;use the <strong>Form_Load </strong>and <strong>Form_Close</strong> events:&nbsp;&nbsp;</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 590px; background-color: #ededed;" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier;"><strong>Form_frmSQL_StoredProc_SourceData</strong><br />---------------------------------------------------------------------------------<br />Option Compare Database</span></p>
<p><span style="font-family: courier new,courier;">Private strSqlOutputTempTableName As String</span></p>
<p><span style="font-family: courier new,courier;">Private Sub <span style="background-color: #ccffcc;">Form_Close</span>()</span><br /><span style="font-family: courier new,courier;">&nbsp; DoCmd.DeleteObject acTable, strSqlOutputTempTableName &amp; "_ExternalLink"</span><br /><span style="font-family: courier new,courier;">End Sub</span></p>
<p><span style="font-family: courier new,courier;">Private Sub <span style="background-color: #ccffcc;">Form_Load</span>()</span></p>
<p><span style="font-family: courier new,courier;">Dim oShell As Object<br /></span><span style="font-family: courier new,courier;">Set oShell = CreateObject("WScript.Shell")</span></p>
<p><span style="font-family: courier new,courier;">strSqlOutputTempTableName = "tmp_" &amp; _</span><br /><span style="font-family: courier new,courier;">Replace(oShell.ExpandEnvironmentStrings("%ComputerName%"), "-", "_") &amp; "_" &amp; _</span><br /><span style="font-family: courier new,courier;">Format(Now, "yyyymmddhhms")</span></p>
<p><span style="font-family: courier new,courier;">Set oShell = Nothing</span></p>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;">Execute_SQL_StoredProc</span> "dbo.TestSP_SQLServer2", <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strSqlOutputTempTableName, <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "tblSourceData"</span><br /><span style="font-family: courier new,courier;"><br /><span style="background-color: #ffff99;">CreateLocal_SQL_TempLinkedTable</span> strSqlOutputTempTableName</span></p>
<p><span style="font-family: courier new,courier;">End Sub</span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p><strong>That's it :-) </strong>! <br /><br />If you have done everything correctly, then once you double-click on your unbound Access <strong>Form</strong>, it should be<br />populated with data. <br /><br />Moreover, if you click on the <strong>Navigation Panel</strong> and press <strong>F5</strong> to refresh it, you will notice that a new linked<br /> <strong>Table </strong>object has appeared.</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: 100%;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;">&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7752.11.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7752.11.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7752.11.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7752.11.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>Now switch to the SQL server and see that a <strong>Table</strong> got created&nbsp;there as well.<br /><br /><span style="background-color: #ffff99;">Note:</span> my sample code will not clean up temporary <strong>Tables</strong> from SQL .. you will have to implement this <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; functionality;</p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #cecece; width: 544px; height: 100%;" border="1">
<tbody>
<tr>
<td style="border-style: solid; border-color: #ffffff;">&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6014.12.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6014.12.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6014.12.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6014.12.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br />&nbsp;</p>
<table style="border-width: 1px 1px 0px; border-style: solid; border-color: #000000; width: 590px; background-color: #000000;" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="color: #ffffff;"><strong><span style="color: #ffff00;">'DISCLAIMER:</span><br /><br /><span style="color: #ffff00;">Please note that the code I have offered is just a proof of concept and should not be put into </span><br /><span style="color: #ffff00;">production without a thorough testing! </span></strong></span></p>
<p><span style="color: #ffff00;"><strong>Microsoft is not responsible if your users will lose data because of this programming solution. <br />It&rsquo;s your responsibility to test it before deployment in your organization.</strong></span><span style="color: #ffffff;"><strong><br /></strong></span><span style="font-family: courier new,courier; font-size: x-small;"><span style="color: #ffffff;"><br /></span></span><span style="font-family: courier new,courier;"><span style="color: #ffffff;">THIS SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, </span></span><span style="font-family: courier new,courier;"><span style="color: #ffffff;">INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.</span></span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #ffffff;">We grant You a nonexclusive, royalty-free right to use and modify the Sample Code and to reproduce and distribute the object </span><span style="color: #ffffff;">code form of the Sample Code, provided that. You agree: <br /><span style="color: #ffff00;"><strong>(i)</strong></span> to not use Our name, logo, or trademarks to market Your software </span><span style="color: #ffffff;">product in which the Sample Code is embedded; <br /><span style="color: #ffff00;"><strong>(ii)</strong></span> to include a valid copyright notice on Your software product in which the </span><span style="color: #ffffff;">Sample Code is embedded; and <br /><span style="color: #ffff00;"><strong>(iii)</strong></span> to indemnify, hold harmless, and defend Us and Our suppliers from and against any claims </span><span style="color: #ffffff;">or lawsuits,&nbsp;including attorneys&rsquo; fees, that arise or result from the use or distribution of the Sample Code.</span></span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p><span style="font-family: courier new,courier;"><strong><span style="background-color: #ffffff;">Thank you for reading my article! If you have liked it, please use the rating button.<br />Bye :-)</span></strong></span><!--EndFragment--></p>
<p>&nbsp;</p>
<p>P.S.&nbsp;Things at work are very busy these days,&nbsp;so I can't always&nbsp;manage to reply to your comments as&nbsp;fast<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; as I'd like. If you&nbsp;need help with understanding or&nbsp;getting something in my blog to work, just&nbsp;drop me <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; an email at cristib-at-microsoft-dot-com.&nbsp;</p>
<p><br /><br />&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>VSTO - Deploying a VSTO Word 2003 add-in to All Users using a  CustomAction Installer override project for assigning CASPOL permissions</title>
      <link>https://docs.microsoft.com/archive/blogs/cristib/vsto-deploying-a-vsto-word-2003-add-in-to-all-users-using-a-customaction-installer-override-project-for-assigning-caspol-permissions</link>
      <pubDate>Thu, 28 Feb 2013 09:55:00 GMT</pubDate>
      <dc:creator><![CDATA[Cristian.Berescu]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cristib/2013/02/28/vsto-deploying-a-vsto-word-2003-add-in-to-all-users-using-a-customaction-installer-override-project-for-assigning-caspol-permissions/</guid>
      <description><![CDATA[&nbsp;




Deploying a VSTO 2003 add-in is a little more complicated than the 2007 and 2010...]]></description>
      <content:encoded><![CDATA[<p>&nbsp;</p>
<table style="width: 569px; height: 1940px;" border="0">
<tbody>
<tr>
<td>
<p><span style="font-family: %value;">Deploying a VSTO 2003 add-in is a little more complicated than the 2007 and 2010 versions. This is because VSTO 2003 solutions require explicit code execution permissions to be assigned using the CASPOL tool, otherwise they will fail to load.<br /><br />First we need to build a very simple Word 2003 add-in project.&nbsp;&nbsp;&nbsp;&nbsp; </span><br /><br /><span style="font-family: %value;"><strong>1.</strong>&nbsp; Open '<strong>Visual Studio 2008</strong>';</span><br /><span style="font-family: %value;"><strong>2.</strong>&nbsp; Go to '<strong>File</strong>' &gt; '<strong>New</strong>' &gt; '<strong>Project</strong>';</span><br /><span style="font-family: %value;"><strong>3.</strong>&nbsp; In '<strong>Project Types</strong>' &gt; go to '<strong>Visual C#</strong>' &gt; '<strong>Office</strong>' &gt; '<strong>2003</strong>' and select '<strong>Word 2003 Add-in</strong>';</span><br /><span style="font-family: %value;"><strong>4.</strong>&nbsp; Choose a <strong>Name </strong>and a <strong>Location</strong>&nbsp;for the project, then click '<strong>OK</strong>';</span><br /><span style="font-family: %value;"><strong>5.</strong>&nbsp; Insert the following code in '<strong>ThisAddIn.cs</strong>':</span></p>
<table style="background-color: #dedede; width: 560px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;">using</span> System;<br /><span style="color: #0000ff;">using</span> System.Windows.Forms;<br /><span style="color: #0000ff;">using</span> Microsoft.VisualStudio.Tools.Applications.Runtime;<br /><span style="color: #0000ff;">using</span> Word = Microsoft.Office.Interop.Word;<br /><span style="color: #0000ff;">using</span> Office = Microsoft.Office.Core;<br /><br />namespace WordAddIn2003_AllUsersDeployment<br />&nbsp;{<br />&nbsp; <span style="color: #0000ff;"><span style="color: #0000ff;">public </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">partial </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">class </span></span><span style="color: #2b91af;"><span style="color: #2b91af;">ThisAddIn<br />&nbsp; </span></span>{&nbsp;<br />&nbsp;&nbsp; <span style="color: #0000ff;"><span style="color: #0000ff;">private </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">void</span></span> ThisAddIn_Startup(<span style="color: #0000ff;"><span style="color: #0000ff;">object</span></span> sender, System.<span style="color: #2b91af;"><span style="color: #2b91af;">EventArgs</span></span> e)&nbsp;&nbsp; <br />&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><span style="color: #0000ff;">this</span></span>.Application.Startup += <span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span><br />&nbsp;&nbsp;&nbsp; Microsoft.Office.Interop.Word.ApplicationEvents4_StartupEventHandler<br />&nbsp;&nbsp;&nbsp; (Application_Startup);<br />&nbsp;&nbsp;}<br /><br />&nbsp; <span style="color: #0000ff;"><span style="color: #0000ff;">void</span></span> Application_Startup()<br />&nbsp; {<br />&nbsp;&nbsp; System.Windows.Forms.MessageBox.Show(<span style="color: #a31515;"><span style="color: #a31515;">"Test add-in loaded."</span></span>);<br />&nbsp;&nbsp;}&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;<span style="color: #0000ff;"><span style="color: #0000ff;">private</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">void</span></span> ThisAddIn_Shutdown(<span style="color: #0000ff;"><span style="color: #0000ff;">object</span></span> sender, System.<span style="color: #2b91af;"><span style="color: #2b91af;">EventArgs</span></span> e)<br />&nbsp; {}<br /><br />&nbsp; #regionVSTO generated code<br />&nbsp; <span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #808080;"><span style="color: #808080;">&lt;summary&gt;</span></span><span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #008000;"><span style="color: #008000;"> Required method for Designer support - do not modify<br />&nbsp; </span></span><span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #008000;"><span style="color: #008000;"> the contents of this method with the code editor.<br />&nbsp; </span></span><span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #808080;"><span style="color: #808080;">&lt;/summary&gt;<br /><br />&nbsp; </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">private</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">void</span></span> InternalStartup()<br />&nbsp; {<br />&nbsp;&nbsp; <span style="color: #0000ff;"><span style="color: #0000ff;">this</span></span>.Startup += <span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span> System.<span style="color: #2b91af;"><span style="color: #2b91af;">EventHandler</span></span>(ThisAddIn_Startup);<br />&nbsp;&nbsp; <span style="color: #0000ff;"><span style="color: #0000ff;">this</span></span>.Shutdown += <span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span> System.<span style="color: #2b91af;"><span style="color: #2b91af;">EventHandler</span></span>(ThisAddIn_Shutdown);<br />&nbsp; }<br />&nbsp;#endregion<br />&nbsp;}<br />}</span></p>
</td>
</tr>
</tbody>
</table>
<p><span style="font-family: %value;">&nbsp;<br /></span><strong>Customizing the&nbsp;deployment project</strong><br /><br />As you might have noticed, the Visual Studio wizard already built a Setup Project for our add-in Solution. If we take a look at its <strong>Properties</strong>, we'll notice that the add-in is already selected as '<strong>Primary Output</strong>'.<br /><br />The next thing we need to check are the Registry settings: right-click on the Setup project from '<strong>Solution Explorer</strong>' view, select '<strong>View</strong>' &gt; '<strong>Registry</strong>'.&nbsp;</p>
<table style="border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<h4><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/5187.1.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/5187.1.bmp"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/5187.1.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/5187.1.bmp" alt="" border="0" /></a></h4>
</td>
</tr>
</tbody>
</table>
<p><span style="font-family: %value;">&nbsp;If we dump the key structure in Notepad, it will look like this:</span></p>
<table style="background-color: #dedede; width: 560px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td><span style="font-family: courier new,courier;">Windows Registry Editor Version 5.00<br /><br />[<span style="background-color: #ffff99;">HKEY_CURRENT_USER</span>\Software\Classes\CLSID\{461A2C5C-EF1D-4E58-AF67-225827B056E4}]<br />&nbsp;@="WordAddIn2003_AllUsersDeployment -- an addin created with VSTO technology"&nbsp;<br /></span><span style="font-family: courier new,courier;"><br />[<span style="background-color: #ffff99;">HKEY_CURRENT_USER</span>\Software\Classes\CLSID\{461A2C5C-EF1D-4E58-AF67-225827B056E4}<br />&nbsp;\InprocServer32]<br />&nbsp;@=hex(2):25,00,43,00,6f,00,6d,00,6d,00,6f,00,6e,00,50,00,72,00,6f,00,67,00,72,\&nbsp; 00,61,00,6d,00,46,00,69,00,6c,00,65,00,73,00,25,00,5c,00,4d,00,69,00,63,00,\&nbsp; 72,00,6f,00,73,00,6f,00,66,00,74,00,20,00,53,00,68,00,61,00,72,00,65,00,64,\&nbsp; 00,5c,00,56,00,53,00,54,00,4f,00,5c,00,38,00,2e,00,30,00,5c,00,41,00,64,00,\&nbsp; 64,00,69,00,6e,00,4c,00,6f,00,61,00,64,00,65,00,72,00,2e,00,64,00,6c,00,6c,\&nbsp; 00,00,00<br />&nbsp;"ManifestName"="WordAddIn2003_AllUsersDeployment.dll.manifest"<br />&nbsp;"ThreadingModel"="Both"<br />&nbsp;"ManifestLocation"="C:\\Program Files\\ms\\WordAddIn2003_AllUsersDeploymentSetup\\"<br /><br />[<span style="background-color: #ffff99;">HKEY_CURRENT_USER</span>\Software\Classes\CLSID\{461A2C5C-EF1D-4E58-AF67-225827B056E4}<br />\ProgID]<br />&nbsp;@="WordAddIn2003_AllUsersDeployment"<br /><br />[<span style="background-color: #ffff99;">HKEY_CURRENT_USER</span>\Software\Classes\CLSID\{461A2C5C-EF1D-4E58-AF67-225827B056E4}<br />&nbsp;\Programmable]&nbsp;<br /><br />[<span style="background-color: #ffff99;">HKEY_CURRENT_USER</span>\Software\Classes\CLSID\{461A2C5C-EF1D-4E58-AF67-225827B056E4}<br />\VersionIndependentProgID]<br />&nbsp;@="WordAddIn2003_AllUsersDeployment"&nbsp;<br /><br />[<span style="background-color: #ffff99;">HKEY_CURRENT_USER</span>\Software\Classes\WordAddIn2003_AllUsersDeployment]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;@=""<br /><br />[<span style="background-color: #ffff99;">HKEY_CURRENT_USER</span>\Software\Classes\WordAddIn2003_AllUsersDeployment\CLSID]<br />&nbsp;@="{461A2C5C-EF1D-4E58-AF67-225827B056E4}"</span></td>
</tr>
</tbody>
</table>
<br /><br />As you may have noticed, the setup project targets the <strong>HKEY_CURRENT_USER</strong> Registry location. For us to successfully install the add-in to all users, we need to target the <strong>HKEY_LOCAL_MACHINE</strong> hive. <br /><br />We can quickly drag and drop these keys using the mouse,&nbsp;to fix this problem ...<br /><br />
<table style="border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<h4><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6332.2.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6332.2.bmp"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6332.2.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6332.2.bmp" alt="" border="0" /></a></h4>
</td>
</tr>
</tbody>
</table>
<h4>&nbsp;</h4>
<h4><strong>Manually granting CASPOL access to our solution</strong>&nbsp;&nbsp;</h4>
<p><span style="font-size: small;">The article <a href="https://msdn.microsoft.com/en-us/library/6exya3kf.aspx">https://msdn.microsoft.com/en-us/library/6exya3kf.aspx</a>&nbsp;</span>(<strong>Security Requirements to Run Office Solutions (2003 System)</strong>) states that Application-level and Document-level 2003 solutions will require full trust permission in .Net Framework ..&nbsp;</p>
<table style="background-color: #dedede; width: 560px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td>
<p class="title"><strong><span style="font-family: courier new,courier;">Security Requirements to Run Office Solutions (2003 System)</span></strong><span style="font-family: courier new, courier;"><a href="https://msdn.microsoft.com/en-us/library/6exya3kf.aspx">https://msdn.microsoft.com/en-us/library/6exya3kf.aspx</a></span><span style="font-family: courier new, courier;"><br /></span><span style="font-family: courier new, courier; font-size: small;">=======================================================================<br /></span><span style="font-family: courier new,courier;">[..]<br /><br /></span></p>
<p><span style="font-family: courier new,courier;">Document-level customizations and application-level add-ins incorporate the security features available in the .NET Framework. This enables your solution to take advantage of a range of evidence on which to base trust decisions.</span></p>
<p class="title"><span style="font-family: courier new,courier;">To deploy and run a Microsoft Office solution, <span style="background-color: #c0c0c0;">you must grant full trust to the assemblies in the security policy of each end user</span>. In the case of customizations, if the document is in a network location instead of on the user's computer, you must grant full trust to the document as well. For information about setting security policy on end user computers, see <a href="https://msdn.microsoft.com/en-us/library/13wcxx6y.aspx">Deploying Security Policy</a>.</span></p>
<span style="font-family: courier new,courier;">Microsoft Office solutions add a custom security restriction of not accepting All Code or Zone-based evidence types, which means that Microsoft Office applications will not run any assemblies that are on the local computer, the network, or the Internet until the assembly is given permission (granted trust) in your security policy.<br /><br /><br /></span><strong><span class="LW_CollapsibleArea_Title" style="font-family: courier new,courier;">Levels of Trust</span></strong>
<div class="LW_CollapsibleArea_HrDiv">&nbsp;</div>
<div class="sectionblock"><span style="font-family: courier new,courier;">Levels of trust in .NET Framework security include these three:</span></div>
<p class="sectionblock"><span style="font-family: courier new,courier;"><strong>&nbsp; Full trust.&nbsp;&nbsp;</strong>This level grants the code permission to do any action that the <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; current user can do. All code must have full trust to run in <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Office solutions.</span></p>
<p class="sectionblock"><span style="font-family: courier new,courier;"><strong>&nbsp; Partial trust.</strong> This level is a restricted permission set that grants&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;only specified permissions. Partially trusted code <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; will not run in Office solutions.<br /></span></p>
<p class="sectionblock"><span style="font-family: courier new,courier;">&nbsp; <strong>Untrusted.</strong>&nbsp;&nbsp;&nbsp; This level grants no permissions, so the code does not&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; run.</span></p>
<span style="font-family: courier new,courier;">The required permission set is full trust; <span style="background-color: #ffff99;">Office solutions do not run managed code extensions that have partial trust or no trust</span>. For more information about permission sets, see <a href="https://msdn.microsoft.com/en-us/library/4652tyx7.aspx">Named Permission Sets</a>. </span><br /><br /><br />
<div>
<div class="LW_CollapsibleArea_TitleDiv">
<div><strong><span style="font-family: courier new,courier;"><span class="LW_CollapsibleArea_Title">Types of Evidence</span></span></strong>
<div class="LW_CollapsibleArea_HrDiv">&nbsp;</div>
</div>
</div>
<div class="sectionblock"><span style="font-family: courier new,courier;">Types of evidence in .NET Framework security include the following: </span></div>
<p class="sectionblock"><span style="font-family: courier new,courier;">&nbsp;&nbsp; All code.<br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">Application directory.<br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">Global assembly cache (GAC).<br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">Hash.<br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">Publisher.<br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">Site.<br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">Strong name.<br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">URL.<br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">Zone.<br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">Custom. (msosec.dll for Office solutions. For more information, see <a href="https://msdn.microsoft.com/en-us/library/9w6bd8f1.aspx">How to: Grant Permissions to Documents and Workbooks in Shared Locations (2003 System)</a>.)</span></p>
</div>
<p class="title">&nbsp;<span style="font-family: courier new,courier;">[..]<br /></span></p>
</td>
</tr>
</tbody>
</table>
<p><br />We can&nbsp;manually grant full trust permission to our add-in using these steps:&nbsp;</p>
<table style="background-color: #dedede; width: 560px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td>
<p class="title"><span style="font-family: courier new,courier;"><strong>How to: Grant Permissions to Folders and Assemblies (2003 System)</strong></span><span style="font-family: courier new, courier; font-size: small;"><span style="font-family: courier new,courier;"><a href="https://msdn.microsoft.com/en-us/library/zdc263t0.aspx">https://msdn.microsoft.com/en-us/library/zdc263t0.aspx</a></span><br />=======================================================================<br /></span><span style="font-family: courier new,courier;"><br />[..]<br /><br /></span></p>
<p><span style="font-family: courier new,courier;">The following procedures grant full trust permissions to an assembly or folder in a Visual Studio Tools for Office solution. Normally, you grant permissions to a specific assembly. If you have several assemblies, and you are certain that the location is secure, you can grant full trust to the folder where the assemblies are located. If you grant trust to the folder, all the assemblies in that folder and its subfolders are also trusted.</span></p>
<p class="title">&nbsp;<span style="font-family: courier new,courier;">There are three ways to grant permissions to folders and assemblies in Office solutions:</span></p>
<ul>
<li>
<p><span style="font-family: courier new,courier;">Using the <span class="label">Trust Assemblies Location</span> property in Visual Studio. (Useful only during development.)</span></p>
<p><span style="font-family: courier new,courier;">The <span class="label">Trust Assemblies Location</span> property only works during development; it has no effect on end users. For this reason, you cannot use this method for deployment. For more information, see <a href="https://msdn.microsoft.com/en-us/library/183f110b.aspx">Properties in Visual Studio Tools for Office Projects</a>.</span></p>
</li>
<li>
<p><span style="font-family: courier new,courier;">Using the <span class="label">Microsoft .NET Framework 2.0 Configuration</span> tool.</span></p>
<p><span style="font-family: courier new,courier;">This tool provides a graphical user interface for working with security policy. It is not included with Visual Studio 2008. You can download the tool as part of the .NET Framework 2.0 SDK from the Microsoft Download Center. For an example, see <a href="https://go.microsoft.com/fwlink/?LinkID=95083">.NET Framework 2.0 Software Development Kit (SDK) (x86)</a>.</span></p>
</li>
<li>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;">Using the <span class="label">Code Access Security Policy</span> tool (Caspol.exe)</span>.</span></p>
<p><span style="font-family: courier new,courier;">This tool is a command-line interface for working with security policy.</span></p>
</li>
</ul>
<p>&nbsp;<span style="font-family: courier new,courier;">[..]<br /><br /></span><span style="font-family: courier new,courier;"><strong>Using the .NET Framework 2.0 Configuration Tool</strong>&nbsp;</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">&nbsp; </span><span style="font-family: courier new,courier;">To install this tool, download and install the </span><span style="font-family: courier new,courier;"><strong>.NET Framework 2.0 Software <br />&nbsp; Development Kit (SDK)</strong> from the Microsoft Download Center.</span></p>
<p>&nbsp;<span style="font-family: courier new,courier;">&nbsp; The procedure to follow depends on where the assembly or folder is located:<br />&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; &gt; </span><span style="font-family: courier new,courier;">On your local computer.<br />&nbsp;&nbsp;&nbsp;&nbsp; &gt; </span><span style="font-family: courier new,courier;">On another computer on a network (or a mapped drive).</span></p>
<p><strong><span style="font-family: courier new,courier;"><br />To grant full trust to an assembly or folder on your local computer</span></strong></p>
<table style="border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><span style="font-family: courier new,courier;">&nbsp;1. In <strong>Control Panel</strong>, open <strong>Administrative Tools</strong>.</span><br /><span style="font-family: courier new,courier;">&nbsp;2. Run <strong>Microsoft .NET Framework 2.0 Configuration</strong>.&nbsp;</span><br /><span style="font-family: courier new,courier;"><br />&nbsp;<strong>Note: </strong></span><br /><span style="font-family: courier new,courier;">&nbsp; There might be several similar tools with names that start with&nbsp;&nbsp;<br />&nbsp; <strong>Microsoft .NET Framework</strong>. Ensure that the configuration tool you<br />&nbsp; use matches your version of the runtime.</span>
<p><span style="font-family: courier new,courier;">&nbsp;3. In the treeview on the left side, expand <strong>.NET Framework 2.0 Configuration</strong>,<br />&nbsp;&nbsp;&nbsp; expand <strong>My Computer</strong>, expand <strong>Runtime Security Policy</strong>, expand <strong>User</strong>, <br />&nbsp;&nbsp;&nbsp; expand <strong>Code Groups</strong>, expand <strong>All_Code</strong>, and then expand </span><span style="font-family: courier new,courier;"><strong>VSTOProjects</strong>.&nbsp;<br /></span><br /><span style="font-family: courier new,courier;">&nbsp;<strong>Note: </strong></span><br /><span style="font-family: courier new,courier;">&nbsp; If you have not compiled a Visual Studio Tools for Office project <br />&nbsp; before, you will not have the VSTOProjects folder. You can add the <br />&nbsp; new code group to the All_Code root node, or you can compile a Visual<br />&nbsp; Studio Tools for Office project to have the VSTOProjects folder created<br />&nbsp; automatically.</span></p>
<p><span style="font-family: courier new,courier;">&nbsp; On the right is the <strong>VSTOProjects</strong> <strong>Code Group</strong> description, which has a<br /><strong>Tasks</strong> section at the bottom of the page.<br /></span><br /><span style="font-family: courier new,courier;">&nbsp;4. In the <strong>Tasks</strong> section, click <strong>Add</strong> <strong>a Child Code Group</strong>.The Create <strong>Code </strong><br /><strong>&nbsp;&nbsp;&nbsp; Group</strong> wizard starts.</span><br /><span style="font-family: courier new,courier;">&nbsp;5. Select <strong>Create a new code group</strong>, and type a name and description that<br />&nbsp;&nbsp;&nbsp; will help you identify the project. Click <strong>Next</strong>.</span><br /><span style="font-family: courier new,courier;">&nbsp;6. In the <strong>Choose the condition type for this code group</strong> list, click <strong>URL</strong>.</span><br /><span style="font-family: courier new,courier;">&nbsp;7. In the <strong>URL</strong> box, type the full path to the assembly, or the path to the<br />&nbsp;&nbsp;&nbsp; bin folder of the project followed by an asterisk (for example, <br />&nbsp;&nbsp;&nbsp; c:\path\ExcelApplication1.dll or c:\path\ExcelApplication1\bin\*).</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; Click <strong>Next</strong>. <br /></span><br /><strong><span style="font-family: courier new,courier;">&nbsp;Note: </span></strong><br /><span style="font-family: courier new,courier;">&nbsp; If you type the path to the bin folder, all assemblies in that folder and<br />&nbsp; all its subfolders are granted full trust on your computer. Ensure that no <br />&nbsp; unauthorized people have access to folders that are fully trusted, or <br />&nbsp; someone could put a malicious assembly in the folder and the assembly would <br />&nbsp; run with full trust.</span></p>
<p><strong><span style="font-family: courier new,courier;">&nbsp;Caution: </span></strong><br /><span style="font-family: courier new,courier;">&nbsp; Do not grant permissions to an entire hard disk (such as C:\*) or to general<br />&nbsp; folders such as My Documents, because you might grant permissions to cached <br />&nbsp; assemblies from the Internet or from e-mail messages. Only grant permissions<br /></span><span style="font-family: courier new,courier;">&nbsp; to specific project folders that contain assemblies you know are safe to&nbsp;&nbsp; <br />&nbsp; run.</span></p>
<p><span style="font-family: courier new,courier;">&nbsp;9. Select <strong>Use existing permission set</strong>, and then select <strong>FullTrust</strong> from the&nbsp; <br />&nbsp;&nbsp;&nbsp; list.</span><br /><span style="font-family: courier new,courier;">&nbsp;10. Click <strong>Next</strong>.</span><br /><span style="font-family: courier new,courier;">&nbsp;11. Click <strong>Finish</strong>.</span></p>
</td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier;">[..]<br /><br /></span><br /><strong><span class="LW_CollapsibleArea_Title" style="font-family: courier new,courier;">Using the Code Access Security Policy Tool (Caspol.exe)<br /><br /></span></strong></p>
<table style="width: 546px; height: 154px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><span style="font-family: courier new,courier;">You can also grant full trust to a folder from a command prompt by using <br />the <strong>Code Access Security Policy tool (Caspol.exe)</strong>. For more information <br />about Caspol.exe, see <a href="https://msdn.microsoft.com/en-us/library/cb6t8dtz.aspx">Code Access Security Policy Tool (Caspol.exe)</a>.<br /><br />You can grant trust to a folder on your local computer at the <strong><span class="label">User</span></strong> level <br />with normal user permissions. To grant trust to a network location, <br />you must have administrator privileges and change the security policy<br />&nbsp;at the <span class="label">Machine</span> level. <span style="background-color: #ffff99;">The <strong><span class="label">Machine</span></strong> policy level acts independently of</span><br /><span style="background-color: #ffff99;">the <span class="label">User</span> policy level</span>, and the <strong><span class="label">Machine</span></strong> policy level does not grant full <br />trust to the Intranet zone even if the <span class="label">User</span> policy does. The policy levels<br />must agree.<br /></span></p>
<p>&nbsp;</p>
<table style="width: 530px; height: 59px;">
<tbody>
<tr><th align="left"><span style="font-family: courier new,courier;"><img id="alert_note" class="cl_IC101471" title="Tip" src="https://i.msdn.microsoft.com/areas/global/content/clear.gif" alt="Tip" /></span><span style="font-family: courier new,courier;"><strong>Tip:</strong></span></th></tr>
<tr>
<td><span style="font-family: courier new,courier;">Type the commands manually. Copying and pasting the commands into the <br />command prompt might result in Unknown Option errors.</span></td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier;">To grant full trust to a local folder<br /><br /></span><span style="font-family: courier new,courier;">&nbsp; &gt; Type the following command at the Visual Studio Command Prompt. </span></p>
<div class="codeSnippetContainerCodeContainer">
<div class="codeSnippetToolBar">
<div class="codeSnippetToolBarText"><span style="font-family: courier new,courier;">&nbsp; <span style="background-color: #c0c0c0;">caspol -u -ag All_Code -url C:\&lt;FolderName&gt;\&lt;FolderName&gt;\* FullTrust</span><br />&nbsp; <span style="background-color: #c0c0c0;">-n "&lt;Name&gt;" -d "&lt;Description&gt;"</span></span></div>
</div>
</div>
<p><span style="font-family: courier new,courier;">[..]<br /><br /></span></p>
<p><span style="font-family: courier new,courier;">For more information, see <a href="https://msdn.microsoft.com/en-us/library/w0fa60b5.aspx">How to: Add Code Groups Using Caspol.exe</a>.<br /></span><span style="font-family: courier new,courier;"><br /><strong>Note:<br /></strong><span style="font-family: courier new,courier;">&nbsp; <span style="background-color: #ccffcc;">After policy is deployed, everyone that is affected by the policy change&nbsp; </span><br /><span style="background-color: #ccffcc;">&nbsp; must quit and then restart all Office applications used in the solution </span><br /><span style="background-color: #ccffcc;">&nbsp; before the policy changes are enforced.</span> If Microsoft Office Word is part of <br />&nbsp; the solution, users must also quit and restart Microsoft Office Outlook. <br />&nbsp; Also, if a user has opened a document or workbook in Internet Explorer, the <br />&nbsp; process could still be running. Check Windows Task Manager to ensure there <br />&nbsp; are no instances of the Office application. Other applications that host <br />&nbsp; Office applications can also prevent the new permissions from being <br />&nbsp; enforced. Users should quit all applications that use Office, hosted or <br />&nbsp; stand-alone, when security policies are changed.</span></span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;<br />Here is how my <strong>.NET Framework 2.0 Configuration</strong>&nbsp;console looks like:</p>
<table style="border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0638.3.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0638.3.bmp"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0638.3.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0638.3.bmp" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>If you don't feel like downloading the entire&nbsp;<strong>.NET SDK</strong> to be able to use this tool (while the add-in is still under development and you need to&nbsp;experiment with CASPOL permissions), you may download <strong>MSCORCFG.MSC</strong> from here: <a href="https://blogs.msdn.com/b/astebner/archive/2006/01/23/516671.aspx" target="_blank">https://blogs.msdn.com/b/astebner/archive/2006/01/23/516671.aspx</a>. Once&nbsp;you run the&nbsp;setup project,&nbsp;the tool found&nbsp;at "<span style="background-color: #ccffcc;">C:\Program Files\Microsoft.NET\SDK\v2.0\Bin\mscorcfg.msc</span>" or at "<span style="background-color: #ccffcc;">C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorcfg.msc</span>".</p>
<p>If you prefer the command-line version, you may create the same setup by running these commands:</p>
<p><span style="background-color: #dadada;"><strong><span style="font-family: courier new,courier;">C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727&gt;CasPol.exe<br />&nbsp; &nbsp;-machine <br />&nbsp;&nbsp; -addgroup 1.1.&nbsp;<br />&nbsp;&nbsp; </span></strong></span><span style="background-color: #dadada;"><strong><span style="font-family: courier new,courier;">-zone MyComputer FullTrust <br />&nbsp;&nbsp; -n "VSTOProjects"<br /><br />C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727&gt;CasPol.exe<br />&nbsp; &nbsp;-machine<br />&nbsp; &nbsp;-addgroup "VSTOProjects" <br />&nbsp;&nbsp; -zone MyComputer FullTrust <br />&nbsp;&nbsp; -n "{461A2C5C-EF1D-4E58-AF67-225827B056E4}"<br /></span></strong></span><br /><strong><span style="background-color: #dadada; font-family: courier new,courier;">C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727&gt;CasPol.exe <br />&nbsp; -machine <br />&nbsp;&nbsp;-addgroup "{46</span></strong><strong><span style="background-color: #dadada; font-family: courier new,courier;">1A2C5C-EF1D-4E58-AF67-225827B056E4}"<br />&nbsp; -url "C:\Program Files\ms\OfficeAddinDummyS</span></strong><strong><span style="background-color: #dadada; font-family: courier new,courier;">etup\*" FullTrust<br />&nbsp;&nbsp;-n "DummyVSTOAdd-in" -d "some text"</span></strong></p>
<p>&nbsp;.. and as you can see from the screenshot below, the results are similar.</p>
<table style="border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1738.4.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1738.4.bmp"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1738.4.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1738.4.bmp" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table style="border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6545.5.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6545.5.bmp"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6545.5.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6545.5.bmp" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>Of course .. you can just run this commandline:&nbsp;<span style="background-color: #dadada; font-family: courier new,courier;"><strong>CasPol.exe -m -listgroups</strong></span> ..&nbsp;to visualize your entries, but <strong>mscorcfg.msc</strong> makes it a lot more easier in my opinion.</p>
<table style="border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1588.6.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1588.6.bmp"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1588.6.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1588.6.bmp" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><br /><br /><strong>How to automate the CASPOL tool?</strong>&nbsp;<br /><br /></p>
<p>&nbsp;We need to add a special type of class which executes our custom code when the MSI Installer is executed on the end-user's&nbsp;machine:<br /><br /><strong>1.</strong>&nbsp;&nbsp;Right-click on the&nbsp;entire&nbsp;<strong>Solution</strong>&nbsp;in '<strong>Solution Explorer</strong>' and select '<strong>Add</strong>' &gt; '<strong>New Project...</strong>';<br /><strong>2.&nbsp;</strong> From the '<strong>Visual Studio installed templates</strong>' list, select&nbsp;'<strong>Empty Project</strong>'; Enter&nbsp;some name (I <br />&nbsp;&nbsp;&nbsp;&nbsp; chose&nbsp;the name <span style="color: #333399;"><strong>InstallerOverrideProject</strong>&nbsp;</span>for this example) and&nbsp;click <strong>OK</strong>;<strong><br /></strong><strong>3.</strong>&nbsp;&nbsp;Right-click the newly inserted project&nbsp;and select&nbsp;'<strong>Add</strong>' &gt; '<strong>New Item ...</strong>', select&nbsp;'<strong>Installer Class</strong>'; <br />&nbsp;&nbsp;&nbsp;&nbsp; Enter any name you&nbsp;want (for this example I used: <span style="color: #333399;"><strong>InstallerOverrideClass</strong></span>) and close the window;</p>
<table style="border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4848.7.1.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4848.7.1.bmp"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4848.7.1.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4848.7.1.bmp" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;If you open the '<strong>InstallerOverrideClass.cs</strong>', you will see that this class derives from <strong>System.Configuration.Install.Installer</strong>. <br /><br /><span style="background-color: #ccffcc;">Delete the InstallerOverrideClass.Designer.cs</span>:<br /><br /></p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2806.14.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2806.14.bmp"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2806.14.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2806.14.bmp" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><br /><strong>4.</strong>&nbsp; Repeat the same actions from the previous step to insert another simple C# class named <br />&nbsp;&nbsp;&nbsp;&nbsp; '<strong>CaspolSecurityPolicyCreator.cs</strong>';&nbsp; Paste the following code inside:&nbsp;<br /><br /></p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<span style="color: #006400;"><span style="font-family: courier new,courier;">//-------------------------------------------------------------------<br /></span><span style="font-family: courier new,courier;">//<br /></span><span style="font-family: courier new,courier;">// Copyright (C) Microsoft Corporation. All rights reserved.<br /></span><span style="font-family: courier new,courier;">//<br /></span><span style="font-family: courier new,courier;">// THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF <br /></span><span style="font-family: courier new,courier;">// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED <br /></span><span style="font-family: courier new,courier;">// TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A<br /></span><span style="font-family: courier new,courier;">// PARTICULAR PURPOSE.<br /></span><span style="font-family: courier new,courier;">//-------------------------------------------------------------------</span></span>
<p><span style="font-family: courier new,courier; color: #0000ff;">using </span><span style="font-family: courier new,courier;">System;<br /></span><span style="font-family: courier new,courier; color: #0000ff;">using </span><span style="font-family: courier new,courier;">System.Diagnostics;<br /></span><span style="font-family: courier new,courier; color: #0000ff;">using </span><span style="font-family: courier new,courier;">System.IO;<br /></span><span style="font-family: courier new,courier; color: #0000ff;">using </span><span style="font-family: courier new,courier;">System.Reflection;<br /></span><span style="font-family: courier new,courier; color: #0000ff;">using </span><span style="font-family: courier new,courier;">System.Runtime.InteropServices;<br /></span><span style="font-family: courier new,courier; color: #0000ff;">using </span><span style="font-family: courier new,courier;">System.Security.Permissions;<br /></span><span style="font-family: courier new,courier; color: #0000ff;">using </span><span style="font-family: courier new,courier;">System.Text;</span></p>
<p><span style="font-family: courier new,courier;">namespace </span><span style="font-family: courier new,courier;">InstallerOverrideProject<br /></span><span style="font-family: courier new,courier;">{<br /></span><span style="font-family: courier new,courier;">[</span><span style="font-family: courier new,courier;"><span style="color: #2b91af;"><span style="color: #2b91af;">PermissionSet</span></span>(<span style="color: #2b91af;"><span style="color: #2b91af;">SecurityAction</span></span>.Demand, Name = <span style="color: #a31515;"><span style="color: #a31515;">"FullTrust"</span></span>)]</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">class</span></span><span style="color: #2b91af;"><span style="color: #2b91af;">CaspolSecurityPolicyCreator<br /></span></span></span><span style="font-family: courier new,courier;">{<br />&nbsp;</span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">private</span></span> CaspolSecurityPolicyCreator()<br />&nbsp;</span><span style="font-family: courier new,courier;">{</span><span style="font-family: courier new,courier;">}<br /><br /></span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">&nbsp;internal </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">static </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">void</span></span> AddSecurityPolicy(<br />&nbsp;&nbsp;<span style="color: #0000ff;"> bool</span> machinePolicyLevel,<br />&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">s</span><span style="color: #0000ff;"><span style="color: #0000ff;">tring</span></span> solutionPath,<br />&nbsp;<span style="color: #008000;"><span style="color: #008000;">//string solutionCodeGroupDescription,<br />&nbsp;</span></span><span style="color: #008000;"><span style="color: #008000;">//string assemblyPath,<br />&nbsp;&nbsp; </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> assemblyCodeGroupName,<br />&nbsp;&nbsp; <span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> assemblyCodeGroupDescription)<br />&nbsp;</span><span style="font-family: courier new,courier;">{<br />&nbsp; </span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> frameworkFolder = GetFrameworkFolder();<br />&nbsp; <span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> policyLevel;<br />&nbsp; <span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> parentCodeGroup;<br /><br />&nbsp; <span style="color: #0000ff;"><span style="color: #0000ff;">if</span></span> (machinePolicyLevel)<br />&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">policyLevel&nbsp;&nbsp;&nbsp;&nbsp; = </span><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"-m"</span></span>; <span style="color: #008000;"><span style="color: #008000;">// Use Machine-level policy.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: courier new,courier;">parentCodeGroup = </span><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"My_Computer_Zone"</span></span>; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #008000;"><span style="color: #008000;">// Use My_Computer_Zone for assemblies installed on the computer.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></span><span style="font-family: courier new,courier;">}<br /></span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">&nbsp; else<br />&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: courier new,courier;">{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">policyLevel&nbsp;&nbsp;&nbsp;&nbsp; = </span><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"-u"</span></span>; <span style="color: #008000;"><span style="color: #008000;">// Use User-level policy.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></span><span style="font-family: courier new,courier;">parentCodeGroup = </span><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"All_Code"</span></span>;<br />&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">//// Add the solution code group. Grant no permission at this level.</span></span><span style="color: #008000;"><span style="color: #008000;">//string arguments = policyLevel + " -q -ag " + parentCodeGroup + " -url \"" + solutionInstallationUrl +</span></span><span style="color: #008000;"><span style="color: #008000;">// "\" Nothing -n \"" + solutionCodeGroupName + "\" -d \"" + solutionCodeGroupDescription +</span></span><span style="color: #008000;"><span style="color: #008000;">// "\"";</span></span><span style="color: #008000;"><span style="color: #008000;">//try</span></span><span style="color: #008000;"><span style="color: #008000;">//{</span></span><span style="color: #008000;"><span style="color: #008000;">// RunCaspolCommand(frameworkFolder, arguments);</span></span><span style="color: #008000;"><span style="color: #008000;">//}</span></span><span style="color: #008000;"><span style="color: #008000;">//catch (Exception ex)</span></span><span style="color: #008000;"><span style="color: #008000;">//{</span></span><span style="color: #008000;"><span style="color: #008000;">// string error = String.Format("Cannot create the security code group '{0}'.", solutionCodeGroupName);</span></span><span style="color: #008000;"><span style="color: #008000;">// throw new Exception(error, ex);</span></span><span style="color: #008000;"><span style="color: #008000;">//}</span></span><span style="color: #008000;"><span style="color: #008000;">// Add the assembly code group. Grant FullTrust permissions to the main assembly.</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">try</span></span></span></p>
<p><span style="font-family: courier new,courier;">{</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">// Use the assembly strong name as the membership condition.</span></span><span style="color: #008000;"><span style="color: #008000;">// Ensure that the assembly is strong-named to give it full trust.</span></span><span style="color: #008000;"><span style="color: #008000;">//AssemblyName assemblyName = Assembly.LoadFile(assemblyPath).GetName();</span></span><span style="color: #2b91af;"><span style="color: #2b91af;">StreamWriter</span></span> sw = <span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span><span style="color: #2b91af;"><span style="color: #2b91af;">StreamWriter</span></span>(<span style="color: #a31515;"><span style="color: #a31515;">@"C:\deployment.txt"</span></span>, <span style="color: #0000ff;"><span style="color: #0000ff;">true</span></span>);<span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> arguments = policyLevel + <span style="color: #a31515;"><span style="color: #a31515;">" -q -ag "</span></span> + parentCodeGroup + <span style="color: #a31515;"><span style="color: #a31515;">" -url \""</span></span> + solutionPath + <span style="color: #a31515;"><span style="color: #a31515;">"*\" FullTrust -n \""</span></span> + assemblyCodeGroupName + <span style="color: #a31515;"><span style="color: #a31515;">"\" -d \""</span></span></span></p>
<p><span style="font-family: courier new,courier;">+ assemblyCodeGroupDescription + </span><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"\""</span></span>;</span></p>
<p><span style="font-family: courier new,courier;">sw.WriteLine(</span><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"arguments: "</span></span> + arguments);</span></p>
<p><span style="font-family: courier new,courier;">sw.Close();</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">//arguments = policyLevel + " -q -ag \"" + solutionCodeGroupName + "\" -strong -file \"" + assemblyPath +</span></span><span style="color: #008000;"><span style="color: #008000;">// "\" \"" + assemblyName.Name + "\" \"" + assemblyName.Version.ToString(4) +</span></span><span style="color: #008000;"><span style="color: #008000;">// "\" FullTrust -n \"" + assemblyCodeGroupName + "\" -d \"" + assemblyCodeGroupDescription +</span></span><span style="color: #008000;"><span style="color: #008000;">// "\"";</span></span></span></p>
<p><span style="font-family: courier new,courier;">RunCaspolCommand(frameworkFolder, arguments);</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">catch</span></span> (<span style="color: #2b91af;"><span style="color: #2b91af;">Exception</span></span> ex)</span></p>
<p><span style="font-family: courier new,courier;">{</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">try</span></span></span></p>
<p><span style="font-family: courier new,courier;">{</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">// Clean the solutionCodeGroupName.</span></span></span></p>
<p><span style="font-family: courier new,courier;">RemoveSecurityPolicy(machinePolicyLevel, solutionPath);</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><span style="color: #0000ff;">catch</span></span></span></p>
<p><span style="font-family: courier new,courier; font-size: small;">{</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">}</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> error = <span style="color: #2b91af;"><span style="color: #2b91af;">String</span></span>.Format(<span style="color: #a31515;"><span style="color: #a31515;">"Cannot create the security code group '{0}'."</span></span>, assemblyCodeGroupName);<span style="color: #0000ff;"><span style="color: #0000ff;">throw</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span><span style="color: #2b91af;"><span style="color: #2b91af;">Exception</span></span>(error, ex);</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">internal</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">static</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">void</span></span> RemoveSecurityPolicy(<span style="color: #0000ff;"><span style="color: #0000ff;">bool</span></span> machinePolicyLevel,<span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> solutionCodeGroupName)</span></p>
<p><span style="font-family: courier new,courier;">{</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> frameworkFolder = GetFrameworkFolder();<span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> policyLevel;<span style="color: #0000ff;"><span style="color: #0000ff;">if</span></span> (machinePolicyLevel)</span></p>
<p><span style="font-family: courier new,courier;">policyLevel =</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"-m"</span></span>; <span style="color: #008000;"><span style="color: #008000;">// Use Machine-level policy.</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">else</span></span></span></p>
<p><span style="font-family: courier new,courier;">policyLevel =</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"-u"</span></span>; <span style="color: #008000;"><span style="color: #008000;">// Use User-level policy.</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> arguments = policyLevel + <span style="color: #a31515;"><span style="color: #a31515;">" -q -rg \""</span></span> + solutionCodeGroupName + <span style="color: #a31515;"><span style="color: #a31515;">"\""</span></span>;</span></p>
<p><span style="font-family: courier new,courier;">RunCaspolCommand(frameworkFolder, arguments);</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">private</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">static</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> GetFrameworkFolder()</span></p>
<p><span style="font-family: courier new,courier;">{</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">// Get the targeted Framework folder.</span></span><span style="color: #2b91af;"><span style="color: #2b91af;">Version</span></span> version = <span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span><span style="color: #2b91af;"><span style="color: #2b91af;">Version</span></span>(2, 0, 50727);<span style="color: #0000ff;"><span style="color: #0000ff;">return</span></span> GetRuntimeInstallationDirectory(version, <span style="color: #0000ff;"><span style="color: #0000ff;">true</span></span>);</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">private</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">static</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">void</span></span> RunCaspolCommand(<span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> frameworkFolder, <span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> arguments)</span></p>
<p><span style="font-family: courier new,courier;">{</span></p>
<p><span style="font-family: courier new,courier;">ProcessStartInfo processStartInfo =</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span> ProcessStartInfo(<span style="color: #2b91af;"><span style="color: #2b91af;">Path</span></span>.Combine(frameworkFolder, <span style="color: #a31515;"><span style="color: #a31515;">"caspol.exe"</span></span>));</span></p>
<p><span style="font-family: courier new,courier;">processStartInfo.CreateNoWindow =</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">true</span></span>;</span></p>
<p><span style="font-family: courier new,courier;">processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;</span></p>
<p><span style="font-family: courier new,courier;">processStartInfo.WorkingDirectory = frameworkFolder;</span></p>
<p><span style="font-family: courier new,courier;">processStartInfo.Arguments = arguments;</span></p>
<p><span style="font-family: courier new,courier;">processStartInfo.RedirectStandardError =</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">true</span></span>;</span></p>
<p><span style="font-family: courier new,courier;">processStartInfo.RedirectStandardOutput =</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">true</span></span>;</span></p>
<p><span style="font-family: courier new,courier;">processStartInfo.UseShellExecute =</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">false</span></span>;</span></p>
<p><span style="font-family: courier new,courier;">Process process = Process.Start(processStartInfo);</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> caspolOutputMessage = process.StandardOutput.ReadToEnd();</span></p>
<p><span style="font-family: courier new,courier;">process.WaitForExit();</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">int</span></span> exitCode = 0;<span style="color: #0000ff;"><span style="color: #0000ff;">if</span></span> (process.HasExited)</span></p>
<p><span style="font-family: courier new,courier;">exitCode = process.ExitCode;</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">if</span></span> (exitCode != 0)</span></p>
<p><span style="font-family: courier new,courier;">{</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> message = <span style="color: #0000ff;"><span style="color: #0000ff;">null</span></span>;<span style="color: #0000ff;"><span style="color: #0000ff;">if</span></span> (!<span style="color: #2b91af;"><span style="color: #2b91af;">String</span></span>.IsNullOrEmpty(caspolOutputMessage))</span></p>
<p><span style="font-family: courier new,courier;">{</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #2b91af;"><span style="color: #2b91af;">String</span></span>[] outputMessageLines = caspolOutputMessage.Split(<span style="color: #a31515;"><span style="color: #a31515;">'\n'</span></span>);<span style="color: #0000ff;"><span style="color: #0000ff;">for</span></span> (<span style="color: #0000ff;"><span style="color: #0000ff;">int</span></span> i = 2; i &lt; outputMessageLines.Length; i++)</span></p>
<p><span style="font-family: courier new,courier;">{</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> line = outputMessageLines[i].Trim();<span style="color: #0000ff;"><span style="color: #0000ff;">if</span></span> (!<span style="color: #2b91af;"><span style="color: #2b91af;">String</span></span>.IsNullOrEmpty(line))</span></p>
<p><span style="font-family: courier new,courier;">{</span></p>
<p><span style="font-family: courier new,courier;">message = line;</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">break</span></span>;</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">if</span></span> (<span style="color: #2b91af;"><span style="color: #2b91af;">String</span></span>.IsNullOrEmpty(message))</span></p>
<p><span style="font-family: courier new,courier;">message =</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"Cannot run the Code Access Security Policy tool (caspol.exe)."</span></span>;<span style="color: #0000ff;"><span style="color: #0000ff;">throw</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span><span style="color: #2b91af;"><span style="color: #2b91af;">ApplicationException</span></span>(message);</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;">[</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #2b91af;"><span style="color: #2b91af;">DllImport</span></span>(<span style="color: #a31515;"><span style="color: #a31515;">"mscoree.dll"</span></span>, CharSet = <span style="color: #2b91af;"><span style="color: #2b91af;">CharSet</span></span>.Unicode, ExactSpelling = <span style="color: #0000ff;"><span style="color: #0000ff;">true</span></span>, PreserveSig = <span style="color: #0000ff;"><span style="color: #0000ff;">true</span></span>,</span></p>
<p><span style="font-family: courier new,courier;">SetLastError =</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">false</span></span>)]<span style="color: #0000ff;"><span style="color: #0000ff;">private</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">static</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">extern</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">int</span></span><span style="color: #008000;"><span style="color: #008000;">/* [HRESULT] */</span></span> GetRequestedRuntimeInfo(<span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span><span style="color: #008000;"><span style="color: #008000;">/* [LPCWSTR] */</span></span> pExe,<span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span><span style="color: #008000;"><span style="color: #008000;">/* [LPCWSTR] */</span></span> pwszVersion,<span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span><span style="color: #008000;"><span style="color: #008000;">/* [LPCWSTR] */</span></span> pConfigurationFile,<span style="color: #0000ff;"><span style="color: #0000ff;">uint</span></span><span style="color: #008000;"><span style="color: #008000;">/* [DWORD] */</span></span> startupFlags,</span></p>
<p><span style="font-family: courier new,courier;">RuntimeInfo</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">/* [DWORD] */</span></span> runtimeInfoFlags,<span style="color: #2b91af;"><span style="color: #2b91af;">StringBuilder</span></span><span style="color: #008000;"><span style="color: #008000;">/* [LPWSTR] */</span></span> pDirectory,<span style="color: #0000ff;"><span style="color: #0000ff;">uint</span></span><span style="color: #008000;"><span style="color: #008000;">/* [DWORD] */</span></span> dwDirectory,<span style="color: #0000ff;"><span style="color: #0000ff;">out</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">uint</span></span><span style="color: #008000;"><span style="color: #008000;">/* [DWORD *] */</span></span> dwDirectoryLength,<span style="color: #2b91af;"><span style="color: #2b91af;">StringBuilder</span></span><span style="color: #008000;"><span style="color: #008000;">/* [LPWSTR] */</span></span> pVersion,<span style="color: #0000ff;"><span style="color: #0000ff;">uint</span></span><span style="color: #008000;"><span style="color: #008000;">/* [DWORD] */</span></span> cchBuffer,<span style="color: #0000ff;"><span style="color: #0000ff;">out</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">uint</span></span><span style="color: #008000;"><span style="color: #008000;">/* [DWORD *] */</span></span> dwLength</span></p>
<p><span style="font-family: courier new,courier;">);</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #808080;"><span style="color: #808080;">&lt;summary&gt;</span></span><span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #008000;"><span style="color: #008000;"> Returns the installation directory of the specified .NET runtime.</span></span><span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #808080;"><span style="color: #808080;">&lt;/summary&gt;</span></span><span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #808080;"><span style="color: #808080;">&lt;param name="version"&gt;</span></span><span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #008000;"><span style="color: #008000;"> The version of the runtime.</span></span><span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #808080;"><span style="color: #808080;">&lt;/param&gt;</span></span><span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #808080;"><span style="color: #808080;">&lt;param name="upgradeVersion"&gt;</span></span><span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #008000;"><span style="color: #008000;"> True to return the installation directory of the nearest compatible runtime version, or false for an exact match.</span></span><span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #808080;"><span style="color: #808080;">&lt;/param&gt;</span></span><span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #808080;"><span style="color: #808080;">&lt;returns&gt;</span></span><span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #008000;"><span style="color: #008000;"> The .NET runtime installation directory.</span></span><span style="color: #808080;"><span style="color: #808080;">///</span></span><span style="color: #808080;"><span style="color: #808080;">&lt;/returns&gt;</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">private</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">static</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> GetRuntimeInstallationDirectory(<span style="color: #2b91af;"><span style="color: #2b91af;">Version</span></span> version, <span style="color: #0000ff;"><span style="color: #0000ff;">bool</span></span> upgradeVersion)</span></p>
<p><span style="font-family: courier new,courier;">{</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> versionString = <span style="color: #a31515;"><span style="color: #a31515;">"v"</span></span> + version.ToString(3);</span></p>
<p><span style="font-family: courier new,courier;">RuntimeInfo runtimeInfo = RuntimeInfo.DoNotShowErrorDialog;</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">if</span></span> (upgradeVersion)</span></p>
<p><span style="font-family: courier new,courier;">runtimeInfo |= RuntimeInfo.UpgradeVersion;</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #2b91af;"><span style="color: #2b91af;">StringBuilder</span></span> runtimeDirectory = <span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span><span style="color: #2b91af;"><span style="color: #2b91af;">StringBuilder</span></span>(270);<span style="color: #2b91af;"><span style="color: #2b91af;">StringBuilder</span></span> runtimeVersion = <span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span><span style="color: #2b91af;"><span style="color: #2b91af;">StringBuilder</span></span>(<span style="color: #a31515;"><span style="color: #a31515;">"v65535.65535.65535"</span></span>.Length);<span style="color: #0000ff;"><span style="color: #0000ff;">uint</span></span> runtimeDirectoryLength;<span style="color: #0000ff;"><span style="color: #0000ff;">uint</span></span> runtimeVersionLength;<span style="color: #0000ff;"><span style="color: #0000ff;">int</span></span> errorCode = GetRequestedRuntimeInfo(<span style="color: #0000ff;"><span style="color: #0000ff;">null</span></span>, versionString, <span style="color: #0000ff;"><span style="color: #0000ff;">null</span></span>, 0, runtimeInfo, runtimeDirectory,</span></p>
<p><span style="font-family: courier new,courier;">(</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">uint</span></span>)runtimeDirectory.Capacity, <span style="color: #0000ff;"><span style="color: #0000ff;">out</span></span> runtimeDirectoryLength,</span></p>
<p><span style="font-family: courier new,courier;">runtimeVersion, (</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">uint</span></span>)runtimeVersion.Capacity,<span style="color: #0000ff;"><span style="color: #0000ff;">out</span></span> runtimeVersionLength);<span style="color: #2b91af;"><span style="color: #2b91af;">Marshal</span></span>.ThrowExceptionForHR(errorCode);<span style="color: #0000ff;"><span style="color: #0000ff;">return</span></span><span style="color: #2b91af;"><span style="color: #2b91af;">Path</span></span>.Combine(runtimeDirectory.ToString(), runtimeVersion.ToString());</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;">#region</span></p>
<p><span style="font-family: courier new,courier;">Nested type: RuntimeInfo</span></p>
<p><span style="font-family: courier new,courier;">[</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #2b91af;"><span style="color: #2b91af;">Flags</span></span>]</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">private</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">enum</span></span><span style="color: #2b91af;"><span style="color: #2b91af;">RuntimeInfo</span></span> : <span style="color: #0000ff;"><span style="color: #0000ff;">uint</span></span></span></p>
<p><span style="font-family: courier new,courier;">{</span></p>
<p><span style="font-family: courier new,courier;">UpgradeVersion = 0x1,</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">// RUNTIME_INFO_UPGRADE_VERSION</span></span></span></p>
<p><span style="font-family: courier new,courier;">RequestIA64 = 0x2,</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">// RUNTIME_INFO_REQUEST_IA64</span></span></span></p>
<p><span style="font-family: courier new,courier;">RequestAmd64 = 0x4,</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">// RUNTIME_INFO_REQUEST_AMD64</span></span></span></p>
<p><span style="font-family: courier new,courier;">RequestX86 = 0x8,</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">// RUNTIME_INFO_REQUEST_X86</span></span></span></p>
<p><span style="font-family: courier new,courier;">DoNotReturnDirectory = 0x10,</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">// RUNTIME_INFO_DONT_RETURN_DIRECTORY</span></span></span></p>
<p><span style="font-family: courier new,courier;">DoNotReturnVersion = 0x20,</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">// RUNTIME_INFO_DONT_RETURN_VERSION</span></span></span></p>
<p><span style="font-family: courier new,courier;">DoNotShowErrorDialog = 0x40</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">// RUNTIME_INFO_DONT_SHOW_ERROR_DIALOG</span></span></span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;">#endregion</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
</td>
</tr>
</tbody>
</table>
<p><strong>5.</strong>&nbsp; Paste the following code inside '<strong>InstallerOverrideClass.cs</strong>':<br /><br /></p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<br /><span style="font-family: courier new,courier; color: #0000ff;">using</span> <span style="font-family: courier new,courier;">System;</span> <br /><span style="font-family: courier new,courier;"><span style="color: #0000ff;">using</span> S</span><span style="font-family: courier new,courier;">ystem.Collections;<br /></span><span style="font-family: courier new,courier;">using </span><span style="font-family: courier new,courier;">System.Collections.Generic;<br /></span><span style="font-family: courier new,courier;">using </span><span style="font-family: courier new,courier;">System.ComponentModel;<br /></span><span style="font-family: courier new,courier;">using </span><span style="font-family: courier new,courier;">System.Configuration.Install;</span>
<p><span style="font-family: courier new,courier;">namespace </span><span style="font-family: courier new,courier;">InstallerOverrideProject<br /></span><span style="font-family: courier new,courier;">{<br />&nbsp;</span><span style="font-family: courier new,courier;">[RunInstaller(</span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">true</span></span><span>)]<br />&nbsp;</span></span><span style="font-family: courier new,courier;">[System.Security.Permissions.</span><span style="font-family: courier new,courier;"><span style="color: #2b91af;"><span style="color: #2b91af;">PermissionSetAttribute</span></span>&nbsp;<br />&nbsp;(System.Security.Permissions.<span style="color: #2b91af;"><span style="color: #2b91af;">SecurityAction</span></span>.Demand, Name = <span style="color: #a31515;"><span style="color: #a31515;">"FullTrust"</span></span><span>)]</span><span style="color: #0000ff;"><span style="color: #0000ff;"><br />&nbsp;<br />&nbsp;public </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">class </span></span><span style="color: #2b91af;"><span style="color: #2b91af;">InstallerOverrideClass</span></span><span> : Installer</span></span> <br />&nbsp; <span style="font-family: courier new,courier;">{<br />&nbsp; </span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">protected </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span><span> targetDir;<br /><br />&nbsp;</span><span style="color: #008000;"><span style="color: #008000;">// Override the Install method to update the customization location<br />&nbsp;</span></span><span style="color: #008000;"><span style="color: #008000;">// in the application manifest.<br /><br />&nbsp; </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">public </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">override </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">void</span></span> Install(System.Collections.<span style="color: #2b91af;"><span style="color: #2b91af;">IDictionary</span></span><span> stateSaver)</span></span> <br />&nbsp;&nbsp; <span style="font-family: courier new,courier;">{ <br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">targetDir = </span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">this</span></span>.Context.Parameters[<span style="color: #a31515;"><span style="color: #a31515;">"target_folder"</span></span><span>];</span></span></p>
<p><span style="font-family: courier new,courier;">&nbsp;&nbsp; </span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">base</span></span><span>.Install(stateSaver);<br /><br />&nbsp;&nbsp; </span><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> solutionCodeGroupName = <span style="color: #a31515;"><span style="color: #a31515;">"{461A2C5C-EF1D-4E58-AF67-225827B056E4}"</span></span><span>;<br />&nbsp;&nbsp; </span><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> solutionCodeGroupDescription = <span style="color: #a31515;"><span style="color: #a31515;">"WordAddIn2003_AllUsersDeployment"</span></span><span>;<br /></span><span style="color: #008000;"><span style="color: #008000;"><br />&nbsp;//string site = targetDir.Substring(0, targetDir.Length - 1);<br /></span></span><span style="color: #0000ff;"><span style="color: #0000ff;">&nbsp;&nbsp; string</span></span><span> site = targetDir;<br /><br />&nbsp;</span><span style="color: #008000;"><span style="color: #008000;">// Note that a code group with solutionCodeGroupName name is created in the <br />&nbsp;</span></span><span style="color: #008000;"><span style="color: #008000;">// Install method and removed in the Rollback and Uninstall methods.<br />&nbsp;</span></span><span style="color: #008000;"><span style="color: #008000;">// The solutionCodeGroupName must be a unique name to ensure that the <br />&nbsp;</span></span><span style="color: #008000;"><span style="color: #008000;">// correct code group is removed during Rollback and Uninstall.<br /><br />&nbsp; </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">if</span></span> (<span style="color: #2b91af;"><span style="color: #2b91af;">String</span></span><span>.IsNullOrEmpty(solutionCodeGroupName))<br />&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff;"><span style="color: #0000ff;">throw </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span> InstallException<br />&nbsp;&nbsp;&nbsp;&nbsp; (<span style="color: #a31515;"><span style="color: #a31515;">"Cannot set the security policy. The specified solution code group name <br />&nbsp;&nbsp;&nbsp;&nbsp; is not valid."</span></span><span>);<br /><br />&nbsp; </span><span style="color: #0000ff;"><span style="color: #0000ff;">if</span></span> (<span style="color: #2b91af;"><span style="color: #2b91af;">String</span></span><span>.IsNullOrEmpty(solutionCodeGroupDescription))<br />&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff;"><span style="color: #0000ff;">throw </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span> InstallException(<span style="color: #a31515;"><span style="color: #a31515;">"Cannot set the security policy. The <br />&nbsp;&nbsp;&nbsp;&nbsp; specified&nbsp;solution code group description is not valid."</span></span><span>);<br /><br />&nbsp; </span><span style="color: #0000ff;"><span style="color: #0000ff;">if</span></span> (<span style="color: #2b91af;"><span style="color: #2b91af;">String</span></span><span>.IsNullOrEmpty(site))<br />&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff;"><span style="color: #0000ff;">throw </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span> InstallException(<span style="color: #a31515;"><span style="color: #a31515;">"Cannot set the security policy. The specified<br />&nbsp;&nbsp;&nbsp;&nbsp; site is not valid."</span></span><span>);<br /><br />&nbsp;&nbsp; </span><span style="color: #0000ff;"><span style="color: #0000ff;">if</span></span> (stateSaver == <span style="color: #0000ff;"><span style="color: #0000ff;">null</span></span><span>)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff;"><span style="color: #0000ff;">throw </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">new </span></span><span style="color: #2b91af;"><span style="color: #2b91af;">ArgumentNullException</span></span>(<span style="color: #a31515;"><span style="color: #a31515;">"stateSaver"</span></span><span>);<br /><br />&nbsp;&nbsp; </span><span style="color: #0000ff;"><span style="color: #0000ff;">try</span></span></span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: courier new,courier;">{<br />&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">// Note that Install method may be invoked during Repair mode and the&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; <span style="color: #008000;"><span style="color: #008000;">// code </span></span>group</span></span><span style="color: #008000;"><span style="color: #008000;"> may already exist.</span></span><span style="color: #008000;"><span style="color: #008000;">To prevent adding of another code group, <br />&nbsp;&nbsp;&nbsp; <span style="color: #008000;"><span style="color: #008000;">// </span></span>remove the code group if it exists.</span></span></span></p>
<p><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000;"><span style="color: #008000;">/*&nbsp;</span></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;<span style="color: #006400;">&nbsp;&nbsp;&nbsp; try</span><br /><span style="color: #006400;">&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="color: #006400;"><span style="font-family: courier new,courier;">{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">// The solutionCodeGroupName must be a unique name; otherwise, the&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: courier new,courier;">// </span>method might delete wrong code group.</span></span></p>
<p><span style="color: #006400;"><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CaspolSecurityPolicyCreator.RemoveSecurityPolicy(solutionCodeGroupName);<br />&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">}<br />&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">catch {}*/</span></span></p>
<p><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">CaspolSecurityPolicyCreator.AddSecurityPolicy(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">true</span></span><span>,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: courier new,courier;">site,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"SampleAddin"</span></span><span>,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: courier new,courier;">solutionCodeGroupDescription);<br />&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">}<br />&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">catch</span></span> (<span style="color: #2b91af;"><span style="color: #2b91af;">Exception</span></span><span>ex)<br />&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: courier new,courier;">{<br />&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">throw </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span> InstallException(<span style="color: #a31515;"><span style="color: #a31515;">"Cannot set the security policy."</span></span><span>, ex);<br />&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">&nbsp;public </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">override </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">void</span></span> Commit(<span style="color: #2b91af;"><span style="color: #2b91af;">IDictionary</span></span><span>savedState)<br />&nbsp; </span></span><span style="font-family: courier new,courier;">{</span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">base</span></span><span>.Commit(savedState);</span></span><span style="font-family: courier new,courier;">}<br /><br />&nbsp;</span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">public </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">override </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">void</span></span> Rollback(<span style="color: #2b91af;"><span style="color: #2b91af;">IDictionary</span></span><span>savedState)<br />&nbsp; </span></span><span style="font-family: courier new,courier;">{</span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">base</span></span><span>.Rollback(savedState);</span></span><span style="font-family: courier new,courier;">}<br /><br />&nbsp;</span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">public </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">override </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">void</span></span> Uninstall(<span style="color: #2b91af;"><span style="color: #2b91af;">IDictionary</span></span><span>savedState)<br />&nbsp; </span></span><span style="font-family: courier new,courier;">{</span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">base</span></span><span>.Uninstall(savedState);</span></span><span style="font-family: courier new,courier;">}<br />&nbsp;</span><span style="font-family: courier new,courier;">}<br /></span><span style="font-family: courier new,courier;">}</span></td>
</tr>
</tbody>
</table>
<p><strong>6.&nbsp; </strong>We&nbsp;need to change the default output type for our project to&nbsp;make it&nbsp;a <strong>ClassLibrary</strong>: right-click&nbsp;it <br />&nbsp;&nbsp;&nbsp;&nbsp; from '<strong>Solution Explorer</strong>' &gt; go to '<strong>Properties</strong>' &gt; select '<strong>Application</strong>' &gt; and choose '<strong>Class Library</strong>' <br />&nbsp;&nbsp;&nbsp;&nbsp; from '&nbsp;Output type'.</p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2210.8.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2210.8.bmp"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2210.8.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2210.8.bmp" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><strong><br /></strong>The last thing&nbsp;that&nbsp;needs to be&nbsp;done is&nbsp;finding a way to transmit information about the destination folder to&nbsp;our '<strong>InstallerOverrideClass</strong>' at runtime. This is achieved using MSI Installer Setup project <strong>Custom</strong>&nbsp;<br /><strong>Actions</strong>.<br /><br /><br /><strong>7.</strong>&nbsp;Right-click the MSI Setup project, select '<strong>Add</strong>' &gt; '<strong>Project Output</strong>' &gt; select <br />&nbsp;&nbsp;&nbsp; '<strong>InstallerOverrideProject</strong>' &gt; click <strong>OK</strong>.</p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/5516.9.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/5516.9.bmp"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/5516.9.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/5516.9.bmp" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><strong>8.</strong>&nbsp;&nbsp;In the 'Solution Explorer', right-click again the Setup project &gt; expand '<strong>View</strong>'&nbsp;&gt; '<strong>Custom Actions</strong>' &gt; <br />&nbsp;&nbsp;&nbsp;&nbsp; in&nbsp;the <strong>Custom Actions</strong>&nbsp;editor window, right-click '<strong>Custom Actions</strong>' root node&nbsp;and click '<strong>Add <br />&nbsp;&nbsp;&nbsp;&nbsp; Custom&nbsp;</strong><strong>Action</strong>'.</p>
<p><strong>9.</strong>&nbsp; In the '<strong>Select Item in Project</strong>'&nbsp;pop-up&nbsp;window, go to the&nbsp;'<strong>Look In</strong>' drop-down&nbsp;list and&nbsp;click <br />&nbsp;&nbsp;&nbsp;&nbsp; '<strong>Application Folder</strong>'. Select '<strong>Primary Output from InstallerOverrideProject (Active)</strong>' and click <strong><br />&nbsp;&nbsp;&nbsp;&nbsp; OK</strong>.</p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3652.10.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3652.10.bmp"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3652.10.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3652.10.bmp" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><strong><br /></strong></p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/5850.11.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/5850.11.bmp"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/5850.11.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/5850.11.bmp" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><strong><br />10.</strong>&nbsp;&nbsp;In the <strong>Custom Actions</strong> editor, right-click&nbsp;on Primary output from <strong>InstallerOverrideProject <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Active)</strong> and click <strong>Properties</strong>.</p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/8105.12.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/8105.12.bmp"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/8105.12.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/8105.12.bmp" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><strong>11.</strong>&nbsp;&nbsp;Enter the following value in&nbsp;the <strong>CustomActionData</strong> property:&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background-color: #dadada; font-family: courier new,courier;"><strong> /target_folder="[TARGETDIR]\"</strong></span> <br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="background-color: #ffff99;">This passes in the location of the&nbsp;</span><span style="background-color: #ffff99;">add-in's DLL at runtime to any class which derives from&nbsp;<strong>Installer</strong></span>.&nbsp;<br /><br /></p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1452.13.1.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1452.13.1.bmp"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1452.13.1.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1452.13.1.bmp" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>&nbsp;</p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>How COM works &amp; How to build a COM visible DLL in C#.Net, call it from VBA and select the proper ClassInterface (AutoDispatch, AutoDual) [part1/2]</title>
      <link>https://docs.microsoft.com/archive/blogs/cristib/how-com-works-how-to-build-a-com-visible-dll-in-c-net-call-it-from-vba-and-select-the-proper-classinterface-autodispatch-autodual-part12</link>
      <pubDate>Wed, 31 Oct 2012 10:38:00 GMT</pubDate>
      <dc:creator><![CDATA[Cristian.Berescu]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cristib/2012/10/31/how-com-works-how-to-build-a-com-visible-dll-in-c-net-call-it-from-vba-and-select-the-proper-classinterface-autodispatch-autodual-part12/</guid>
      <description><![CDATA[&nbsp;




This article is split across two blog posts and this is part #1.. use this...]]></description>
      <content:encoded><![CDATA[<p>&nbsp;</p>
<table style="width: 590px;" border="0">
<tbody>
<tr>
<td>
<p><span style="color: #888888;">This article is split across two blog posts and this is part #1.. use <span style="text-decoration: underline;">this link&nbsp;</span>(<strong>please be patient&nbsp;:), I am still working on part 2</strong>)&nbsp;to go to part #2.<!--EndFragment--></span><br /><br />When a beginner&nbsp;programmer needs to create a COM visible&nbsp;DLL which&nbsp;will be&nbsp;called from VBA, PowerShell, VBScript&nbsp;or .NET applications, he&nbsp;can find lots of tutorials on how to get started.</p>
<p>Some of the articles are just&nbsp;presenting&nbsp;the simplest possible steps to build the COM DLL, others go into more detail. <br /><br />For someone that has not had the opportunity to work extensively with multiple versions of the same COM DLL, it&nbsp;is&nbsp;easy to overlook&nbsp;a couple of very important&nbsp;library design&nbsp;details. If this happens, and the project gets released to end-users, fixing the problem becomes a lot harder.</p>
<p><br /><br /><strong>What's the most important choice&nbsp;when creating COM visible DLLs?&nbsp;&nbsp;</strong></p>
<p><br />ANSWER:&nbsp;Selecting <span style="color: #ffffff; background-color: #3366ff;"><strong>AutoDual</strong></span>, <span style="color: #ffffff; background-color: #3366ff;"><strong>AutoDispatch</strong></span> or <span style="color: #ffffff; background-color: #3366ff;"><strong>None</strong></span> for its interface.&nbsp;</p>
<p><br />Each COM visible library exposes a set of functions to the outside world. The programmer can choose how these functions are discovered by applications referencing his DLL.<br /><br />As this&nbsp;MSDN&nbsp;article explains: <a href="https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.classinterfacetype.aspx">https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.classinterfacetype.aspx</a> <br />(<strong>ClassInterfaceType Enumeration</strong>), we basically have 3 options:</p>
<table style="border-width: 1px 1px 0px; border-style: solid; border-color: #000000; width: 560px; height: 1px; background-color: #ededed;" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier;"><a href="https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.classinterfacetype.aspx">https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.classinterfacetype.aspx</a></span><span style="font-family: courier new,courier; font-size: x-small;"><a href="https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.classinterfacetype.aspx"><br /><br /></a> <span style="font-size: small;"><strong><span style="font-family: arial,helvetica,sans-serif;">ClassInterfaceType Enumeration</span></strong></span><span style="font-size: small;"><strong><br /></strong></span></span><span style="font-size: medium;"><span style="font-family: courier new,courier;">---------------------------------------------------------</span></span><!--EndFragment--></p>
<p><span style="font-family: courier new,courier; font-size: x-small;">[...]</span><br /><br /><span style="font-family: courier new,courier; font-size: small;"><strong>&nbsp;Members</strong></span></p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #7a7a7a; width: 549px; height: 642px;" border="1" align="center">
<tbody>
<tr>
<td style="border: 1px solid #dadada;" valign="top">
<p><span style="font-family: courier new,courier;">Member </span><span style="font-family: courier new,courier;">name &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></p>
</td>
<td style="border: 1px solid #dadada;" valign="top">
<p><span style="font-family: courier new,courier;">Description</span></p>
</td>
</tr>
<tr>
<td style="border-style: solid; border-color: #dadada;" valign="top">
<p><span style="font-family: courier new,courier;">None</span></p>
</td>
<td style="border-style: solid; border-color: #dadada;" valign="top"><span style="font-family: courier new,courier;">Indicates that no class interface is generated for the class. <br /></span><span style="background-color: #ccffcc;"><span style="font-family: courier new,courier;">If no interfaces are </span><span style="font-family: courier new,courier;">implemented explicitly, the class can only provide&nbsp; late-bound access through the </span></span><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;"><strong>IDispatch</strong> interface</span>. </span><br /><br /><span style="font-family: courier new,courier;">This is the recommended setting for <a href="https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.classinterfaceattribute.aspx">ClassInterfaceAttribute</a>. Using ClassInterfaceType.None is the only way to expose functionality through interfaces implemented explicitly by the class.</span>
<p><span style="font-family: courier new,courier;"><a href="https://msdn.microsoft.com/en-us/library/hfzzah2c.aspx">Tlbexp.exe (Type Library Exporter)</a> exposes the first public, <strong>COM-visible interface </strong></span><span style="font-family: courier new,courier;">implemented by the class as the default interface of the <strong>coclass</strong>. <br />Beginning with </span><span style="font-family: courier new,courier;">the .NET Framework version 2.0, you can specify the default interface exposed to </span><span style="font-family: courier new,courier;">COM by using the <a href="https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.comdefaultinterfaceattribute.aspx">ComDefaultInterfaceAttribute</a> attribute. </span><br /><br /><span style="font-family: courier new,courier;">If the class implements no interfaces, the first public, COM-visible interface implemented by a base class becomes the default interface&nbsp; (starting </span><span style="font-family: courier new,courier;">with the most recently derived base class and working backward). Tlbexp.exe </span><span style="font-family: courier new,courier;">exposes _Object as the default interface if neither the class&nbsp; nor its base classes implement interfaces.</span></p>
</td>
</tr>
<tr>
<td style="border-style: solid; border-color: #dadada;" valign="top">&nbsp;
<p><span style="font-family: courier new,courier;">AutoDispatch&nbsp;&nbsp; </span></p>
</td>
<td style="border-style: solid; border-color: #dadada;" valign="top"><span style="font-family: courier new,courier;">Indicates that the class only supports <span style="background-color: #ccffcc;">late binding</span> for COM clients. A <strong>dispinterface</strong> for the class is automatically exposed to COM clients on request. The <strong>type library</strong> produced by <a href="https://msdn.microsoft.com/en-us/library/hfzzah2c.aspx">Tlbexp.exe (Type Library Exporter)</a><br /> <span style="background-color: #ffff99;">does not contain type information for the <strong>dispinterface</strong> in order to </span><span style="background-color: #ffff99;">prevent clients from caching the <strong>DISPIDs</strong> of the interface</span>. <span style="background-color: #ccffcc;">The</span> <span style="background-color: #ccffcc;"><strong>dispinterface</strong> does not exhibit the versioning problems described in <a href="https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.classinterfaceattribute.aspx"><span style="background-color: #ccffcc;">ClassInterfaceAttribute</span></a> because clients can only <strong>late-bind</strong> to the </span><span style="background-color: #ccffcc;">interface</span>.</span>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;">This is the default setting for <a href="https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.classinterfaceattribute.aspx"><span style="background-color: #ffff99;">ClassInterfaceAttribute</span></a></span>.</span></p>
</td>
</tr>
<tr>
<td style="border-style: solid; border-color: #dadada;" valign="top">&nbsp;
<p><span style="font-family: courier new,courier;">AutoDual</span></p>
</td>
<td style="border-style: solid; border-color: #dadada;" valign="top">
<p><span style="font-family: courier new,courier;">Indicates that a <strong>dual class interface</strong> is automatically generated for&nbsp;the class and exposed to <strong>COM</strong>. <span style="background-color: #ffcc99;">Type information is produced for the </span><span style="background-color: #ffcc99;">class interface and published in the type library</span>. <span style="background-color: #ffcc99;">Using <strong>AutoDual</strong> is&nbsp;</span><span style="background-color: #ffcc99;"><span style="color: #ffffff; background-color: #3366ff;"><strong>strongly discouraged</strong></span> because of the versioning </span></span><span style="font-family: courier new,courier;"><span style="background-color: #ffcc99;">limitations described</span><br /><span style="background-color: #ffcc99;"> in <a href="https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.classinterfaceattribute.aspx"><span style="background-color: #ffcc99;">ClassInterfaceAttribute</span></a></span>.</span></p>
</td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier; font-size: x-small;">[...]&nbsp;</span>&nbsp;</p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>By-default, if you don't do anything to change the class interface settings, <strong>Visual Studio</strong> will automatically generate:<br />&nbsp;&nbsp; &gt; an <strong>AutoDispatch</strong> interface for your COM library if you create it using C#;<br />&nbsp;&nbsp; &gt; an <strong>AutoDual</strong> interface for your COM library if you create it using VB.Net;</p>
<p>&nbsp;</p>
<p><strong>Why is this choice so important?&nbsp;&nbsp;</strong></p>
<p>It matters because programs are caching (binding to) your DLL's interface&nbsp;information (it is an internal optimization designed to improve code execution speed - I'll give you more details later in the article).<br /><br />If you plan to release new versions&nbsp;which will run&nbsp;side-by-side or will replace the old ones, you&nbsp;don't want everyone else to recompile the code which calls into your library.</p>
<p>&nbsp;</p>
<p><strong>Some background information about COM (how it works behind the scenes)</strong></p>
<p>Microsoft has released a very nice article which explains how COM works from the Office&nbsp;point of view.&nbsp;However, its design principles apply to all COM&nbsp;libraries:</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 590px; background-color: #ededed;" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier; font-size: x-small;"><a title="https://msdn.microsoft.com/en-us/library/aa155776(v=office.10).aspx" href="https://msdn.microsoft.com/en-us/library/aa155776(v=office.10).aspx" target="_blank">https://msdn.microsoft.com/en-us/library/aa155776(v=office.10).aspx</a><br /><br /> <strong></strong> <span style="font-family: arial,helvetica,sans-serif; font-size: small;"><strong>Automating Microsoft Office 97 and Microsoft Office 2000<br /></strong></span></span><span style="font-family: courier new,courier; font-size: small;">-------------------------------------------------------------------------</span> <!--EndFragment--></p>
<p><span style="font-family: courier new,courier;">[...]</span></p>
<p class="dtH1"><span style="font-family: courier new,courier; font-size: small;"><strong>Introduction</strong></span></p>
<p><span style="font-family: courier new,courier;"><strong><em>Automation</em></strong>, formerly called "<strong>OLE Automation</strong>" is a technology that allows you to take advantage of an existing program's content and functionality, and to incorporate it into your own applications. <strong>Automation</strong> is based on the <strong><em>Component Object Model</em> (COM)</strong>. <strong>COM</strong> is a standard software architecture based on interfaces that is designed to separate code into self-contained objects, or components. Each component exposes a set of interfaces through which all communication to the component is handled.</span></p>
<p><span style="font-family: courier new,courier;">With <strong>Automation</strong>, you can use the Microsoft&reg; Word mail merge feature to generate form letters from data in a database without the user being aware that Word is involved. You could even use Automation to incorporate all of the charting and data analysis functionality that Microsoft Excel provides. You don't need to write your own calculation engine to provide the multitude of mathematical, financial, and engineering functions that Excel provides; instead, you can automate Microsoft Excel to "borrow" this functionality and incorporate it into your own application.</span></p>
<p><span style="font-family: courier new,courier;"><strong>Automation</strong> consists of a <span style="background-color: #cacaca;"><strong><em>client</em></strong></span> and a <em><strong></strong><span style="background-color: #cacaca;"><strong>server</strong></span>.</em> The <strong>Automation</strong> client attaches to the <strong>Automation</strong> <strong>server</strong> so that it can use the content and functionality that the Automation server provides. <span style="background-color: #ccffcc;">The terms <strong><em>client</em></strong> and <strong><em>server</em></strong> are mentioned frequently throughout this article, so it is important that you understand their relationship</span>.</span></p>
<p><span style="font-family: courier new,courier;">This article is intended to provide you with a foundation for developing your own Automation clients for Microsoft Office applications. In this article, we provide a hands-on approach to help you to do the following:</span></p>
<ul>
<li><span style="font-family: courier new,courier;">Understand how Office applications expose their content and functionality to Automation clients;</span></li>
<li><span style="font-family: courier new,courier;">Identify the specific functions for the task you choose to Automate;</span></li>
<li><span style="font-family: courier new,courier;">Locate the resources and documentation you need;</span></li>
<li><span style="font-family: courier new,courier; background-color: #ffff99;">Understand how Automation works behind the scenes;</span></li>
<li><span style="font-family: courier new,courier;">Create Automation clients with Visual Basic&reg;, Visual C++&reg;, and Microsoft Foundation Classes (MFC);</span></li>
<li><span style="font-family: courier new,courier;">Develop a controller that uses the server as efficiently as possible;</span></li>
</ul>
<p><span style="font-family: courier new,courier;">All the Microsoft Office applications have their own scripting language, which can be used to perform tasks within applications. This scripting language is Microsoft Visual Basic for Applications (VBA). The set of functions that a VBA routine, or <em>macro,</em> can use to control its host application is the same set of functions that the Automation client can use to control the application externally, regardless of the programming language for the controller.</span></p>
<p><span style="font-family: courier new,courier;">[...]</span></p>
<p>&nbsp;</p>
<p class="dtH1"><strong><span style="font-family: courier new,courier; font-size: small;">Type Libraries</span></strong></p>
<p class="dtH1">&nbsp;</p>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;">A <strong>type library</strong> specifies all the information an <strong>Automation</strong> client needs to call a <strong>method</strong> or <strong>property</strong> for an <strong>object</strong></span>. <span style="background-color: #ccffcc;">For <strong>properties</strong>, the <strong>type library</strong> describes the value it accepts or returns. For methods, the <strong>type library</strong> provides a list of all the arguments the method can accept, tells you the data type of each argument, and indicates whether an argument is required.</span></span></p>
<p><span style="font-family: courier new,courier;">Type libraries can appear in any of the following forms:</span></p>
<ul>
<li><span style="font-family: courier new,courier;">A resource in a .dll file;</span></li>
<li><span style="font-family: courier new,courier;">A resource in an .exe file;</span></li>
<li><span style="font-family: courier new,courier;">A stand-alone type library file (.tlb);</span></li>
</ul>
<p><span style="font-family: courier new,courier;">[...]</span><br /><span style="font-size: small;"><strong><span style="font-family: courier new,courier;"><br /></span></strong></span></p>
<p><span style="font-size: small;"><strong><span style="font-family: courier new,courier;">OLE/COM Object Viewer</span></strong></span></p>
<p><span style="font-family: courier new,courier;"><br />To view type library information, you can also use the <strong><span style="background-color: #cacaca;">OLE/COM Object Viewer</span></strong> utility that is included with <strong>Microsoft Visual Studio&reg;</strong>. Like the <strong>Object Browser</strong> that <strong>Visual Basic</strong> and <strong>Microsoft VBA</strong> use, the <span style="background-color: #ccffcc;"><strong>OLE/COM Object Viewer</strong> lists all the classes exposed in a <strong>type</strong> <strong>library</strong>, along with the <strong>methods</strong> and <strong>properties</strong> those classes support.</span> <span style="background-color: #ffff99;">For the C++ programmer, the OLE<strong>/COM Object Viewer</strong> provides important information, such as function return types, argument types, and <strong>DISPIDs</strong> (which will be discussed shortly). You can use the information that the viewer provides in conjunction with the Office object model documentation.<br /></span></span>&nbsp;</p>
<p><span style="font-family: courier new,courier;">To view a <strong>type library</strong> with the <strong>OLE/COM Object Viewer</strong>:</span></p>
<ol>
<li><span style="font-family: courier new,courier;">In Visual C++, on the <strong>Tools</strong> menu, click <strong>OLE/COM Object Viewer</strong>.</span></li>
<li><span style="font-family: courier new,courier;">On the <strong>File </strong>menu, click <strong>View TypeLib</strong>, and browse to locate the type library you want to view.</span>&nbsp;</li>
</ol>
<p><span style="font-family: courier new,courier;">The OLE/COM Object Viewer illustrated in Figure 3 displays information from the Microsoft Word 97 type library. More specifically, it shows the details for the <strong>Add </strong>member function of the <strong>Documents </strong>class.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0535.1.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0535.1.bmp"><img style="margin-right: auto; margin-left: auto; display: block;" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0535.1.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0535.1.bmp" alt="" border="0" /></a></p>
<p><span style="font-family: courier new,courier;"><strong>&nbsp;&nbsp; Figure 3. Use the OLE/COM Object Viewer to view class information in a<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;type&nbsp;library.</strong></span></p>
<p><span style="font-family: courier new,courier;">[...]<br /><br /></span></p>
<p class="dtH1"><strong><span style="font-family: courier new,courier; font-size: small;">PROGIDs and CLSIDs<br /><br /><br /></span></strong><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;">Office applications register all of their classes in the Windows&reg; system registry</span>. <span style="background-color: #ffff99;">Each <strong>class</strong> is associated with a <em>globally <strong>unique identifier</strong></em> (or <span style="background-color: #cacaca;">GUID</span>) called a </span><span style="background-color: #ffff99;"><strong><em>class identifier</em></strong></span></span><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;">.</span> In the registry, each class identifier (or <span style="background-color: #cacaca;"><strong>CLSID</strong></span>) is mapped to a <em>programmatic identifier</em> (or <strong><span style="background-color: #cacaca;">PROGID</span></strong>) and to its application, as shown in Figure 4.<br /></span><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/8863.2.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/8863.2.bmp"><img style="margin-right: auto; margin-left: auto; display: block;" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/8863.2.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/8863.2.bmp" alt="" border="0" /></a><br /><span style="font-family: courier new,courier;"><strong>&nbsp;&nbsp; Figure 4. The relationship between PROGID, CLSID, and Server as described<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;in the Windows&nbsp;registry</strong></span></p>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;">When automating an Office application, you can use either the <strong>CLSID</strong> or the <strong>PROGID</strong> to create an object from one of the classes that the Office application exposes</span>.</span></p>
<p><span style="font-family: courier new,courier;">[...]</span>&nbsp;</p>
<p><br />&nbsp;</p>
<p class="dtH1"><span style="font-family: courier new,courier; font-size: small;"><strong>How an Object Exposes Its Methods and Properties<br /><br /></strong></span></p>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;">All <strong>COM objects</strong> that can be automated implement a special interface:</span> <span style="background-color: #ffff99;">the <strong>IDispatch</strong> interface</span>. <span style="background-color: #ccffcc;">It is this <strong>IDispatch</strong> interface that provides Automation clients with access to an object's content and functionality</span>. <span style="background-color: #ffff99;">An object can expose its methods and properties in two ways: by means of a </span></span><span style="background-color: #ffff99;"><span style="color: #ff0000;"><span style="font-family: courier new,courier;"><span style="font-family: arial,helvetica,sans-serif;"><strong><em>dispatch interface </em></strong><span style="color: #000000; font-family: courier new,courier;">and in its </span><strong><em><em>vtable</em></em></strong></span></span></span></span><span style="font-family: courier new,courier;">.<br /><br /></span></p>
<p class="dtH1"><strong><span style="font-family: courier new,courier; font-size: small;">The Dispatch Interface<br /><br /></span></strong></p>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;">An object's <strong>methods</strong> and <strong>properties</strong> collectively make up its <strong><em>dispatch</em> <em>interface</em></strong></span> (or </span><span style="font-family: courier new,courier;"><span style="color: #ffffff; font-family: arial,helvetica,sans-serif; background-color: #3366ff;"><strong><em>dispinterface</em></strong></span></span><span style="font-family: courier new,courier;">). <span style="background-color: #ffff99;">Within the <strong>dispinterface</strong>, each method and property is identified by a unique member</span>. This member is the function's </span><span style="font-family: arial,helvetica,sans-serif;"><span style="color: #ffffff; background-color: #3366ff;"><strong><em>dispatch identifier</em></strong></span></span><span style="font-family: courier new,courier;">(or <span style="background-color: #ffff99;"><strong><em>DispID</em></strong></span>).</span></p>
<p class="fig"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7450.3.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7450.3.bmp"><img style="margin-right: auto; margin-left: auto; display: block;" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7450.3.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7450.3.bmp" alt="" border="0" /></a></p>
<p class="label"><span style="font-family: courier new,courier;"><strong>&nbsp;&nbsp; Figure 5. An object can provide clients access to its functions using a <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dispinterface, an&nbsp;array of function names, and an array of<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;function pointers that are indexed by&nbsp;DispIDs.</strong></span></p>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;">To execute a method or a property of the object portrayed in Figure 5, an <strong>Automation</strong> <strong>client</strong> can</span>:</span></p>
<ol>
<li><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;">Call <strong>GetIDsOfNames</strong> to "look up" the <strong>DispID</strong> for the method or property</span>.</span></li>
<li><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;">Call <strong>Invoke</strong> to execute the method or property by using the <strong>DispID</strong> to index the array of function pointers</span>.</span></li>
</ol>
<blockquote class="dtBlock">
<div><span style="font-family: courier new,courier;"><strong class="le">Note&nbsp;&nbsp;&nbsp;</strong>IDispatch and its functions are described in greater detail in this article under <a href="https://msdn.microsoft.com/en-us/library/aa155776(v=office.10).aspx#offaut_creautclicplus">"Creating an Automation client with C++."</a></span></div>
</blockquote>
<p class="dtH1"><strong><span style="font-family: courier new,courier; font-size: small;"><br /><br />Virtual Function Table (vtable)<br /></span></strong></p>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;">The <strong>pointer</strong> to an interface <span style="background-color: #ffff99;">references a table of pointers to functions</span> that the interface supports. This table is called the <span style="background-color: #ffff99;"><em>virtual function table</em></span> (or </span></span><strong><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;"><span style="color: #ffffff; font-family: arial,helvetica,sans-serif; background-color: #3366ff;"><em>vtable</em></span></span></span></strong><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;">).</span> <span style="background-color: #ffff99;">A <strong>COM object</strong> can expose its functions in its <strong>vtable</strong> to provide clients more direct access to the functions</span>. </span><span style="color: #000000; font-family: courier new,courier;">Subsequently, this eliminates the need to call </span><span style="color: #ffffff; font-family: arial,helvetica,sans-serif; background-color: #3366ff;"><strong>Invoke</strong></span><span style="color: #000000; font-family: courier new,courier;"> and </span><span style="color: #ffffff; background-color: #3366ff;"><strong><span style="font-family: courier new,courier;">GetIDsOfNames</span></strong></span><span style="color: #000000; font-family: courier new,courier;">.</span></p>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;">An object that exposes its methods through both a </span></span><span style="font-family: arial,helvetica,sans-serif;"><span style="background-color: #ffff99;"><strong><span style="color: #ffffff; background-color: #3366ff;">dispinterface</span></strong></span></span><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;"> and its </span></span><span style="color: #000000; font-family: courier new,courier; background-color: #ffff99;"><strong>vtable</strong></span><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;"> supports a </span></span><span style="color: #ff0000; font-family: arial,helvetica,sans-serif; font-size: small;"><strong><span style="background-color: #ffff99;"><em>dual interface</em></span></strong></span><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;">.</span> Figure 6 represents an object that has a dual interface. Clients can either:</span></p>
<ul>
<li><span style="font-family: courier new,courier; background-color: #ffff99;">Access its functions using <strong>GetIDsOfNames</strong> and <strong>Invoke</strong>.&nbsp;</span>
<p><span style="font-family: courier new,courier;">-or-</span></p>
</li>
<li><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;">Access its functions through the <strong>vtable</strong>.</span> <span style="background-color: #ffcc99;">It is up to the Automation client to decide which method it uses to gain access to the object's functions.</span></span></li>
</ul>
<p class="fig"><span style="font-family: courier new,courier; font-size: x-small;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3386.4.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3386.4.bmp"><img style="margin-right: auto; margin-left: auto; display: block;" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3386.4.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3386.4.bmp" alt="" border="0" /></a></span></p>
<p class="label"><span style="font-family: courier new,courier;"><strong>&nbsp;&nbsp; Figure 6. An object that has a dual interface can provide clients access<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;to its functions with&nbsp;a dispinterface and in its vtable.</strong></span></p>
<p><span style="font-family: courier new,courier;">You can examine type libraries in the <strong>OLE/COM Object Viewer</strong> to determine if an object provides a dual interface. An object that provides a dual interface specifies the dual attribute in its interface declaration.</span></p>
<p class="dtH1"><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;">[...]</span></span></p>
</td>
</tr>
</tbody>
</table>
<p>Sorry for using so many different colors to highlight the article from above, but it is vital that you don't miss one of those key concepts.</p>
<p>&nbsp;</p>
<p>So .. to briefly summarize what's written above:<br /><br />&nbsp;&nbsp; &gt; when COM libraries&nbsp;get registered on the client machine, they create a set of entries (<strong>PROGID</strong>, <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>CLSID</strong> ..etc) in the Registry; These&nbsp;entries help client programs discover COM&nbsp;automation servers;<br /><br />&nbsp;&nbsp; &gt; client programs can create&nbsp;instantiate COM server objects&nbsp;using their <strong>PROGID&nbsp;</strong>(example: <strong><span style="font-family: courier new,courier; background-color: #cacaca;">CreateObject<br /></span><span style="font-family: courier new,courier;"><span style="background-color: #ffffff;">&nbsp; <span style="background-color: #cacaca;">("&lt;some CO</span></span></span><span style="background-color: #cacaca;"><span style="font-family: courier new,courier;">M</span><span style="font-family: courier new,courier;">_DLL PROGID&gt;")</span></span></strong> ) or <strong>CLSID</strong> (example: <span style="background-color: #cacaca;"><strong><span style="font-family: courier new,courier;">ProgIDFromCLSID(</span></strong></span><span style="font-family: courier new,courier;"><strong><span style="font-family: courier new,courier; background-color: #cacaca;"><strong>&lt;</strong>some CLSID&gt;",&nbsp;</span><br />&nbsp;&nbsp;<span style="background-color: #cacaca;">&amp;progid)</span></strong></span>);<br /><br />&nbsp;&nbsp; &gt; all COM libraries expose their internal functions using&nbsp;a <strong>dispatch</strong> <strong>interface </strong>(which is made of a collection <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; of separate interfaces, such as <strong>IUnknown</strong>, <strong>IDispatch</strong> ..etc);<br /><br />&nbsp;&nbsp;&gt;&nbsp; specific&nbsp;functions inside the <strong>IDispatch</strong> interface are responsible for allowing client programs to "look up"&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; methods inside the COM library (<strong>GetIDsOfNames</strong>);<br /><br />&nbsp;&nbsp; &gt; &nbsp;if <strong>IDispatch::</strong><strong>GetIDsOfNames&nbsp;</strong>returns a valid&nbsp;function pointer (<strong>DISPID</strong>), the client program calls <strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IDispatch::</strong><strong>Invoke </strong>and&nbsp;uses the<strong> DISPID&nbsp;</strong>pointer to execute it;&nbsp;<br /><br />&nbsp;&nbsp; &gt;&nbsp; other functions exposed by the <strong>dispatch</strong> <strong>interface </strong>handle the lifetime of the COM object (we'll talk more <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; about the <strong>IUnknown</strong> interface in the next paragraphs);<br /><br />&nbsp;&nbsp; &gt; &nbsp;but&nbsp;if the creator of the COM DLL&nbsp;wishes so, he can allow client programs to&nbsp;bind to his library's&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>vtable</strong> of <strong>DISPID&nbsp;</strong>function pointers; In this way, clients can optimize the execution speed (by not having<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;to&nbsp;discover,&nbsp;then execute each COM method call .. they can use the <strong>DISPID</strong>s which are already cached)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;of&nbsp;COM automation code.</p>
<p>&nbsp;</p>
<p>This&nbsp;was a high level&nbsp;overview of&nbsp;what happens behind the scenes .. the whole process of calling and sending / receiving&nbsp;parameters to COM&nbsp;servers is more complex.</p>
<p><br />For the sake of completeness, I will go ahead and cite the rest of the article which talks about the inner workings of <strong>IDispatch</strong> and <strong>IUnknown</strong>. You will need this information if you decide to write your own COM automation&nbsp;client program in C++, or if you build&nbsp;your own&nbsp;compiler&nbsp;(which will need to do&nbsp;this kind of dirty work, to&nbsp;let the programmer concentrate on&nbsp;writing the code,&nbsp;without worrying how COM calls will be triggered).&nbsp;&nbsp;</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 590px; background-color: #ededed;" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier; font-size: x-small;"><span style="font-size: small;"><strong><span style="font-family: courier new,courier; font-size: x-small;"><a title="https://msdn.microsoft.com/en-us/library/aa155776(v=office.10).aspx" href="https://msdn.microsoft.com/en-us/library/aa155776(v=office.10).aspx" target="_blank">https://msdn.microsoft.com/en-us/library/aa155776(v=office.10).aspx</a><br /><br /><strong></strong> <span style="font-family: arial,helvetica,sans-serif; font-size: small;"><strong>Automating Microsoft Office 97 and Microsoft Office 2000<br /></strong></span></span></strong></span></span><span style="font-family: courier new,courier; font-size: small;">-------------------------------------------------------------------</span> <!--EndFragment--></p>
<p><span style="font-family: courier new,courier;">[...]</span><br /><br /><span style="font-family: courier new,courier; font-size: small;"><strong>Creating an Automation Client with C++</strong></span></p>
<p class="dtH1"><span style="font-family: courier new,courier; font-size: small;"><strong>The <span style="color: #ffffff; background-color: #3366ff;">IUnknown</span> and <span style="color: #ffffff; background-color: #3366ff;">IDispatch</span> Interfaces<br /></strong></span></p>
<p><span style="font-family: courier new,courier;">Interfaces are the cornerstone to COM. <span style="background-color: #ffff99;">An <strong><em>interface</em></strong> is a table of pointers to related functions</span>. <span style="background-color: #ffff99;">Once you acquire a pointer to an interface, you have access to the functions in that interface</span>. <span style="background-color: #ffcc99;">The <strong>IUnknown</strong> and <strong>IDispatch</strong> interfaces are at the heart of Automation.</span></span></p>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ffcc99;">All COM interfaces inherit from the <strong>IUnknown </strong>interface.</span> <strong>IUnknown</strong> gives COM objects the means to manage their lifetimes and provides clients access to other interfaces that an object supports. The <strong>IUnknown</strong> interface has only three functions, all of which a COM object must support.</span></p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #7a7a7a; width: 529px; height: 112px; table-layout: auto;" border="1" align="center">
<tbody>
<tr>
<td style="border: 1px solid #dadada;"><strong><span style="font-family: courier new,courier;">IUnknown::QueryInterface()&nbsp;&nbsp; </span></strong></td>
<td style="border: 1px solid #dadada; margin-right: auto; margin-left: auto;"><span style="font-family: courier new,courier;">Called to identify and navigate interfaces that an object supports</span></td>
</tr>
<tr>
<td style="border-style: solid; border-color: #dadada;" width="40%"><strong><span style="font-family: courier new,courier;">IUnknown::AddRef()</span></strong></td>
<td style="border-style: solid; border-color: #dadada;"><span style="font-family: courier new,courier;">Called each time a client makes a request for an interface</span></td>
</tr>
<tr>
<td style="border-style: solid; border-color: #dadada;"><strong><span style="font-family: courier new,courier;">IUnknown::Release()</span></strong></td>
<td style="border-style: solid; border-color: #dadada;"><span style="font-family: courier new,courier;">Called each time a client releases an interface</span></td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier;">Each <strong>COM object</strong> is responsible for maintaining a count of the number of interface pointers it has handed out to clients by means of <strong>AddRef</strong> and <strong>Release</strong>. This count is called the <em>reference count.</em> When the object's reference count goes to zero, this is an indication to the object that there are no clients currently using its interfaces and that it can safely remove itself from memory. As you can imagine, properly maintaining reference counts is very important; if references to objects are not properly released, you risk the chance of leaving an object in memory even when it is no longer in use.</span></p>
<p><span style="font-family: courier new,courier;">In addition to <strong>IUnknown</strong>, every <strong>COM object</strong> that can be automated implements <strong>IDispatch</strong> because it is <strong>IDispatch</strong> that gives a client access to the object's properties and methods. The <strong>IDispatch</strong> interface provides the means for automating COM objects using only four functions.</span></p>
<table style="border-width: 3px 0px; border-style: solid; border-color: #7a7a7a; width: 541px; height: 144px; table-layout: auto;" border="1" align="center">
<tbody>
<tr>
<td style="border: 1px solid #dadada;" width="42%"><strong><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;"><strong>IDispatch::GetTypeInfoCount()</strong></span>&nbsp; </span></strong></td>
<td style="border: 1px solid #dadada; margin-right: auto; margin-left: auto;"><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;">Called to determine if type information is available</span></span></td>
</tr>
<tr>
<td style="border-style: solid; border-color: #dadada;"><strong><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;"><strong>IDispatch::GetTypeInfo()</strong></span></span></strong></td>
<td style="border-style: solid; border-color: #dadada;"><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;">Called to retrieve the type information</span></span></td>
</tr>
<tr>
<td style="border-style: solid; border-color: #dadada;"><strong><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;"><strong>IDispatch::GetIDsOfNames()</strong></span></span></strong></td>
<td style="border-style: solid; border-color: #dadada;"><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;">Called to obtain the DISPID from the name of a property or method</span></span></td>
</tr>
<tr>
<td style="border-style: solid; border-color: #dadada;"><strong><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;"><strong><span style="font-family: courier new,courier;"><strong>IDispatch::Invoke()</strong></span></strong></span></span></strong></td>
<td style="border-style: solid; border-color: #dadada;"><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;">Called to invoke a method or property for the object</span></span></span></td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier;">To begin the<strong> Automation</strong> process, a client creates an instance of the <strong>Automation server</strong> by making a call to <strong>::CoCreateInstance</strong>. With <strong>::CoCreateInstance</strong>, you provide a CLSID for the Automation server and make a request for the <strong>IUnknown</strong> interface. (Note that you can determine the <strong>CLSID</strong> from the <strong>ProgID</strong> at run time with <strong>::CLSIDFromProgID.</strong>) Once the pointer to <strong>IUnknown</strong> is received, the client can then make the call to <strong>IUnknown::QueryInterface</strong> for a pointer to the object's <strong>IDispatch</strong> interface. The following code illustrates how an <strong>Automation client</strong> can create a new instance of Microsoft Word and obtain an <strong>IDispatch</strong> pointer to Word's Application object:</span></p>
<table style="width: 560px; margin-right: auto; margin-left: auto;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #dedede;">
<p><strong><span style="color: #339966; font-family: courier new,courier;">// Get the CLSID for Word's Application Object</span></strong><br /><span style="font-family: courier new,courier;">CLSID clsid;</span><br /><span style="font-family: courier new,courier;">CLSIDFromProgID(L"Word.Application", &amp;clsid);&nbsp; </span><br /><br /><strong><span style="color: #339966; font-family: courier new,courier;">// Create an instance of the Word application and obtain the pointer</span></strong><br /><strong><span style="color: #339966; font-family: courier new,courier;">// to the application's IUnknown interface</span></strong><br /><span style="font-family: courier new,courier;">IUnknown* pUnk;</span><br /><span style="font-family: courier new,courier;">HRESULT hr = ::CoCreateInstance( clsid,</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL,</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CLSCTX_SERVER,</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IID_IUnknown,</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void**) &amp;pUnk);</span><br /><br /><span style="color: #339966;"><strong><span style="font-family: courier new,courier;">// Query IUnknown to retrieve a pointer to the IDispatch interface</span></strong></span><br /><span style="font-family: courier new,courier;">IDispatch* pDispApp;</span><br /><span style="font-family: courier new,courier;">hr = pUnk-&gt;QueryInterface(IID_IDispatch, (void**)&amp;pDispApp);</span></p>
</td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier;"><br />Once the <strong>client</strong> has a pointer to the object's <strong>IDispatch</strong> interface, it can begin the work of calling the object's exposed methods and properties. To call methods and properties, it needs their corresponding <strong>DISPIDs</strong>. The <strong>Automation</strong> client can call <strong>IDispatch::GetIDsOfNames</strong> to retrieve a <strong>DISPID</strong> for a function of the object. Then, with the DISPID in hand, the client can use <strong>IDispatch::Invoke</strong> to invoke the method or property.</span></p>
<p><span style="font-family: courier new,courier;">Now consider the <strong>IDispatch</strong> interface in terms of a C/C++ Automation client that automates Word to create a document similar to that of your Visual Basic Automation client. Figure 7 represents how this Automation client might use the <strong>IDispatch</strong> interface for the Automation server:<br /><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4186.5.bmp" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4186.5.bmp"><img style="margin-right: auto; margin-left: auto; display: block;" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4186.5.bmp" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4186.5.bmp" alt="" border="0" /></a></span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: courier new,courier;"><strong>Figure 7. A representation of the COM objects that an Automation client<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;might access for&nbsp;Microsoft Word</strong></span></p>
<p><span style="font-family: courier new,courier;">The <strong>Automation client</strong> represented in <strong>Figure 7</strong>:</span></p>
<ul>
<li><span style="font-family: courier new,courier;">Calls <strong>::CoCreateInstance</strong> to create a new instance of Microsoft Word<br />and obtains a pointer to the <strong>Application</strong> object's <strong>IUnknown</strong> interface,<br /> </span><span style="background-color: #cacaca;"><strong><span style="font-family: courier new,courier;"><code>pUnk</code></span></strong></span><span style="font-family: courier new,courier;">.</span></li>
<li><span style="font-family: courier new,courier;">Obtains a pointer to the <strong>Application</strong>'s object's <strong>IDispatch</strong> interface<br /> through a call to <strong>IUnknown::QueryInterface</strong>. This pointer is </span><strong><span style="font-family: courier new,courier; background-color: #cacaca;"><code>pDispApp</code></span></strong><span style="font-family: courier new,courier;">.</span></li>
<li><span style="font-family: courier new,courier;">Calls <strong>IDispatch::GetIDsOfNames</strong> on </span><span style="font-family: courier new,courier; background-color: #cacaca;"><code>pDispApp</code></span><span style="font-family: courier new,courier;"> to acquire the <strong>DISPID</strong> of<br /> the Application's <strong>Documents</strong> property and receives the DISPID <span style="background-color: #ffcc99;">0x6</span>.</span></li>
<li><span style="font-family: courier new,courier;">Calls <strong>IDispatch::Invoke</strong> with the DISPID <span style="background-color: #ffcc99;">0x6</span> to get the <strong>Documents</strong> <br />property. The call to get the <strong>Documents</strong> property returns a pointer<br /> to <strong>IDispatch</strong> for the <strong>Documents</strong> collection. This pointer is </span><span style="background-color: #cacaca;"><strong><span style="font-family: courier new,courier;"><code>pDispDocs</code></span></strong></span><span style="font-family: courier new,courier;">.</span></li>
<li><span style="font-family: courier new,courier;">Calls <strong>IDispatch::GetIDsOfNames</strong> on </span><span style="font-family: courier new,courier; background-color: #cacaca;"><code>pDispDocs</code></span><span style="font-family: courier new,courier;"> to acquire the <strong>DISPID</strong> of<br /> the Documents' <strong>Add</strong> method and receives the DISPID <span style="background-color: #ffcc99;">0xb</span>.</span></li>
<li><span style="font-family: courier new,courier;">Calls <strong>IDispatch::Invoke</strong> with the DISPID <span style="background-color: #ffcc99;">0xb</span> to execute the <strong>Add</strong> method<br /> so that a new document is added in Microsoft Word.</span></li>
<li><span style="font-family: courier new,courier;">Continues in this same manner, making calls to pairs of <strong>IDispatch::GetIDsOfNames</strong> and <strong>IDispatch::Invoke</strong>, until the automated <br />task&nbsp;is complete.</span></li>
</ul>
<p><span style="font-family: courier new,courier;">When <strong>IDispatch::Invoke</strong> is called upon to invoke a method or property, it also<strong> </strong>passes on parameters for the invoked method or property and receives its return value, if a value is returned. As you can see, <strong>IDispatch::Invoke</strong> really does most of the work in this process and rightfully deserves a little extra attention.</span></p>
<table style="width: 560px; margin-right: auto; margin-left: auto;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #dedede;">
<p><span style="color: #000000;"><span style="font-family: courier new,courier;">HRESULT Invoke(</span><strong><span style="font-family: courier new,courier;"> <br />&nbsp; </span></strong><span style="font-family: courier new,courier;">DISPID&nbsp; dispIdMember</span><strong><span style="font-family: courier new,courier;">,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #339966;">// DISPID for the member function&nbsp;</span> <br />&nbsp; </span></strong><span style="font-family: courier new,courier;">REFIID&nbsp; riid,&nbsp;&nbsp;</span><strong><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #339966;">// Reserved, must be IID_NULL&nbsp;&nbsp;&nbsp;</span> <br />&nbsp; </span></strong><span style="font-family: courier new,courier;">LCID&nbsp; lcid,&nbsp;</span><strong><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #339966;">//</span> <span style="color: #339966;">Locale</span><br />&nbsp; </span></strong><span style="font-family: courier new,courier;">WORD&nbsp; wFlags,&nbsp;</span><strong><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #339966;">// Flags describing the call's context</span><br />&nbsp; </span></strong><span style="font-family: courier new,courier;">DISPPARAMS FAR*&nbsp; pDispParams,</span><strong><span style="font-family: courier new,courier;"> <span style="color: #339966;">// Structure containing the arguments</span><br />&nbsp; </span></strong><span style="font-family: courier new,courier;">VARIANT FAR*&nbsp; pVarResult,</span><strong><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #339966;"> // Return Value of invoked call</span><br />&nbsp; </span></strong><span style="font-family: courier new,courier;">EXCEPINFO FAR*&nbsp; pExcepInfo,</span><strong><span style="font-family: courier new,courier;">&nbsp;&nbsp; <span style="color: #339966;">// Error information</span><br />&nbsp; </span></strong><span style="font-family: courier new,courier;">unsigned int FAR*&nbsp; puArgErr</span><strong><span style="font-family: courier new,courier;">&nbsp;&nbsp; <span style="color: #339966;">// Indicates which argument causes error</span><br /></span></strong><span style="font-family: courier new,courier;">);</span><strong><span style="font-family: courier new,courier;"><br /></span></strong></span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p><span style="font-family: courier new,courier;">Examine the arguments for <strong>IDispatch::Invoke</strong> in more detail:</span></p>
<ul>
<li><span style="font-family: courier new,courier;"><strong><em>dispIDMember </em></strong>is the DISPID of the method or property you want to invoke.</span></li>
<li><span style="font-family: courier new,courier;"><strong><em>riid </em></strong>is reserved and must be IID_NULL.</span></li>
<li><span style="font-family: courier new,courier;"><strong><em>lcid</em></strong> is the locale context and can be used to allow the object to interpret the call specific to a locale.</span></li>
<li><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;"><strong><em>wFlags</em></strong> indicates the type of member function you're invoking; are you executing a method, getting a property, or setting a property? The <em>wFlags </em>parameter can contain the following:<br /></span></span>
<table style="border-width: 3px 0px; border-style: solid; border-color: #7a7a7a; width: 459px; height: 102px; float: left; table-layout: auto;" border="1" align="center">
<tbody>
<tr>
<td style="border: 1px solid #dadada;" width="42%"><strong><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;">DISPATCH_METHOD</span>&nbsp; </span></strong></td>
<td style="border: 1px solid #dadada; margin-right: auto; margin-left: auto;"><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;">Executes a method</span></span></span></td>
</tr>
<tr>
<td style="border-style: solid; border-color: #dadada;"><strong><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;"><strong><span style="font-family: courier new,courier;">DISPATCH_PROPERTYGET</span></strong></span></span></strong></td>
<td style="border-style: solid; border-color: #dadada;"><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;">Gets a property</span></span></span></td>
</tr>
<tr>
<td style="border-style: solid; border-color: #dadada;"><strong><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;"><strong><span style="font-family: courier new,courier;">DISPATCH_PROPERTYPUT</span></strong></span></span></strong></td>
<td style="border-style: solid; border-color: #dadada;"><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;">Sets a property</span></span></span></td>
</tr>
<tr>
<td style="border-style: solid; border-color: #dadada;"><strong><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;"><strong><span style="font-family: courier new,courier;"><strong><span style="font-family: courier new,courier;">DISPATCH_PROPERTYPUTREF</span></strong></span></strong></span></span></strong></td>
<td style="border-style: solid; border-color: #dadada;"><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;">Sets a property by a reference assignment rather than a value assignment</span></span></span></span></td>
</tr>
</tbody>
</table>
<div class="tablediv"><br /><br /><br /><br /><br /><br /><br /><br />&nbsp;</div>
</li>
<li><span style="font-family: courier new,courier;"><strong><em>pDispParams</em></strong> is a pointer to a <strong>DISPPARAMS</strong> structure; a <strong>DISPPARAMS</strong> is a single "package" that represents all of the parameters to pass to the method or property you're invoking. Each parameter represented by a <strong>DISPPARAMS</strong> structure is type <strong>VARIANT.</strong> (<strong>VARIANT</strong>s are discussed in greater detail later in this section).</span></li>
<li><span style="font-family: courier new,courier;"><strong><em>pVarResult</em></strong> is a pointer to another <strong>VARIANT</strong> type and represents the value returned from the invoked property or method.</span></li>
<li><span style="font-family: courier new,courier;"><strong><em>pExcepInfo</em></strong> is a pointer to an <strong>EXCEPINFO</strong> structure that contains exception information.</span></li>
<li><span style="font-family: courier new,courier;"><strong><em>puArgErr</em></strong> also contains error information. If an error occurs due to one of the parameters you passed to the invoked method or property, <em>puArgErr</em> identifies the offending parameter.</span></li>
</ul>
<p><span style="font-family: courier new,courier;">The simplest use of <strong>IDispatch::Invoke</strong> is to call a method that has no parameters and does not return a value. Now, once again consider the <strong>IDispatch</strong> interface in terms of your Automation client for Microsoft Word. As you might recall, the <strong>TypeParagraph</strong> method of the <strong>Selection</strong> object is one such method that had no return value and no arguments. Given the <strong>IDispatch</strong> pointer to the <strong>Selection</strong> object, you could invoke the <strong>TypeParagraph</strong> method with the following code:</span></p>
<table style="width: 560px; margin-right: auto; margin-left: auto;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #dedede;">
<p><span style="color: #000000;"><strong><span style="font-family: courier new,courier;"><span style="color: #339966;">// pDispSel represents a pointer to the IDispatch interface of the</span><br /><span style="color: #339966;">// Selection object.</span><br /><br /></span></strong><span style="font-family: courier new,courier;">DISIPD dispid;</span><span style="font-family: courier new,courier;"><br /><strong>DISPPARAMS</strong> dispparamsNoArgs = {NULL, NULL, 0, 0};<br />HRESULT hr;<br />OLECHAR FAR* szFunction;<br />szFunction = OLESTR("TypeParagraph");<br /><br />hr = pDispSel-&gt;GetIDsOfNames (IID_NULL, &amp;szFunction, 1, <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCALE_USER_DEFAULT, &amp;dispid);<br /><br />hr = pDispSel-&gt;Invoke (dispid, IID_NULL, LOCALE_USER_DEFAULT,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DISPATCH_METHOD, &amp;dispparamsNoArgs, NULL, NULL, <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL);</span></span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;<span style="font-family: courier new,courier;">[...]</span></p>
</td>
<td style="border-style: solid; border-color: #dadada;">&nbsp;</td>
</tr>
</tbody>
</table>
<div class="tablediv">&nbsp;</div>
<p><br /><strong>How are those internal COM mechanisms affecting your COM visible DLL?</strong><br /><br />As I wrote, you most probably won't actually need to call&nbsp;low-level&nbsp;<strong>IDispatch</strong>&nbsp;methods from your code just to execute&nbsp;a simple COM call ..&nbsp;if you are&nbsp;accessing&nbsp;COM objects from VBA, the compiler hides&nbsp;those things form you.&nbsp;&nbsp;</p>
<p>But even if high-level programming languages hide those complex details away, you must be aware of what could happen if you allow client programs to cache your COM DLL's interface.<br /><br />There are two ways in which you can import a COM DLL in Visual Basic..</p>
<p style="padding-left: 30px;"><strong>Early binding:<br />&nbsp; </strong>&gt; go to <strong>Tools</strong> &gt; <strong>References</strong> &gt;&nbsp;locate the COM DLL &gt; click <strong>OK</strong> to import it in your VBA project;<br />&nbsp; &gt; inside your code, create an object instance like this: <span style="font-family: courier new,courier; background-color: #cacaca;"><strong>Dim objCOM As New COM_Obj_ProgID</strong><span style="font-family: arial,helvetica,sans-serif; background-color: #ffffff;">;</span></span><br />&nbsp;&nbsp;&gt; from this point onwards, the <strong>VBIDE</strong> will discover the list of available methods and properties for<br />&nbsp;&nbsp;&nbsp;&nbsp; your&nbsp;newly created COM object&nbsp;class instance and you will receive InteliSense suggestions about<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;the&nbsp;name and list&nbsp;of accepted parameters,&nbsp;when you will try to call any method;<br /><br />&nbsp; &gt;&nbsp;when using early binding,&nbsp;VBIDE&nbsp;reads and caches&nbsp;your DLL's vtable, containing all function pointers;<br />&nbsp; &gt; if at any point you&nbsp;try to call a method, the VBIDE doesn't call IDispatch to check if the method&nbsp;exists, <br />&nbsp;&nbsp;&nbsp;&nbsp; it just&nbsp;calls the corresponding function pointer;<br /><br />&nbsp; &gt; <span style="background-color: #ccffcc;">this is OK from the client's point of view, because the performance is optimized, and you get&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; design-time&nbsp;InteliSense suggestions from the IDE</span>;<br />&nbsp; &gt;&nbsp;<span><span style="background-color: #ffcc99;">but if you later&nbsp;decide&nbsp;that some functions need to be removed or replaced&nbsp;and you roll out the new</span> <br /></span>&nbsp;&nbsp;&nbsp; <span><span style="background-color: #ffcc99;">&nbsp;COM DLL version to&nbsp;all end-users,&nbsp;every VBA project&nbsp;referencing the&nbsp;previous version might throw <br />&nbsp;&nbsp;&nbsp;&nbsp; a&nbsp;</span><span style="background-color: #ffcc99;">runtime error, because the <strong>DISPID</strong> table of pointers&nbsp;exposed by&nbsp;the new DLL&nbsp;is going to be <br />&nbsp;&nbsp;&nbsp;&nbsp; different</span></span><span style="background-color: #ffcc99;">;</span>&nbsp;<br />&nbsp;<br /><strong>Late binding:</strong><br />&nbsp; &gt; you don't need to import any reference;<br />&nbsp; &gt; just instantiate the object like this: <span style="background-color: #cacaca;"><strong><span style="font-family: courier new,courier;">Dim objCOM As Object</span></strong></span>;<br />&nbsp; &gt; then you can create a new class instance using: <br />&nbsp;&nbsp;&nbsp;&nbsp; <span style="background-color: #cacaca;"><strong><span style="font-family: courier new,courier;">Set objCOM =&nbsp;CreateObject("&lt;COM PROGID&gt;")</span></strong></span>;<br />&nbsp; &gt; finally, you will be able to access all&nbsp;COM visible methods by calling them as usual;<br /><br />&nbsp; &gt; because VBA has no way of knowing (until run-time) if the method you tried to&nbsp;execute is correctly <br />&nbsp;&nbsp;&nbsp;&nbsp; accessed (such as the proper method name, the correct number of parameters, the expected data <br />&nbsp;&nbsp;&nbsp;&nbsp; type), you can write&nbsp;any combination of method name and input parameters you want;<br />&nbsp; &gt; if you got it wrong,&nbsp;VBIDE will trigger a run-time error&nbsp;when the <strong>IDispatch</strong> interface returns an <br />&nbsp;&nbsp;&nbsp;&nbsp; error&nbsp;code&nbsp;because the VBA compiler will first try to discover if the&nbsp;methods you are&nbsp;attempting <br />&nbsp;&nbsp;&nbsp;&nbsp; to&nbsp;access are really available;&nbsp;&nbsp;<br /><br />&nbsp; &gt; <span style="background-color: #ccffcc;">however, this late binding mechanism has a big advantage; If the creator of the COM DLL decides to </span><br /><span style="background-color: #ccffcc;">&nbsp;&nbsp;&nbsp;&nbsp; release a new version, with a different function interface layout, any VBA code calling those methods </span><br /><span style="background-color: #ccffcc;">&nbsp;&nbsp;&nbsp;&nbsp; won't crash unless the methods are no longer available;</span> <br />&nbsp; &gt; <span style="background-color: #ffcc99;">if they are still having their old names and the same input parameters, even if the virtual pointer table <br />&nbsp;&nbsp;&nbsp;&nbsp; is&nbsp;different, VBA will&nbsp;discover the new <strong>DISPIDs</strong> and will call their appropriate methods;</span></p>
<p><strong>&nbsp;<br /></strong><strong><br /></strong>Here is what the cited article says about binding:</p>
<table style="border-width: 1px 1px 0px; border-color: #000000; width: 590px; background-color: #ededed;" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1px solid #000000;">
<p><span style="font-family: courier new,courier; font-size: x-small;"><a title="https://msdn.microsoft.com/en-us/library/aa155776(v=office.10).aspx" href="https://msdn.microsoft.com/en-us/library/aa155776(v=office.10).aspx" target="_blank">https://msdn.microsoft.com/en-us/library/aa155776(v=office.10).aspx</a><br /><br /><strong></strong> <span style="font-family: arial,helvetica,sans-serif; font-size: small;"><strong>Automating Microsoft Office 97 and Microsoft Office 2000<br /></strong></span></span><span style="font-family: courier new,courier; font-size: small;">-------------------------------------------------------------------------</span></p>
<p><span style="font-family: courier new,courier;">[...]</span>&nbsp;</p>
<p><strong><span style="font-family: courier new,courier; font-size: small;">Creating an Automation Client with Visual Basic<br /></span></strong><span style="font-family: courier new,courier;">..</span></p>
<p><strong><span style="font-family: courier new,courier; font-size: small;"><br />Binding<br /></span></strong></p>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;"><strong>Binding</strong> describes how an <strong>Automation client</strong> internally invokes a given method or property.</span> There are two types of binding: <strong><em>early binding</em></strong> and <strong><em>late binding</em></strong>. With Visual Basic, the type of binding you choose is determined solely by the manner in which you declare your variables.</span><br /><span style="font-family: courier new,courier;"><br /><br /></span><strong><span style="color: #ffffff; font-family: courier new,courier; background-color: #3366ff;">Early binding</span></strong><br /><span style="font-family: courier new,courier;"><br />With <strong>early binding</strong>, your project maintains a reference to the <strong>Automation server</strong>'s <strong>type library</strong> and you declare your variables as types defined by that <strong>type library</strong>. For example, if your project had a reference to the <strong>Microsoft Word type library</strong>, you could declare an object variable as shown:</span></p>
<table style="width: 564px; height: auto; margin-right: auto; margin-left: auto;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #dedede;">
<p>&nbsp;<span style="font-family: courier new,courier;">Dim oWordApp as Word.Application&nbsp;</span>&nbsp;</p>
</td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier;">Because information from the server's type library is available at compile time, Visual Basic does not need to "look up" the property or method at run time. If the object exposes its function in its <strong>vtable</strong>, <span style="background-color: #ffcc99;">Visual Basic uses <em><strong>vtable</strong> <strong>binding</strong></em> and calls the function through the <strong>vtable</strong>.</span> <span style="background-color: #ffff99;">If the object does not support <strong>vtable</strong> <strong>binding</strong>, Visual Basic invokes the function using the <strong>DispId</strong> it obtained from the type library. In other words, it uses <em><strong>DispID</strong> binding</em></span>.<br /><br /></span><br /><strong><span style="color: #ffffff; background-color: #3366ff;"><span style="font-family: courier new,courier; font-size: small;">Late binding</span></span></strong>&nbsp;</p>
<p><span style="font-family: courier new,courier;">With <strong>late binding</strong> in Visual Basic, your project does not need a reference to the Automation server's type library and you can declare your variables as type <strong>Object</strong>.</span></p>
<table style="width: 564px; height: auto; margin-right: auto; margin-left: auto;" border="1">
<tbody>
<tr>
<td style="border: 1px solid #dedede;">
<p>&nbsp;<span style="font-family: courier new,courier;">Dim oWordApp as Object&nbsp;</span>&nbsp;</p>
</td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier;">When you declare a variable as type <strong>Object</strong>,<span style="background-color: #ffcc99;"> Visual Basic cannot determine at compile time what sort of object reference the variable contains, so binding occurs at run time</span>. When you call a property or method of an object with late binding, the process by which Visual Basic makes the call, is twofold:</span>&nbsp;</p>
<ul>
<li><span style="font-family: courier new,courier;">Using an interface pointer to the object, Visual Basic calls <strong>GetIDsOfNames</strong>to "look up" the name of that property or method to retrieve its <strong>DispID</strong>.<br /></span><span style="font-family: courier new,courier;">-and-</span></li>
<li><span style="font-family: courier new,courier;">Visual Basic calls <strong>Invoke</strong> to execute the property or method using the <strong>DispID</strong>.</span></li>
</ul>
<p>&nbsp;</p>
<p class="dtH1"><span style="font-size: small;"><strong><span style="font-family: courier new,courier;">Choosing the correct type of binding for your automation client<br /></span></strong></span>&nbsp;&nbsp;</p>
<p><span style="font-family: courier new,courier;">There are advantages to both types of binding. You should weigh the benefits of each before deciding which type of binding to choose for your Automation client.</span></p>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;">Early binding provides you with increased performance and compile-time syntax checking</span>. In addition, you receive direct access to the server's <strong>type library</strong> in the Visual Basic design environment and to the Help for the object model.</span>&nbsp;</p>
<p><span style="font-family: courier new,courier;">Despite the benefits of early binding, <span style="background-color: #ffcc99;">late binding is most advantageous when you are writing Automation clients that you intend to be compatible with future versions of your Automation server</span>. <span style="background-color: #ffff99;">With late binding, information from the server's type library is not "hard-wired" into your client, so you can have greater confidence that your Automation client can work with future versions of the Automation server without code changes</span>.</span></p>
<p><span style="font-family: courier new,courier;"><br />For more information about binding in Visual Basic, please see the following article in the Microsoft Knowledge Base:</span>&nbsp;</p>
<p><span style="font-family: courier new,courier;"><a href="https://support.microsoft.com/support/kb/articles/q245/1/15.asp">Q245115 INFO: Using Early Binding and Late Binding in Automation</a></span></p>
<p><span style="font-family: courier new,courier;">[...]</span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>In part two of this article I am going to&nbsp;demonstrate&nbsp;how we can create&nbsp;COM DLLs which allow for <strong>Late</strong> or <strong>Early&nbsp;Binding</strong>. <br /><br />I will also show you the&nbsp;how&nbsp;Automation clients fail when they encounter a DLL with an unexpected <strong>vtable</strong> interface layout&nbsp;and what can be done to ensure that different versions of the same COM DLLs with the same PROGID can run side by side.&nbsp;<br /><br /><br /><span style="font-family: courier new,courier;"><strong><span style="background-color: #ffffff;">Thank you for reading my article! Bye :-)</span></strong></span><!--EndFragment--></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>VSTO - How to build a setup project which targets x64 bit OS, and add custom Registry Launch Condition that checks if a key is found in the native 64bit  registry hive.</title>
      <link>https://docs.microsoft.com/archive/blogs/cristib/vsto-how-to-build-a-setup-project-which-targets-x64-bit-os-and-add-custom-registry-launch-condition-that-checks-if-a-key-is-found-in-the-native-64bit-registry-hive</link>
      <pubDate>Fri, 28 Sep 2012 03:32:00 GMT</pubDate>
      <dc:creator><![CDATA[Cristian.Berescu]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cristib/2012/09/28/vsto-how-to-build-a-setup-project-which-targets-x64-bit-os-and-add-custom-registry-launch-condition-that-checks-if-a-key-is-found-in-the-native-64bit-registry-hive/</guid>
      <description><![CDATA[A&nbsp;developer that needs to learn&nbsp;all about building and deploying a VSTO&nbsp;2010...]]></description>
      <content:encoded><![CDATA[<p>A&nbsp;developer that needs to learn&nbsp;all about building and<span style="font-family: arial,helvetica,sans-serif;"> deploying</span> a VSTO&nbsp;2010 installer project,&nbsp;should carefully review this&nbsp;very nice article: <a href="https://msdn.microsoft.com/en-us/library/ff937654.aspx" target="_blank">https://msdn.microsoft.com/en-us/library/ff937654.aspx</a>&nbsp;(Deploying a Visual Studio 2010 Tools for Office Solution Using Windows Installer).</p>
<p>Starting from the 2010 version, Office applications come in two flavors:<strong> x32</strong> bit and<strong> x64</strong> bit. <br /><br />If you&nbsp;need to take advantage of the x64 bit architecture in your add-in,&nbsp;you also have to ensure that it gets&nbsp;properly built and installed. For x64 bit native components, the&nbsp;known VSTO add-in registry keys (<strong><span style="font-family: courier new,courier;"><span class="parameter">Root</span>\Software\Microsoft\Office\<span class="parameter">application name</span>\Addins\<span class="parameter">add-inID</span></span>&nbsp;</strong><a href="https://msdn.microsoft.com/en-us/library/bb386106.aspx" target="_blank">https://msdn.microsoft.com/en-us/library/bb386106.aspx</a>)&nbsp;will have to&nbsp;be written in the default place, but for 32 bit solutions, they get deployed to <span style="font-size: small;"><strong><span style="font-family: courier new,courier;">Wow6432Node</span></strong><span style="font-family: arial,helvetica,sans-serif;">(</span><strong><span style="font-family: courier new,courier;"><strong><span style="font-family: courier new,courier;"><span class="parameter">Root</span>\Software\<span style="font-size: small;"><strong><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;">Wow6432Node</span>\</span></strong></span>Microsoft\Office\<span class="parameter">application name</span>\Addins\<span class="parameter">add-inID</span></span></strong></span></strong><span style="font-family: arial,helvetica,sans-serif;">)</span></span>.</p>
<table style="background-color: #dedede; width: 560px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td><span style="font-family: courier new,courier; font-size: small;"><strong>32-bit and 64-bit Application Data in the Registry</strong><br /><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms724072(v=vs.85).aspx" target="_parent">https://msdn.microsoft.com/en-us/library/windows/desktop/ms724072(v=vs.85).aspx</a><br />=======================================================================<br /></span>
<p><span style="font-family: courier new,courier;">On 64-bit Windows, portions of the registry entries are stored separately for 32-bit application and 64-bit applications and mapped into separate logical registry views using the <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384232(v=vs.85).aspx">registry redirector</a> and <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384235(v=vs.85).aspx">registry reflection</a>, because the 64-bit version of an application may use different registry keys and values than the 32-bit version. There are also <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384253(v=vs.85).aspx">shared registry keys</a> that are not redirected or reflected.</span></p>
<p><span style="font-family: courier new,courier;">The parent of each 64-bit registry node is the <strong>Image-Specific Node</strong> or <strong>ISN</strong>. The registry redirector transparently directs an application's registry access to the appropriate <strong>ISN</strong> subnode. Redirection subnodes in the registry tree are created automatically by the WOW64 component using the name <span style="background-color: #c0c0c0;"><strong>Wow6432Node</strong></span>. As a result, it is essential not to name any registry key you create <span style="background-color: #c0c0c0;"><strong>Wow6432Node</strong></span>.</span></p>
<p><span style="font-family: courier new,courier;">The KEY_WOW64_64KEY and KEY_WOW64_32KEY flags enable explicit access to the 64-bit registry view and the 32-bit view, respectively. For more information, see <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384129(v=vs.85).aspx">Accessing an Alternate Registry View</a>.</span></p>
<p><span style="font-family: courier new,courier;">To disable and enable registry reflection for a particular key, use the <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms724858(v=vs.85).aspx"><strong>RegDisableReflectionKey</strong></a> and <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms724859(v=vs.85).aspx"><strong>RegEnableReflectionKey</strong></a> functions. Applications should disable reflection only for the registry keys that they create and not attempt to disable reflection for the predefined keys such as <strong>HKEY_LOCAL_MACHINE</strong> or <strong>HKEY_CURRENT_USER</strong>. To determine which keys are on the reflection list, use the <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms724907(v=vs.85).aspx"><strong>RegQueryReflectionKey</strong></a> function.</span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table style="background-color: #dedede; width: 560px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td>
<p><span style="font-family: courier new,courier; font-size: small;"><strong>Registry Redirector</strong></span><br /><span style="font-family: courier new,courier; font-size: small;"><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384232(v=vs.85).aspx">https://msdn.microsoft.com/en-us/library/windows/desktop/aa384232(v=vs.85).aspx</a></span><br /><span style="font-family: courier new,courier; font-size: small;">=======================================================================</span></p>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;">The registry redirector isolates 32-bit and 64-bit applications by providing separate logical views of certain portions of the registry on WOW64</span>. <span style="background-color: #ffff99;">The registry redirector intercepts 32-bit and 64-bit registry calls to their respective logical registry views and maps them to the corresponding physical registry location</span>. The redirection process is transparent to the application. <span style="background-color: #ccffcc;">Therefore, a 32-bit application can access registry data as if it were running on 32-bit Windows even if the data is stored in a different location on 64-bit Windows</span>.</span></p>
<p><span style="font-family: courier new,courier;">A subset of keys under redirected registry paths are shared. 32-bit registry calls to shared keys are not redirected. Instead, one physical copy of the key is mapped into each logical view of the registry. For a list of redirected keys and shared keys, see <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384253(v=vs.85).aspx">Registry Keys Affected by WOW64</a>.</span></p>
<blockquote>
<div><span style="font-family: courier new,courier;"><strong>Windows Server&nbsp;2008, Windows&nbsp;Vista, Windows Server&nbsp;2003, and Windows&nbsp;XP:&nbsp;&nbsp;</strong>To enable application interoperability through COM and other mechanisms, a subset of redirected registry keys are also reflected. The process of registry reflection copies registry keys and values between two registry views to keep them synchronized. Registry reflection was removed starting with Windows 7 and Windows Server 2008 R2. For more information, see <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384235(v=vs.85).aspx">Registry Reflection</a>.</span></div>
</blockquote>
<p><span style="font-family: courier new,courier;">&nbsp;The following scenario illustrates the use of these logical views:</span></p>
<ul>
<li><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;">A 32-bit application checks for the existence of the following registry key</span>: <strong>HKEY_LOCAL_MACHINE\Software\Hello</strong>. If the key does not exist, the application creates it with a default value of "Hello 32-bit world"; otherwise, it reads and displays the value.</span></li>
<li><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;">The same application is modified to write "Hello 64-bit world" instead of "Hello 32-bit world" and recompiled as a 64-bit application</span>.</span></li>
<li><span style="font-family: courier new,courier;"><span style="background-color: #ccffcc;">When the 32-bit application is run on 64-bit Windows, it displays "Hello 32-bit world".</span> <span style="background-color: #ffff99;">When the 64-bit application is run, it displays "Hello 64-bit world".</span> Both applications call the same registry functions with the same predefined handle and the same key name; <span style="background-color: #ffff00;">the difference is that each application operates on its logical view of registry</span>, and each view is mapped to a separate physical location of the registry, which keeps both versions of the string intact.</span></li>
</ul>
<p><span style="font-family: courier new,courier;"><span style="background-color: #ffff00;">Redirected keys are mapped to physical locations under <strong>Wow6432Node</strong></span>. For example, <strong>HKEY_LOCAL_MACHINE\Software</strong> is redirected to <strong>HKEY_LOCAL_MACHINE\Software\Wow6432Node</strong>. However, the physical location of redirected keys should be considered reserved by the system. Applications should not access a key's physical location directly, because this location may change. For more information, see <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384129(v=vs.85).aspx">Accessing an Alternate Registry View</a>.</span></p>
<p><span style="font-family: courier new,courier;">To help 32-bit applications that write <strong>REG_SZ</strong> or <strong>REG_EXPAND_SZ</strong> data containing %ProgramFiles% or %commonprogramfiles% to the registry, WOW64 intercepts these write operations and replaces them with "%ProgramFiles(x86)%" and "%commonprogramfiles(x86)%". For example, if the Program Files directory is on the C drive, then "%ProgramFiles(x86)%" expands to "C:\Program Files (x86)".</span><br /><br /><span style="font-family: courier new,courier;">[...]</span></p>
</td>
</tr>
</tbody>
</table>
<p><br />As the article says, if we compile our MSI&nbsp;installer project&nbsp;to&nbsp;explicitly&nbsp;target the&nbsp;x64 bit architecture, then the <strong>Registry redirector</strong> feature will ensure that it finds the right logical view of the registry.</p>
<p>The <a href="https://msdn.microsoft.com/en-us/library/ff937654.aspx">https://msdn.microsoft.com/en-us/library/ff937654.aspx</a>&nbsp;article tells us that all we have to do is change the <strong>TargetPlatform</strong> for our MSI installer project to <strong>x64 </strong>and then we can deploy&nbsp;our&nbsp;64-bit add-in to a 64-bit OS<strong>. </strong></p>
<table style="border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6866.1.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6866.1.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6866.1.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6866.1.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>There is another step linked to&nbsp;the previous&nbsp;one .. at a later stage, we will need to introduce some <strong>Launch Conditions</strong> and check&nbsp;whether&nbsp;some&nbsp;keys are found in Registry. Depending on the result, we will continue with our installation,&nbsp;or&nbsp;we abort the operation.&nbsp;</p>
<p>The <a href="https://msdn.microsoft.com/en-us/library/ff937654.aspx">https://msdn.microsoft.com/en-us/library/ff937654.aspx</a> example&nbsp;show us how we build a simple <strong>Launch Condition&nbsp;</strong>to&nbsp;test if a 32-bit key exists:&nbsp;<br />&nbsp;<br />&nbsp; &gt; <strong>SOFTWARE\Microsoft\VSTO Runtime Setup\v4 </strong>(for x86 OS);<br />&nbsp; &gt; <strong>SOFTWARE\<span style="background-color: #ffff99;">Wow6432Node</span>\Microsoft\VSTO Runtime Setup\v4 </strong>(for x64 OS);<br /><br /><strong><br /></strong><strong></strong></p>
<p><strong></strong><span style="font-size: small;">Since the article doesn't contain&nbsp;an explicit warning about scenarios when we explicitly target an x64 bit registry key with our <strong>Launch Condition</strong>, one&nbsp;would assume that we only&nbsp;need to&nbsp;input the correct registry path and things will work out as expected.&nbsp;<span style="color: #ff0000;"><strong>Unfortunately,&nbsp;everything will not&nbsp;run as smooth as&nbsp;we'd like ... due to some MSI installer&nbsp;issue in Visual Studio 2010, you will never&nbsp;be able to target the x64bit registry location</strong></span>. Every time, your search will be redirected to the x32 bit hive.<br /></span></p>
<p><span style="font-size: small;">A quick internet search reveals that other people have noticed this fact:<br />&nbsp;&gt; "Launch condition issue while running on Windows server 2008 (64 bit)" <br />&nbsp;&nbsp;&nbsp; (<a href="https://social.msdn.microsoft.com/forums/en-us/winformssetup/thread/1DF0D4D6-3D84-4D81-ABF4-100F457FAE5A" target="_blank">https://social.msdn.microsoft.com/forums/en-us/winformssetup/thread/1DF0D4D6-3D84-4D81-ABF4-100F457FAE5A</a>);<br /></span><span style="font-size: small;">&nbsp;&gt; "What Is need to support 64-bit 'msi' files" <br />&nbsp;&nbsp;&nbsp; (<a href="https://social.msdn.microsoft.com/Forums/en-US/winformssetup/thread/7f87ff71-8871-4047-becb-3381173cb915" target="_blank">https://social.msdn.microsoft.com/Forums/en-US/winformssetup/thread/7f87ff71-8871-4047-becb-3381173cb915</a>);<br /></span></p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;<br /><span style="font-size: small;"><strong>Let's test this, shall we ?</strong></span></p>
<p>I am using a&nbsp;machine with Windows7 x64 + Office 2010 x64 + Visual Studio 2010.<br /><br />Steps to reproduce the issue:</p>
<p><span style="color: #ff0000;"><strong>1.</strong></span>&nbsp;&nbsp; Create a new <strong>Windows Forms Application</strong> project (we won't use a VSTO&nbsp;add-in project because the issue can&nbsp;be reproduced with any type of solution, as long as we build a MSI deployment&nbsp;project for it);<br /><span style="color: #ff0000;"><strong>2.</strong></span>&nbsp;&nbsp; After <strong>Visual Studio</strong> generates the project's structure, go to the '<strong>Solution Explorer</strong>' window, right click on the solution and choose '<strong>Add</strong>'&nbsp; &gt; '<strong>New Project</strong>';<br /><span style="color: #ff0000;"><strong>3.</strong></span>&nbsp;&nbsp; In the '<strong>Add New Project</strong>' window, browse to '<strong>Other Project Types</strong>' &gt; '<strong>Visual Studio Installer</strong>' &gt; select '<strong>Setup Project</strong>' in the right-hand panel;<br /><span style="color: #ff0000;"><strong>4.</strong></span>&nbsp;&nbsp; Once the new project is added to your solution, click with the left-mouse button to select it in the '<strong>Solution Explorer</strong>' window; This should populate the '<strong>Properties</strong>' window with the items specific to a setup project;<br /><br />&nbsp;<span style="background-color: #c0c0c0;">&nbsp; If the <strong>Properties</strong> window is not visible, go to '<strong>View</strong>' &gt; '<strong>Properties Window (F4)</strong>';<br /><br /></span><span style="color: #ff0000;"><strong>5.</strong></span>&nbsp;&nbsp; Locate the '<strong>Target Platform</strong>' property item and select '<strong>x64</strong>' from the drop-down menu;</p>
<table style="width: 560px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2311.2.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2311.2.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2311.2.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2311.2.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><span style="color: #ff0000;"><strong>6. </strong></span>&nbsp; Right-click the solution in&nbsp; '<strong>Solution Explorer</strong>' window, select '<strong>Configuration Manager</strong>';<br /><span style="color: #ff0000;"><strong>7.</strong></span>&nbsp;&nbsp; In the '<strong>Configuration Manager</strong>' window, only the default '<strong>x86</strong>' value should be available for the '<strong>Active Solution Platform</strong>'; Click on this drop-down, and select '<strong>New</strong>'; A new solution setup window appears:<br />&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&gt; select '<strong>x64</strong>' from '<strong>Type or select the new platform</strong>' drop-down;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; select '<strong>&lt;Empty&gt;</strong>' in '<strong>Copy settings from</strong>' drop-down;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; click <strong>OK</strong>;</p>
<table style="width: 560px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2063.3.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2063.3.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2063.3.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2063.3.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><span style="color: #ff0000;"><strong>8.</strong></span>&nbsp;&nbsp; When you return to the '<strong>Configuration Manager</strong>' panel, you should see that the '<strong>Platform</strong>' project configuration setting for your Windows Forms project&nbsp; is set to the newly added item: <strong>'x64</strong>'; (if it is still pointing to x86, change it to x64);<br /><span style="color: #ff0000;"><strong>9.</strong></span>&nbsp;&nbsp; Notice the '<strong>Build</strong>' project configuration check-box setting: if it is only checked for the Windows Forms solution, mark the other project's check-box as enabled, so that you also generate a setup MSI output file when you trigger the '<strong>Build</strong>' action; <br /><span style="color: #ff0000;"><strong>10.</strong></span>&nbsp;&nbsp; Close '<strong>Configuration Manager</strong>' window;<br /><span style="color: #ff0000;"><strong>11. </strong></span>&nbsp; In '<strong>Solution Explorer</strong>', right-click on the setup project, choose '<strong>Add</strong>' &gt; '<strong>Project Output..</strong>' &gt; select '<strong>Primary Output</strong>' and choose the name of your Windows Forms solution from the '<strong>Project</strong>' drop-down menu, then click <strong>OK</strong>;<br /><span style="color: #ff0000;"><strong>12.</strong></span>&nbsp;&nbsp; In '<strong>Solution Explorer</strong>', right-click again on the setup project, select '<strong>View</strong>' &gt; '<strong>Launch Conditions</strong>';<br /><span style="color: #ff0000;"><strong>13.</strong></span>&nbsp;&nbsp; The '<strong>Launch Conditions</strong>' window appears; Right click on the root node '<strong>Requirements on Target Machine</strong>' &gt; select '<strong>Add Registry Launch Condition</strong>'; <br /><span style="color: #ff0000;"><strong>14.</strong></span>&nbsp;&nbsp; Notice that 2 new items appear: <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; the '<strong>Search Target Machine</strong>' node contains a child item named '<strong>Search for RegistryEntry1</strong>';<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; the '<strong>Launch Conditions</strong>' node contains a child item named '<strong>Condition1</strong>';</p>
<table style="width: 560px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6765.4.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6765.4.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6765.4.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6765.4.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><span style="color: #ff0000;"><strong>For demonstrating the issue, I am going to search if a native x64-bit registry key exists: "SOFTWARE\Microsoft\Office\14.0\Excel" ...&nbsp;<br /><br />15.</strong></span>&nbsp;&nbsp; You need to customize these entries:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&gt; click to select the '<strong>Search for RegistryEntry1</strong>' node to bring its '<strong>Properties</strong>' page into view;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; the '<strong>Property</strong>' field should have the value "<span style="background-color: #ccffff;"><strong>REGISTRYVALUE1</strong></span>";<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; the '<strong>RegKey</strong>' has to receive the value "<strong>SOFTWARE\Microsoft\Office\14.0\Excel</strong>" <span style="background-color: #ffff99;">&gt;&gt;</span><span style="color: #ffff99;"><span style="background-color: #ffff99;">&nbsp;</span><span style="background-color: #ffff99; color: #000000;">don't include the&nbsp;quotes&nbsp;</span></span>(for this test we are trying to verify if Excel key can be accessed in <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x64bit environments;&nbsp;You may use any other registry location);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; the '<strong>Root</strong>' has to receive the value "<strong>vsdrrHKLM</strong>";<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; the '<strong>Value</strong>' field remains empty (<span style="background-color: #ffff99;">here things get more complicated ..&nbsp;it seems that the way Windows Installer's&nbsp;<strong>'Value Property</strong>'&nbsp;works is&nbsp;a little bit non-intuitive. For more details, see the clarifications from below, otherwise skip to step #<strong>16</strong>)</span>;</p>
<table style="width: 560px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td>The help page for the '<strong>Value Property</strong>' of&nbsp;Windows Installer&nbsp;says:<br /><br />
<table style="background-color: #f5f5f5; width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p class="title"><strong><span style="font-family: courier new,courier; font-size: small;">Value Property (Windows Installer)</span></strong><span style="font-family: courier new,courier; font-size: small;"><br /><a href="https://msdn.microsoft.com/en-us/library/89afw1yy(v=vs.100).aspx" target="_blank">https://msdn.microsoft.com/en-us/library/89afw1yy(v=vs.100).aspx</a><br /><span style="font-family: courier new,courier; font-size: small;">===================================================================</span><br /><br />Specifies a registry value to search for on the target computer. If an exact match for the value specified in the Value property is not found, the registry search will return null.</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">Note </span><br /><span style="background-color: #ffffff; font-family: courier new,courier; font-size: small;">If the Value property is left blank, the registry search will <span style="background-color: #ffff99;">search for the default value of the key</span> specified in the RegKey property. </span><br /><span style="background-color: #ffffff;"><span style="font-family: courier new,courier; font-size: small;">If the default value is null (appears as "Value not set" in the Windows Registry Editor), the registry search will <span style="background-color: #ffff99;">return null</span>. Additionally, if a key has no values assigned, the search will <span style="background-color: #ffff99;">return null</span> even if the Value property is blank.</span><span style="font-family: courier new,courier; font-size: small;">&nbsp;</span></span><br /><span style="font-family: courier new,courier; font-size: small;">Settings</span><br /><span style="font-family: courier new,courier; font-size: small;">------------------------------------------------------------------</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;The Value property takes a string that matches the value as displayed in the Data column of the Windows Registry Editor.</span></p>
</td>
</tr>
</tbody>
</table>
<p>.. also this how-to article makes it clear that we cannot search if a key exists unless it holds some non-empty value:</p>
<table style="background-color: #f5f5f5; width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><strong><span style="font-family: courier new,courier; font-size: small;">How to: Add a Registry Launch Condition&nbsp;</span></strong> <br /><span style="font-family: courier new,courier;"><a href="https://msdn.microsoft.com/en-us/library/4awx1f1d(v=VS.80).aspx" target="_blank">https://msdn.microsoft.com/en-us/library/4awx1f1d(v=VS.80).aspx</a></span><br /><span style="font-family: courier new,courier; font-size: small;">===================================================================</span><br /><br /><strong><span style="font-family: courier new,courier; font-size: small;">To add a registry launch condition</span></strong>
<div class="subSection"><ol>
<li>
<p><span style="font-family: courier new,courier; font-size: small;">In the <strong>Launch Conditions Editor</strong>, select the <strong>Requirements on Target Machine</strong> node.</span></p>
</li>
<li>
<p><span style="font-family: courier new,courier; font-size: small;">On the <strong>Action</strong> menu, choose <strong>Add Registry Launch Condition</strong>.</span></p>
</li>
<li>
<p><span style="font-family: courier new,courier; font-size: small;">Select the <strong>Search for RegistryEntry</strong> node. In the <strong>Properties</strong> window, select the <strong>Root</strong> property and select the registry root to be searched.</span></p>
</li>
<li>
<p><span style="font-family: courier new,courier; font-size: small;">Select the <strong>RegKey</strong> property and type the name of the registry key to search for. This should include the full path to the registry key, excluding the root.</span></p>
<div class="alert">
<table style="width: 100%;">
<tbody>
<tr><th align="left"><span style="font-family: courier new,courier; font-size: small;"><img class="note cl_IC103139" src="https://i.msdn.microsoft.com/areas/global/content/clear.gif" alt="Note" />Note</span></th></tr>
<tr>
<td>
<p><span style="background-color: #ffff00; font-family: courier new,courier; font-size: small;">A registry search cannot verify that a registry key exists unless the registry key contains a non-null value.<br /><br /></span></p>
</td>
</tr>
</tbody>
</table>
</div>
</li>
<li>
<p><span style="font-family: courier new,courier; font-size: small;">Optionally, set the <strong>Value</strong> property to search for a specific value in the registry key.</span></p>
<div class="alert">
<table style="width: 100%; height: 79px;">
<tbody>
<tr><th align="left"><span style="font-family: courier new,courier; font-size: small;"><img class="note cl_IC103139" src="https://i.msdn.microsoft.com/areas/global/content/clear.gif" alt="Note" />Note</span></th></tr>
<tr>
<td>
<p><span style="background-color: #ffff00; font-family: courier new,courier; font-size: small;">A registry search cannot verify that a value exists unless it contains a non-null value.<br /><br /></span></p>
</td>
</tr>
</tbody>
</table>
</div>
</li>
<li>
<p><span style="font-family: courier new,courier; font-size: small;">Select the <strong>Condition</strong> node. In the <strong>Properties</strong> window, select the <strong>Message</strong> property and type the error message that will be displayed if the registry entry is not found.</span></p>
</li>
</ol></div>
<p>&nbsp;</p>
</td>
</tr>
</tbody>
</table>
<p>As the aforementioned article states, if we leave the '<strong>Value</strong>' field empty, then we have to make sure that the&nbsp;key we are searching for has a non-empty (Default) value; Otherwise the setup project will mark this Launch Condition as failed; So this is why we&nbsp;have to introduce the value '<strong>test</strong>' at step #<strong>19</strong>;</p>
</td>
</tr>
</tbody>
</table>
<p><br /><span style="color: #ff0000;"><strong>16.</strong></span>&nbsp;&nbsp; Next, we will set up what happens in case this key is not found; For this purpose, we select '<strong>Condition1</strong>' to bring its '<strong>Properties page into view</strong>';<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; the '<strong>Condition</strong>' field should have the value "<span style="background-color: #ccffff;"><strong>REGISTRYVALUE1</strong></span>";<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; the '<strong>InstallUrl</strong>' should be empty;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; the '<strong>Message</strong>' should contain "<strong>Required Reg key was not found</strong>" string;<br /><br /></p>
<table style="width: 560px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4075.5.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4075.5.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4075.5.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4075.5.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><span style="color: #ff0000;"><strong>17.</strong></span>&nbsp;&nbsp; Build the <strong>Visual Studio</strong> solution;<br /><span style="color: #ff0000;"><strong>18.</strong></span>&nbsp;&nbsp; Right-click<span style="background-color: #ffff99;"> the setup project</span>, select '<strong>Open Folder in Windows Explorer</strong>', go to '<strong>\..\x64\Debug</strong>' folder and locate the '<strong>setup.exe</strong>' file;<br /><span style="color: #ff0000;"><strong>19.</strong></span>&nbsp;&nbsp; Before running the installer, open the Registry, navigate to "<strong>HKLM\SOFTWARE\Microsoft\Office\14.0\Excel</strong>", double click on the '(Default)' key and write the string "<strong>test</strong>";</p>
<table style="width: 560px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6675.6.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6675.6.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/6675.6.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/6675.6.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><span style="color: #ff0000;"><strong>20</strong>.&nbsp;</span>&nbsp; Run the setup ..<br /><br /><br />Actual result:&nbsp; the installation will fail, and you should get the error message: "<strong>Required Reg key was not found</strong>";</p>
<table style="width: 560px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0728.7.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0728.7.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0728.7.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0728.7.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br />Expected result: the setup should complete, because the Excel registry key exists in the native x64bit node, and we built a x64bit setup project;</p>
<p><br />If we run ProcMon while executing the setup project, we notice that the '<strong>msiexec.exe</strong>' process is actually querying the 32-bit key:</p>
<table style="background-color: #dedede; width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><span style="font-family: courier new,courier; font-size: small;"><br />msiexec.exe&nbsp;&nbsp; </span><br /><span style="font-family: courier new,courier; font-size: small;">RegOpenKey&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><br /><span style="font-family: courier new,courier; font-size: small;">HKLM\SOFTWARE\Wow6432Node\Microsoft\Office\14.0\Excel </span><br /><span style="font-family: courier new,courier; font-size: small;">SUCCESS </span><br /><span style="font-family: courier new,courier; font-size: small;">Desired Access: Read</span><br /><br /><span style="font-family: courier new,courier; font-size: small;">msiexec.exe&nbsp;&nbsp; </span><br /><span style="font-family: courier new,courier; font-size: small;">RegQueryValue&nbsp;&nbsp; </span><br /><span style="font-family: courier new,courier; font-size: small;">HKLM\SOFTWARE\Wow6432Node\Microsoft\Office\14.0\Excel\(Default) </span><br /><span style="font-family: courier new,courier; font-size: small;">NAME NOT FOUND </span><br /><span style="font-family: courier new,courier; font-size: small;">Length: 144</span><br /><br /><span style="font-family: courier new,courier; font-size: small;">msiexec.exe&nbsp;&nbsp;</span><br /><span style="font-family: courier new,courier; font-size: small;">RegCloseKey&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><br /><span style="font-family: courier new,courier; font-size: small;">HKLM\SOFTWARE\Wow6432Node\Microsoft\Office\14.0\Excel </span><br /><span style="font-family: courier new,courier; font-size: small;">SUCCESS</span></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table style="width: 560px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7801.8.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7801.8.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7801.8.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7801.8.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>.. and&nbsp;if we create this key, then&nbsp;if we add a non-empty string in the '(Default)' node, then the setup completes successfully;</p>
<table style="width: 560px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2477.10.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2477.10.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2477.10.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2477.10.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><strong></strong></p>
<p><strong><span style="font-size: small;">So why do we get this problem?</span></strong><br /><br />We can research:&nbsp;"How to: Create a Windows Installer for a 64-bit Platform" (<a href="https://msdn.microsoft.com/en-us/library/cd7a85k9(v=vs.100).aspx">https://msdn.microsoft.com/en-us/library/cd7a85k9(v=vs.100).aspx</a>) to make sure that we performed the correct steps when trying to build the native 64bit setup project:</p>
<table style="background-color: #dedede; width: 560px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td>
<p><span style="font-family: courier new,courier; font-size: small;"><strong>How to: Create a Windows Installer for a 64-bit Platform</strong></span><br /><span style="font-family: courier new,courier; font-size: small;"><a href="https://msdn.microsoft.com/en-us/library/cd7a85k9(v=vs.100).aspx">https://msdn.microsoft.com/en-us/library/cd7a85k9(v=vs.100).aspx</a><br />=======================================================================</span><span style="font-family: courier new,courier; font-size: small;"><br /><br />The deployment tools in Visual Studio allow you to create installers for 64-bit applications and components. The <strong>TargetPlatform Property</strong> of a deployment project determines whether an installer will target a 32-bit or a specific 64-bit platform. The target platforms are <strong>x86</strong> for 32-bit platforms, <strong>x64</strong> for computers supporting the AMD64 and EM64T instruction sets, and Itanium for the 64-bit Itanium processor.</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">In addition, three special folders are available in the File System editor: for 64-bit applications, <strong>Common Files (64-bit)</strong>, <strong>Program Files (64-bit)</strong>, and <strong>System (64-bit)</strong> are the native folders; <strong>Common Files</strong>, <strong>Program Files</strong>, and <strong>System</strong> are the Windows on Windows folders.</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">In general, 32- and 64-bit Microsoft Installer (MSI) packages are treated in the same way except for how Windows Installer treats folder variables such as [Program Files] and [System Folder], and how it writes components into the registry or GAC. When you create a 32- or 64-bit MSI package, the processor architecture is noted in the .NET Framework assembly's strong name identity when it is installed in the GAC. You can also create setup projects for 64-bit computers from 32-bit computers.</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">64-bit MSI packages can support both 32- and 64-bit DLLs or EXEs to perform custom actions; however, 32-bit MSI packages cannot support 64-bit DLLs or EXEs to perform custom actions.</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">[...]</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">To distribute a .NET Framework application both to 32- and 64-bit platforms, build two MSI packages, one targeted at a 32-bit and the other a 64-bit computer. The user can install the 32-bit setup project package and it will most likely run as a 64-bit application, only the 64-bit setup project will install to the "Program Files64" directory.</span></p>
<p><br /><span style="font-family: courier new,courier; font-size: small;">[...]</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">To create an installer for a 64-bit platform</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">1.&nbsp; Open a deployment project. For more information, see How to: Create or Add Deployment Projects.</span><br /><span style="font-family: courier new,courier; font-size: small;">2.&nbsp; In the <strong>Solution Explorer</strong>, select the deployment project.</span><br /><span style="font-family: courier new,courier; font-size: small;">3.&nbsp; In the <strong>Properties</strong> window, select the <strong>TargetPlatform</strong> property.</span><br /><span style="font-family: courier new,courier; font-size: small;">4.&nbsp; Choose either <strong>Itanium</strong> for an <strong>Intel Itanium 64-bit</strong> platform, or x64 for any other 64-bit platform (such as AMD64 and EM64T instruction sets).</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">At installation time, an error will be raised and installation will be halted if the target computer is not compatible with the specified platform.</span></p>
</td>
</tr>
</tbody>
</table>
<p>... but we don't get any clue. Also "Properties for the Launch Conditions Editor" (<a href="https://msdn.microsoft.com/en-us/library/5ecafwe3(v=vs.100).aspx#vxconlaunchconditionpropertiesanchor2" target="_blank">https://msdn.microsoft.com/en-us/library/5ecafwe3(v=vs.100).aspx#vxconlaunchconditionpropertiesanchor2</a>) doesn't seem to point us&nbsp;on the right path.</p>
<p>&nbsp;</p>
<p>&nbsp;The answer is given this thread:&nbsp;"Launch condition issue while running on Windows server 2008 (64 bit)" (<a href="https://social.msdn.microsoft.com/forums/en-us/winformssetup/thread/1DF0D4D6-3D84-4D81-ABF4-100F457FAE5A" target="_blank">https://social.msdn.microsoft.com/forums/en-us/winformssetup/thread/1DF0D4D6-3D84-4D81-ABF4-100F457FAE5A</a>):</p>
<table style="background-color: #dedede; width: 560px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><strong>Launch condition issue while running on Windows server 2008 (64 bit)</strong><br /><span style="font-family: courier new,courier; font-size: small;">=======================================================================</span><br /><br /><span style="font-family: courier new,courier; font-size: small;">I have created a setup package in VS 2008 setup and deployment project. I have added a launch condition using registry search for MSCRM 4.0. Setup works fine on 32 bit operating system but MSCRM 4.0 pre requisite fails on Windows Server 2008 (64 bit) operating system. It shows the message for pre requisite while MSCRM is installed and registry values also exist. i have tried to create setup x64 too. but same issue appears. </span>
<p><span style="font-family: courier new,courier; font-size: small;">[...]</span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span style="background-color: #ffff00;">Setup projects only ever do a registry search in the 32-bit part of the registry, even if they are built for x64.</span> <span style="background-color: #00ff00;">Internally, the RegLocator table does not have the msidbLocatorType64bit bit set in the Type field on x64 builds. So on an x64 system the MSCRM registry item might exist only in the 64-bit part of the registry, and not in the 32-bit view, the Wow6432Node, and both x86 and x64 setups would fail to find it.</span> If you look at the registry and that's the issue, then I'm not sure what you'd do except use Orca to update your x64 MSI file in the RegLocator table: </span><span style="font-family: courier new,courier; font-size: small;"><a href="https://msdn.microsoft.com/en-us/library/aa371171(VS.85).aspx">https://msdn.microsoft.com/en-us/library/aa371171(VS.85).aspx</a> (RegLocator Table);</span></p>
</td>
</tr>
</tbody>
</table>
<p><br />Similar threads:<br />&gt; "<span>Setup project: search registry always return false"</span>&nbsp;<a href="https://social.msdn.microsoft.com/Forums/en-US/winformssetup/thread/007318ae-fc2c-4912-8801-74ea48f9199a" target="_blank">https://social.msdn.microsoft.com/Forums/en-US/winformssetup/thread/007318ae-fc2c-4912-8801-74ea48f9199a</a>;</p>
<p><br />Let's see what role <strong>RegLocator</strong> table&nbsp;plays&nbsp;for a Windows Installer Database:</p>
<table style="background-color: #dedede; width: 560px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><span style="font-family: courier new,courier; font-size: small;"><strong>RegLocator Table</strong><br /><a href="https://msdn.microsoft.com/en-us/library/aa371171(VS.85).aspx">https://msdn.microsoft.com/en-us/library/aa371171(VS.85).aspx</a></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="font-size: small;">=======================================================================<br /><br /></span></span>
<p><span style="font-family: courier new,courier;">The RegLocator table holds the information needed to search for a file or directory using the registry, or to search for a particular registry entry itself. This table has the following columns.</span><br /><br /></p>
<table style="width: 532px; height: 99px; border: #000000 1px solid;" border="0">
<tbody>
<tr>
<td><span style="font-family: courier new,courier;">Signature_</span></td>
<td><span style="font-family: courier new,courier;"><a href="https://msdn.microsoft.com/en-us/library/aa369212(v=vs.85).aspx">Identifier</a></span></td>
<td><span style="font-family: courier new,courier;">Y</span></td>
<td><span style="font-family: courier new,courier;">N</span></td>
</tr>
<tr>
<td><span style="font-family: courier new,courier;">Root</span></td>
<td><span style="font-family: courier new,courier;"><a href="https://msdn.microsoft.com/en-us/library/aa369549(v=vs.85).aspx">Integer</a></span></td>
<td><span style="font-family: courier new,courier;">N</span></td>
<td><span style="font-family: courier new,courier;">N</span></td>
</tr>
<tr>
<td><span style="font-family: courier new,courier;">Key</span></td>
<td><span style="font-family: courier new,courier;"><a href="https://msdn.microsoft.com/en-us/library/aa371173(v=vs.85).aspx">RegPath</a></span></td>
<td><span style="font-family: courier new,courier;">N</span></td>
<td><span style="font-family: courier new,courier;">N</span></td>
</tr>
<tr>
<td><span style="font-family: courier new,courier;">Name</span></td>
<td><span style="font-family: courier new,courier;"><a href="https://msdn.microsoft.com/en-us/library/aa368609(v=vs.85).aspx">Formatted</a></span></td>
<td><span style="font-family: courier new,courier;">N</span></td>
<td><span style="font-family: courier new,courier;">Y</span></td>
</tr>
<tr>
<td><span style="font-family: courier new,courier;">Type</span></td>
</tr>
</tbody>
</table>
<br /><span style="font-family: courier new,courier;">[...]</span><br /><br /><span style="font-family: courier new,courier;">Key:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The key for the registry value.</span><br /><span style="font-family: courier new,courier;">Name:&nbsp;&nbsp;&nbsp;&nbsp; The registry value name. If this value is null, then the value from the key's unnamed or default value, if any, is retrieved.</span><br /><span style="font-family: courier new,courier;"><span style="background-color: #ffff00;">Type</span>:&nbsp;&nbsp;&nbsp;&nbsp; <span style="background-color: #ffff00;">A&nbsp;value that determines if the registry value is a file name, a directory location, or raw registry value</span>. </span>
<p><span style="font-family: courier new,courier;">The following table lists valid values. Set one of the first three values and <strong>msidbLocatorType64bit</strong> if necessary. If the entry in this field is absent, Type is set to be 1.</span></p>
<table style="border: #000000 1px solid;" border="0">
<tbody>
<tr><th><span style="font-family: courier new,courier;">Constant</span></th><th><span style="font-family: courier new,courier;">Hexadecimal</span></th><th><span style="font-family: courier new,courier;">Decimal</span></th><th><span style="font-family: courier new,courier;">Description</span></th></tr>
<tr>
<td><span style="font-family: courier new,courier;"><strong>msidbLocatorTypeDirectory</strong></span></td>
<td><span style="font-family: courier new,courier;">0x000</span></td>
<td><span style="font-family: courier new,courier;">0</span></td>
<td><span style="font-family: courier new,courier;">Key path is a directory.</span></td>
</tr>
<tr>
<td><span style="font-family: courier new,courier;"><strong>msidbLocatorTypeFileName</strong></span></td>
<td><span style="font-family: courier new,courier;">0x001</span></td>
<td><span style="font-family: courier new,courier;">1</span></td>
<td><span style="font-family: courier new,courier;">Key path is a file name.</span></td>
</tr>
<tr>
<td><span style="font-family: courier new,courier;"><strong>msidbLocatorTypeRawValue</strong></span></td>
<td><span style="font-family: courier new,courier;">0x002</span></td>
<td><span style="font-family: courier new,courier;">2</span></td>
<td><span style="font-family: courier new,courier;">Key path is a registry value.</span></td>
</tr>
<tr>
<td><span style="background-color: #ffff00; font-family: courier new,courier;"><strong>msidbLocatorType64bit</strong></span></td>
<td><span style="font-family: courier new,courier;">0x010</span></td>
<td><span style="font-family: courier new,courier;">16</span></td>
<td><span style="font-family: courier new,courier;">Set this bit to have the installer search the 64-bit portion of the registry. Do not set this bit to have the installer search the 32-bit portion of the registry.</span></td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier;">&nbsp;</span></p>
</td>
</tr>
</tbody>
</table>
<p><span style="font-size: small;"><strong><br /><br />Fixing our MSI installer&nbsp;</strong></span></p>
<p>&nbsp;First you need to download and install&nbsp;the <strong>ORCA</strong> database table editor. Then you need to perform these steps:</p>
<p><span style="color: #ff0000;"><strong>1.&nbsp;&nbsp;</strong><span style="color: #000000;">Open the output .MSI file and locate the</span></span> "<strong>ReqLocator</strong>" table entry;</p>
<table style="width: 560px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1300.11.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1300.11.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1300.11.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1300.11.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><span style="color: #ff0000;"><strong>2.</strong></span>&nbsp;&nbsp;&nbsp;Notice that &nbsp;that it is&nbsp;pointing to the a different type: "<strong>Type</strong>" =&nbsp;2;<br /><span style="color: #ff0000;"><strong>3.</strong></span>&nbsp;&nbsp; Assign the value <span style="background-color: #ffff00;"><strong>0x010</strong></span> to the "<strong>Type</strong>" property and press ENTER;</p>
<table style="width: 560px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/8372.12.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/8372.12.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/8372.12.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/8372.12.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><span style="color: #ff0000;"><strong>4.</strong></span>&nbsp;&nbsp; Save and run the project;<br /><br /><br />This time we&nbsp;notice that the search is directed to the correct registry hive. <strong><span style="color: #ff0000;">Please note that&nbsp;it doesn't mean&nbsp;the problem was solved ... :-( !</span></strong></p>
<table style="width: 560px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7652.13.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7652.13.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7652.13.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7652.13.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;<br />Unfortunately, even if we managed to overcome the <strong>RegLocator</strong> bug (<span style="color: #ff0000;"><strong>yes .. it's a bug</strong></span>, and it afects Visual Studio 2005, 2008, 2010 -&nbsp;I haven't tested with 2012 version yet), we have an even bigger problem that can't be solved, as far as I know.</p>
<p><br /><span style="font-size: small;"><strong>Fixed&nbsp;MSI installer still won't properly read the 64-bit registry value&nbsp;</strong></span></p>
<p>While testing, I noticed that no matter which <strong>Launch Condition</strong> I used (<strong>REGISTRYVALUE1="test"</strong>, <strong>REGISTRYVALUE1~="test"</strong>&nbsp;..more details on "Windows Installer Conditional Statement Syntax": <a href="https://msdn.microsoft.com/en-gb/library/windows/desktop/aa368012(v=vs.85).aspx">https://msdn.microsoft.com/en-gb/library/windows/desktop/aa368012(v=vs.85).aspx</a>&nbsp;), the project would always fail to validate my <strong>Condition</strong> statement. <br /><br />It was very strange since <strong>ProcMon</strong> clearly showed the key gets accessed and read. In order to troubleshoot this issue, I created an <strong>Installer Override</strong> custom project.</p>
<table style="background-color: #dedede; width: 550px; height: 488px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;">using&nbsp;</span>System;</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;">using&nbsp;</span>System.Collections;</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;">using&nbsp;</span>System.Collections.Generic;</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;">using&nbsp;</span>System.ComponentModel;</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;">using&nbsp;</span>System.Configuration.Install;</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;">using&nbsp;</span>System.Linq;　</span><br /><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;">namespace&nbsp;</span>ClassLibrary_InstallerOverride{</span><br /><span style="font-family: courier new,courier; font-size: small;">[</span><br /><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #2b91af;"><span style="color: #2b91af;"><span style="color: #2b91af;">RunInstaller</span></span></span>(<span style="color: #0000ff;"><span style="color: #0000ff;"><span style="color: #0000ff;">true</span></span></span>)]</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><span style="color: #0000ff;"><span style="color: #0000ff;">public</span></span></span><span style="color: #0000ff;"><span style="color: #0000ff;"><span style="color: #0000ff;">partial</span></span></span><span style="color: #0000ff;"><span style="color: #0000ff;"><span style="color: #0000ff;">class</span></span></span><span style="color: #2b91af;"><span style="color: #2b91af;"><span style="color: #2b91af;">InstallerOverride</span></span></span> : </span><br /><span style="font-family: courier new,courier; font-size: small;">System.Configuration.Install.<span style="color: #2b91af;">Installer</span></span><br /><span style="font-family: courier new,courier; font-size: small;">{</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp; <span style="color: #0000ff;"><span style="color: #0000ff;"><span style="color: #0000ff;">public</span></span></span>InstallerOverride()</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;{</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; InitializeComponent();</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp; } </span>
<p><span style="font-family: courier new,courier; color: #008000; font-size: small;">// Override the 'Install' method.</span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><span style="color: #0000ff;"><span style="color: #0000ff;">public</span></span></span><span style="color: #0000ff;"><span style="color: #0000ff;"><span style="color: #0000ff;">override</span></span></span><span style="color: #0000ff;"><span style="color: #0000ff;"><span style="color: #0000ff;">void</span></span></span> Install(<span style="color: #2b91af;"><span style="color: #2b91af;"><span style="color: #2b91af;">IDictionary </span></span></span>savedState)<br />{<br /></span><span style="font-family: courier new,courier; font-size: small;">&nbsp; System.Windows.Forms.</span><span style="font-family: courier new,courier; font-size: small;"><span style="color: #2b91af;"><span style="color: #2b91af;"><span style="color: #2b91af;">MessageBox</span></span></span>.Show(<span style="color: #a31515;"><span style="color: #a31515;"><span style="color: #a31515;">"Registry test value: ["</span></span></span> +<span style="color: #0000ff;"><span style="color: #0000ff;"><span style="color: #0000ff;">&nbsp; <br />&nbsp; this</span></span></span>.Context.Parameters[<span style="color: #a31515;"><span style="color: #a31515;"><span style="color: #a31515;">"<span style="background-color: #ffff00;">regPath</span>"</span></span></span>] + <span style="color: #a31515;"><span style="color: #a31515;"><span style="color: #a31515;">"]"</span></span></span></span><span style="font-family: courier new,courier; font-size: small;">);<br />&nbsp; </span><span style="font-family: courier new,courier; color: #0000ff; font-size: small;"><span style="color: #0000ff;"><span style="color: #0000ff;">base</span></span></span><span style="font-family: courier new,courier; font-size: small;">.Install(savedState);<br /></span><span style="font-family: courier new,courier; font-size: small;">}</span><br /><span style="font-family: courier new,courier; font-size: small;">}<br /></span><span style="font-family: courier new,courier; font-size: small;">}</span></p>
</td>
</tr>
</tbody>
</table>
<p><br />The project displays a message box, which contains the value read&nbsp;from our&nbsp;<strong>Custom Launch Condition</strong> variable. Using a little <strong>Windows Installer</strong> trick, we can access custom defined variables at runtime from an <strong>Installer Override</strong> class. We may&nbsp;use message boxes or text files to dump their contents.</p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/8640.14.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/8640.14.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/8640.14.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/8640.14.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br />More details:<br />&nbsp; &gt; "HOW TO: Retrieve a Value from the Registry and Then Use the Value in a Setup Project in Visual Studio .NET" <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="https://support.microsoft.com/kb/827026">https://support.microsoft.com/kb/827026</a>;<br />&nbsp; &gt; "Walkthrough: Deploying a Document-Level Customization Using a Windows Installer File"<br />&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<a href="https://msdn.microsoft.com/en-us/library/ms268758(v=vs.80).aspx">https://msdn.microsoft.com/en-us/library/ms268758(v=vs.80).aspx</a>&nbsp;<span style="background-color: #ffff99;">&gt;&gt; shows you all the steps for adding a<br />&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;custom&nbsp;installer override project and how you can define your own runtime variables for a MSI project</span>;&nbsp;</p>
<p><br />Since the test was always failing, I couldn't get as far as the step when my <strong>Custom Installer</strong> code kicks in. Therefore<span style="background-color: #ffff99;"> I had to modify my launch condition</span> to always return&nbsp;<strong>TRUE</strong> (for example, if "<strong>REGISTRYVALUE1</strong>" <strong>Custom Launch Condition</strong> is different than the searched string).</p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3426.15.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3426.15.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3426.15.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3426.15.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br />I rebuilt the project, fixed the <strong>RegLocator</strong> with ORCA editor and executed the setup. <span style="color: #ff0000;"><strong>For x64bit registry keys, the message box was empty!</strong></span></p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2480.16.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2480.16.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2480.16.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2480.16.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>To test if my code really works, I rebuilt the MSI (since the <strong>Custom Launch</strong> condition gets read properly now, we have to set its expression back to the initial format: <strong>REGISTRYVALUE1="test"</strong>).&nbsp;<strong><span style="color: #ff0000;">We can see that when it is targeting the 32-bit registry view, it is indeed working properly</span></strong>:</p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4810.17.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4810.17.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/4810.17.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/4810.17.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p><br /><strong>Conclusions:<br />&nbsp; </strong>&gt;&nbsp;I did some research in our internal database and it doesn't look like the Visual Studio team is aware<br />&nbsp;&nbsp;&nbsp; &nbsp;of the second issue; <br />&nbsp; &gt;&nbsp;I'll try to&nbsp;file a bug-fix request internally, but without a significant impact, it is unlikely that it will ever<br />&nbsp;&nbsp;&nbsp; &nbsp;be addressed;<br />&nbsp; &gt; in the meantime, developers that need to deploy x64bit&nbsp;applications with Windows Installer projects<br />&nbsp;&nbsp;&nbsp; &nbsp;should find alternative ways to check for the existence of 64-bit registry keys;&nbsp;</p>
<p>&nbsp;<br /><br /><br /></p>
<p><span style="font-family: courier new, courier; font-size: small;"><strong><span style="background-color: #ffffff;">Thank you for reading my article! Bye :-)</span></strong></span></p>]]></content:encoded>
    </item>
    <item>
      <title>VSTO - .Net code throws 'System.AccessViolationException' error when automating the 'Find' object in Word (KB 292744 BUG: Automation client receives an error message or crashes when the client calls the Find object in Word)</title>
      <link>https://docs.microsoft.com/archive/blogs/cristib/vsto-net-code-throws-system-accessviolationexception-error-when-automating-the-find-object-in-word-kb-292744-bug-automation-client-receives-an-error-message-or-crashes-when-the-client-calls-t</link>
      <pubDate>Fri, 31 Aug 2012 12:06:00 GMT</pubDate>
      <dc:creator><![CDATA[Cristian.Berescu]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cristib/2012/08/31/vsto-net-code-throws-system-accessviolationexception-error-when-automating-the-find-object-in-word-kb-292744-bug-automation-client-receives-an-error-message-or-crashes-when-the-client-calls-t/</guid>
      <description><![CDATA[Sometimes users are&nbsp;running&nbsp;versions of Office which are not fully up-to-date....]]></description>
      <content:encoded><![CDATA[<table style="width: 600px; height: 5806px; border-color: #ffffff;" border="0">
<tbody>
<tr>
<td>
<p><span style="font-family: courier new,courier; font-size: small;">Sometimes users are&nbsp;running&nbsp;versions of Office which are not fully <br />up-to-date. This&nbsp;might be due to the fact that their local IT <br />department has not tested the new patches and did not approve their <br />company wide distribution, or because the machine is not connected to<br />the Internet and needs to be manually&nbsp;updated .. or&nbsp;some other reason.&nbsp;<br />At the same time end-users&nbsp;are&nbsp;relying on&nbsp;COM add-ins and stand-alone COM automation programs&nbsp;to help&nbsp;with their daily work.</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">Later,&nbsp;the machine gets updated&nbsp;(let's&nbsp;suppose&nbsp;its user&nbsp;had Office 2007<br />SP2 and&nbsp;he installs SP3 and the latest&nbsp;Cumulative Updates).&nbsp;Suddenly he<br />notices that some of the programs automating Word&nbsp;will crash when performing&nbsp;certain tasks.</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">Let's assume&nbsp;the user&nbsp;is working with a&nbsp;WindowsForms application&nbsp;<br />developed in a managed environment (VB.NET), which uses COM automation <br />to open a document and perform a <strong>Find and Replace</strong> action in Word 2007:</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">-&nbsp; everything worked as expected until&nbsp;he updated&nbsp;Office&nbsp;from SP2 to<br />&nbsp;&nbsp;&nbsp; &nbsp;SP3;<br />&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">-&nbsp; after this change,&nbsp;the code started to trigger a&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; '<strong>System.AccessViolationException</strong>'&nbsp;error when running this code:</span></p>
<table style="background-color: #dedede; width: 570px; height: 364px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td><span style="font-family: courier new,courier; color: #000000; font-size: small;">Private Sub Test()</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp; Dim wrd As Microsoft.Office.Interop.Word.Application</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;wrd = CreateObject("Word.Application")</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;wrd.Documents.Open(sFilename)</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;wrd.ActiveDocument.Selection.Find.ClearFormatting()</span>
<p><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;With wrd.ActiveDocument.Selection.Find</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp; .Text = "-"</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp; .Replacement.Text = "-test-"</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp; .Forward = True</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp; .Wrap =&nbsp;Microsoft.Office.Interop.Word.WdFindWrap.wdFindContinue</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp; &nbsp;.Format = True</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp; .MatchCase = False</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.MatchWholeWord = False</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.MatchWildcards = False</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.MatchSoundsLike = False</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.MatchAllWordForms = False</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;End With</span><br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;wrd.ActiveDocument.Selection.Find.Execute <br />&nbsp;&nbsp;&nbsp;&nbsp; (Replace:=Microsoft.Office.Interop.Word.WdReplace.wdReplaceAll)</span><br /><span style="color: #000000;"><span style="font-family: courier new,courier; font-size: small;">End Sub</span></span></p>
</td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier; font-size: small;"><br />&nbsp; - even if we try to comment&nbsp;the "<span style="background-color: #e7e7e7;">Selection.Find.ClearFormatting()</span>"<br />&nbsp;&nbsp; &nbsp;line,&nbsp;any instruction&nbsp;which gets executes inside the WITH block&nbsp;<br />&nbsp;&nbsp;&nbsp; triggers&nbsp;a COM exception:&nbsp;</span></p>
<table style="background-color: #dedede; width: 570px; height: 796px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><span style="font-family: courier new,courier; font-size: small;">Application: sampleApp.exe</span><br /><span style="font-family: courier new,courier; font-size: small;"><br />Framework Version: v4.0.30319</span><br /><span style="font-family: courier new,courier; font-size: small;">Description:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The process was terminated due to an unhandled exception.</span><br /><span style="font-family: courier new,courier; font-size: small;">Exception Info:&nbsp;&nbsp;&nbsp;&nbsp;<span style="background-color: #c0c0c0;">System.AccessViolationException</span><br /></span><br /><span style="font-family: courier new,courier; font-size: small;">Stack:</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at Microsoft.Office.Interop.Word.Find.set_Style(System.Object<br />&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">&nbsp;ByRef)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at Word2WikiPlus.Form1.ConvertHeading(Int64, System.String,&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.String)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at Word2WikiPlus.Form1.Transform(System.String ByRef, Int32)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at Word2WikiPlus.Form1.Button_start_Click(System.Object, <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.EventArgs)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at System.Windows.Forms.Control.OnClick(System.EventArgs)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at System.Windows.Forms.Button.OnClick(System.EventArgs)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at System.Windows.Forms.Button.OnMouseUp<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (System.Windows.Forms.MouseEventArgs)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at System.Windows.Forms.Control.WmMouseUp<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (System.Windows.Forms.Message ByRef,<br />&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;System.Windows.Forms.MouseButtons, Int32)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at System.Windows.Forms.Control.WndProc(System.Windows.Forms.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Message ByRef)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at System.Windows.Forms.ButtonBase.WndProc<br />&nbsp;&nbsp;&nbsp;&nbsp; (System.Windows.Forms.Message ByRef)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at System.Windows.Forms.Button.WndProc(System.Windows.Forms.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Message ByRef)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at System.Windows.Forms.Control+ControlNativeWindow.OnMessage(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.Windows.Forms.Message ByRef)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at System.Windows.Forms.Control+ControlNativeWindow.WndProc(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.Windows.Forms.Message ByRef)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32,<br />&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;IntPtr,&nbsp;IntPtr)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ByRef)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at System.Windows.Forms.Application+ComponentManager.System.<br />&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FPushMessageLoop(IntPtr,Int32,Int32)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at System.Windows.Forms.Application+ThreadContext.RunMessageLoop<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Inner(Int32,System.Windows.Forms.ApplicationContext)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at System.Windows.Forms.Application+ThreadContext.RunMessageLoop&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Int32,System.Windows.Forms.ApplicationContext)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at&nbsp;Microsoft.VisualBasic.ApplicationServices.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WindowsFormsApplicationBase.OnRun()</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at Microsoft.VisualBasic.ApplicationServices.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WindowsFormsApplicationBase.DoApplicationModel()</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at Microsoft.VisualBasic.ApplicationServices.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WindowsFormsApplicationBase.Run(System.String[])</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; at Word2WikiPlus.My.MyApplication.Main(System.String[])</span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p><span style="font-family: courier new,courier; font-size: small;">This entry appears in <strong>Computer Management</strong> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">&gt; <strong>Event Viewer<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </strong>&gt; <strong>Windows Logs</strong>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt; <strong>Application</strong></span></p>
<table style="background-color: #dedede; width: 550px; height: 10px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td><span style="font-family: courier new,courier; font-size: small;">The description for Event ID 1000 from source .NET Runtime 4.0 Error Reporting cannot be found. Either the component that raises this event is not&nbsp;&nbsp;&nbsp; installed on your local computer or the installation is corrupted. You can install or repair the component on the local computer.</span>
<p><span style="font-family: courier new,courier; font-size: small;">If the event originated on another computer, the display information had to be saved with the event.</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">The following information was included with the event:</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; sampleApp.exe</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; 0.3.3.0</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; 4eca4fbc</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; oleaut32.dll</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; 5.1.2600.5512</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; 4802bdb7</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; 0</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; 0007c86c</span></p>
</td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier; font-size: small;"><br />&nbsp; -&nbsp; however, another machine that has also been updated to SP3 can <br />&nbsp;&nbsp;&nbsp;&nbsp; successfully run the code;</span></p>
<p>&nbsp;</p>
<p><span style="font-size: small;"><strong><span style="font-family: courier new,courier;">Troubleshooting steps performed</span></strong></span></p>
<p><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;<strong>1.</strong>&nbsp;tried to eliminate the .Net layer by writing a small VBscript:</span></p>
<table style="background-color: #dedede; width: 550px; height: 1px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><span style="font-family: courier new,courier; font-size: small;">Set objDOCXSourceApp = CreateObject("Word.Application") </span></p>
<p><span style="font-family: courier new,courier; font-size: small;">objDOCXSourceApp.Visible&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = false<br /></span><span style="font-family: courier new,courier; font-size: small;">objDOCXSourceApp.DisplayAlerts = false </span></p>
<p><span style="font-family: courier new,courier; font-size: small;">wscript.echo " Open Input file..."</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">Set objDOCXSourceDoc = objDOCXSourceApp.Documents.Open(&lt;inputPath&gt;)</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">If Err.Number &lt;&gt; 0 Then<br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">objDOCXSourceApp.Application.Quit<br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">Set objDOCXSourceDoc = Nothing<br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">Set objDOCXSourceApp = Nothing<br />&nbsp;&nbsp; wscript.Quit<br /></span><span style="font-family: courier new,courier; font-size: small;">End If</span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span style="font-family: courier new,courier; font-size: small;">wscript.echo </span>" File opened OK."</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">Dim newDocWin<br />Set newDocWin = objDOCXSourceDoc.ActiveWindow <br /><br />newDocWin.Selection.Find.ClearFormatting()</span><span style="font-family: courier new,courier; font-size: small;">newDocWin.Selection.Find.Replacement.ClearFormatting()</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">If Err.Number &lt;&gt; 0 Then <br />&nbsp;&nbsp; wscript.Quit<br /></span><span style="font-family: courier new,courier; font-size: small;">End If </span></p>
<p><span style="font-family: courier new,courier; font-size: small;">wscript.echo " ClearFormatting .. OK."</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">With newDocWin.Selection.Find<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">.Text = "-"<br />&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">.Replacement.Text = "-test-"<br />&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">.Forward = True<br />&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">.Wrap = 1 'Microsoft.Office.Interop.Word.WdFindWrap.wdFindContinue <br />&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">.Format = True<br />&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">.MatchCase = False<br />&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">.MatchWholeWord = False<br />&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">.MatchWildcards = False<br />&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">.MatchSoundsLike = False<br />&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">.MatchAllWordForms = False<br /></span><span style="font-family: courier new,courier; font-size: small;">End With </span></p>
<p><span style="font-family: courier new,courier; font-size: small;">'WdReplace.wdReplaceAll = 2 </span></p>
<p><span style="font-family: courier new,courier; font-size: small;">newDocWin.Selection.Find.Execute ,,,,,,,,,,2</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">wscript.echo " newDocWin.Selection.Find.Execute(Replace) .. OK."</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">objDOCXSourceDoc.Close (False)<br /></span><span style="font-family: courier new,courier; font-size: small;">objDOCXSourceApp.Application.Quit</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">Set objDOCXSourceDoc = Nothing<br /></span><span style="font-family: courier new,courier; font-size: small;">Set objDOCXSourceApp = Nothing</span></p>
</td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp; RESULT: the late binding code works;</span></p>
<p><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;&nbsp;<strong>2.</strong>&nbsp;Analyzed Fusion logs and ProcMon&nbsp;activity trace;<br />&nbsp;&nbsp;&nbsp;&nbsp; RESULT: the correct&nbsp;type libraries seem to be loaded;</span><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;<strong>3.</strong> Researched the Internet;<br />&nbsp;&nbsp;&nbsp;&nbsp; RESULT:&nbsp;found&nbsp;t</span><span style="font-family: courier new,courier; font-size: small;">his article: <a href="https://support.microsoft.com/kb/292744" target="_blank">https://support.microsoft.com/kb/292744</a>;<br />&nbsp;&nbsp;&nbsp; &nbsp;The&nbsp;issues which are described are similar to what we experience when&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; working&nbsp;with the <strong>Find</strong> object, but the error we receive is not listed <br />&nbsp;&nbsp;&nbsp;&nbsp; there.</span></p>
<p>&nbsp;</p>
<table style="background-color: #dedede; width: 550px; height: 22px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><span style="font-family: courier new,courier; font-size: small;"><strong>BUG: Automation client receives an error message or crashes when the client calls the Find object in Word</strong><br /><a href="https://support.microsoft.com/kb/292744" target="_blank">https://support.microsoft.com/kb/292744</a><br />=======================================================================<br /></span><span style="font-family: courier new,courier; font-size: small;"><br />...<br /></span><span style="font-size: small;"><strong><br /><span style="font-family: courier new,courier;">Symptoms</span></strong><br /></span><span style="font-family: courier new,courier;"><span style="font-size: small;"><br />When you us</span><span style="font-size: small;">e an out-of-process client application that uses early binding to Automate Microsoft Word 97 or later versions of Word, the application may crash with an access violation or you may receive one of the following error messages:</span></span></p>
<p>&nbsp;</p>
<p><span style="font-family: courier new,courier; font-size: small;">From Microsoft Visual Basic:<br /></span><br />&nbsp;&nbsp;<span style="font-family: courier new,courier; font-size: small;"> &gt;&nbsp;Run-time error '-2147023113 (800706f7)': The method '~' of object '~' failed<br />&nbsp; &gt; Run-time error '-2147023113 (800706f7)':&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">Method 'Execute' of object 'Find' failed<br />&nbsp; &gt; </span><span style="font-family: courier new,courier; font-size: small;">Run-time error 430:&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">Class does not support automation or does not support expected interface. </span></p>
<p><br /><span style="font-family: courier new,courier; font-size: small;">From Microsoft Visual C++:</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">&nbsp; &gt; HRESULT = 0x800706F7</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; &nbsp;RPC_X_BAD_STUB_DATA - The stub received bad data. <br /></span><br /><span style="font-family: courier new,courier; font-size: small;"><strong>Note</strong> In debug builds, you receive a corrupt stack warning message from an Assert dialog box, and the value of EAX is that listed above. In release builds, the stack corruption likely crashes the application soon after this point. However, the HRESULT value is likely to be similar to the above.</span></p>
<p>&nbsp;</p>
<p><span style="font-family: courier new,courier; font-size: small;">The problem occurs consistently on some computers, but may never occur on others. <span style="background-color: #00ff00;">Installing a new application or a Microsoft Excel service pack can cause a computer that was working previously to experience the problem</span>.</span></p>
<p><br /><strong>Cause</strong> <br /><br /></p>
<p><span style="font-family: courier new,courier; font-size: small;">Several globally unique identifiers (GUIDs) that are used by Word for its interface identifiers were used by Excel 5.0 for an older object model that is now obsolete.</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">When the Excel 5.0 type library is reregistered on a system, the interface <span style="background-color: #00ff00;">GUIDs in the registry that should point to the Word type library</span> <span style="background-color: #ffff00;">point to the Excel 5.0 library</span>, and COM can mistakenly construct the wrong proxy v-table for an out-of-process <span style="background-color: #00ff00;">client using early binding to Word</span>. Calls that are made to this proxy return errors or crash because the proxy is configured for a dispinterface for Excel instead of for a dispinterface for the expected Word interface.</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">The following GUIDs are duplicated in the Excel 5.0 type library and the Word 8.0, 8.1, 10.0 and 11.0 type libraries.</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">The following GUIDs are affected:</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">&nbsp; &gt; Word.Replacement interface {000209B1-0000-0000-C000-000000000046}</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp; &gt; Word.Dictionary&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {000209AD-0000-0000-C000-000000000046}</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp; &gt; Word.ReadabilityStatistics {000209AE-0000-0000-C000-000000000046}</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp; &gt; Word.ReadabilityStatistic&nbsp; {000209AF-0000-0000-C000-000000000046}</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp; &gt; Word.Find&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {000209B0-0000-0000-C000-000000000046}<br /></span></p>
<p><strong><span style="font-family: courier new,courier; font-size: small;"><br />Resolution</span></strong><br /><span style="font-family: courier new,courier; font-size: small;"><br />To resolve this problem, use one of the following methods.<br /><br />&bull; Modify your code to use late binding when you call methods or properties on any of the above listed Word interfaces.</span><br /><span style="font-family: courier new,courier; font-size: small;">&bull; Reregister the Word type library on the system on which the problem occurs.</span><br /><span style="font-family: courier new,courier; font-size: small;"><br />The recommended solution is to use late binding. Because both type libraries describe interfaces that implement the IDispatch interface, calls to any of the IDispatch methods work regardless of which library was last registered on the system. This is the only way to be sure that your code does not encounter this error on systems that you do not administer.</span></p>
<p>&nbsp;</p>
<p><span style="font-family: courier new,courier; font-size: small;">For customers who use client applications that cannot be recompiled to use late binding, you can reregister the Word type library to resolve the problem in most cases. <span style="background-color: #00ff00;">Because the problem returns if the Excel 5.0 library is reregistered again, this method is not an ideal resolution</span>. However, the chances of the Excel 5.0 library being reregistered are low. Therefore, this method should work for most users.</span></p>
<p>&nbsp;</p>
<p><span style="font-family: courier new,courier; font-size: small;">To reregister the Word type library, find the appropriate type library for the version of Word that is installed on the system.</span></p>
<p>&nbsp;</p>
<p><span style="font-family: courier new,courier; font-size: small;">Version&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">Library name<br />--------------------------------------<br /></span><span style="font-family: courier new,courier; font-size: small;">Word 97&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">Msword8.olb<br /></span><span style="font-family: courier new,courier; font-size: small;">Word 2000&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">Msword9.olb<br /></span><span style="font-family: courier new,courier; font-size: small;">Word 2002&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">Msword.olb<br /></span><span style="font-family: courier new,courier; font-size: small;">Word 2003&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">Msword.olb</span></p>
<p>&nbsp;</p>
<p><span style="font-family: courier new,courier; font-size: small;">Then, from the command line, use <span style="background-color: #c0c0c0;">Regtlib.exe</span> together with the full path to the type library to reregister the library for COM. Regtlib.exe calls the LoadTypeLib and RegisterTypeLib application program interfaces (APIs) on the type library (.tlb or .olb) file that is passed in. COM repairs the misconfigured registry keys.</span><span style="font-family: courier new,courier; font-size: small;">&nbsp;</span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;<br /><br /><strong><span style="font-family: courier new,courier; font-size: small;">How to solve this issue?</span></strong></p>
<p><span style="font-family: courier new,courier; font-size: small;">Since the user cannot modify the design of the application, he has to <br />re-register the Word type library.</span></p>
<table style="background-color: #dedede; width: 550px; height: 37px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td><span style="font-family: courier new,courier; font-size: small;">C:\Windows\Microsoft.NET\Framework\v4.0.30319\<span style="color: #993366;"><strong>regtlibv12.exe</strong></span> "C:\Program Files\Microsoft Office\Office12\MSWORD.OLB"</span></td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier; font-size: small;"><strong><br /><br />Caution:</strong>&nbsp;<br /></span><span style="font-family: courier new,courier; font-size: small;">------------------------------------------------------------------------------<br />*&nbsp; If the library registration goes wrong, you might receive&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">the <br />"<span style="background-color: #e7e7e7;">SEHException was unhandled</span>" message&nbsp;when&nbsp;automating the <strong>Find</strong> object.</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">*&nbsp; The&nbsp;.NET error message&nbsp;is a bit&nbsp;misleading ... in the managed<br />environment, we didn't get any hint that the is something wrong the&nbsp;<br /><strong>Find</strong> object ("<span style="font-family: courier new,courier; font-size: small;">Class does not support automation or does not support <br />expected interface.</span>").<br />&nbsp;The only clue I could find is&nbsp;this KB: "<a href="https://msdn.microsoft.com/en-us/library/ms164911(v=VS.80).aspx" target="_blank">Troubleshooting Exceptions: System.AccessViolationException</a>"</span></p>
<table style="background-color: #dedede; width: 550px; height: 37px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td><span style="font-family: courier new,courier; font-size: small;">An access violation that occurs in unsafe <span style="background-color: #00ff00;">managed code</span> can be expressed<br />as either a <span style="background-color: #ffff00;">NullReferenceException </span>or a <span style="background-color: #ffff00;">AccessViolationException</span>, depending on the platform.<br /><span style="background-color: #00ff00;">Access violations in unmanaged code</span> that bubble up to <span style="background-color: #ffff00;">managed code</span> are always <span style="font-family: courier new,courier; font-size: small;">wrapped in an <span style="background-color: #ffff00;">AccessViolationException</span>.<br /></span></span></td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier; color: #000000; font-size: small;"><br />.. so it appears that if anything goes wrong in the unmanaged code, it will show up as a memory violation in the managed layer.<br /><br /><span style="font-family: courier new,courier; font-size: small;">*&nbsp; Sometimes, the error surfaces as corrupted memory exceptions:<br />&nbsp;&nbsp; &gt; "<span style="background-color: #ffff99;">Attempted to read or write protected memory. This is often<br />&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;an indication that other memory is corrupt</span>";<br />&nbsp;&nbsp; &gt; "<span style="background-color: #ccffcc;">Es wurde versucht, im gesch&uuml;tzten Speicher zu lesen oder<br />&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;zu schreiben. Dies ist h&auml;ufig ein Hinweis darauf, dass<br />&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;anderer Speicher besch&auml;digt ist</span>"<br /></span></span><span style="font-family: courier new,courier; color: #000000; font-size: small;">------------------------------------------------------------------------------</span></p>
<p><br /><span style="background-color: #ffffff; font-family: courier new,courier; font-size: small;">Hopefully this blog entry will help you identify and solve&nbsp;the <br /><strong>AccessViolationException</strong> error faster.<br /><br /><br /></span></p>
<p><span style="font-family: courier new,courier; color: #800000; font-size: small;"><span style="background-color: #ffffff;"><strong>I would like to thank Mr. Domenico Zanferrari for&nbsp;his valuable <br />insight and for helping me run my tests in an environment affected <br />by&nbsp;the aforementioned&nbsp;issue.&nbsp;</strong>&nbsp;</span></span></p>
<p><span style="font-family: courier new,courier; font-size: small;">&nbsp;</span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><strong><span style="background-color: #ffffff;">Thank you for reading my article! Bye :-)</span></strong></span></p>
<p><span style="font-family: courier new,courier; font-size: small;">&nbsp;</span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>OpenXML &amp; VSTO &amp; VBA - Finding a reliable mechanism for reading the correct value of CharactersWithSpaces 'extended-properties' in Word documents [part 2/2].</title>
      <link>https://docs.microsoft.com/archive/blogs/cristib/openxml-vsto-vba-finding-a-reliable-mechanism-for-reading-the-correct-value-of-characterswithspaces-extended-properties-in-word-documents-part-22</link>
      <pubDate>Mon, 30 Jul 2012 12:59:00 GMT</pubDate>
      <dc:creator><![CDATA[Cristian.Berescu]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cristib/2012/07/30/openxml-vsto-vba-finding-a-reliable-mechanism-for-reading-the-correct-value-of-characterswithspaces-extended-properties-in-word-documents-part-22/</guid>
      <description><![CDATA[&nbsp;




This article&nbsp;is split across&nbsp;two blog posts and&nbsp;this is&nbsp;part...]]></description>
      <content:encoded><![CDATA[<p>&nbsp;</p>
<table style="width: 569px; height: 657px;" border="0">
<tbody>
<tr>
<td>
<p><span style="font-family: arial, helvetica, sans-serif; color: #888888;"><span style="font-size: small;">This article&nbsp;is split across&nbsp;two blog posts and&nbsp;this is&nbsp;part #2&nbsp;.. use <a title="Part 1" href="https://blogs.msdn.com/b/cristib/archive/2012/06/30/openxml-vsto-vba-finding-a-reliable-mechanism-for-reading-the-correct-value-of-characterswithspaces-_2700_extended_2d00_properties_2700_-in-word-documents-part1.aspx" target="_blank">this link</a> to go to part #1.</span></span></p>
<p><span style="font-family: arial, helvetica, sans-serif; color: #000000;"><span style="font-size: small;">In&nbsp;part #1 of this article, I&nbsp;demonstrated how words are counted&nbsp;using OpenXML and&nbsp;I warned about the dangers of not getting it done correctly.<br /></span></span></p>
<p><span style="font-family: arial, helvetica, sans-serif; color: #000000;"><span style="font-size: small;">Here is a short summary of the alternatives we have:&nbsp;&nbsp;&nbsp;</span></span></p>
<p><span style="font-family: %value;"><strong>Can we&nbsp;obtain&nbsp;100%&nbsp;reliable statistics?</strong></span><br /><br /><span style="font-family: %value; color: #000080;"><strong>Method&nbsp;#1:</strong></span><br /><span style="font-family: %value;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;When Word receives a query about the Document statistics&nbsp;(either manually&nbsp;through&nbsp;</span><span style="font-family: %value;">the <strong>Ribbon</strong> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; graphical interface or using <strong>VBA ObjectModel</strong>), it computes&nbsp;those results&nbsp;and always reports&nbsp;</span><span style="font-family: %value;">the <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; correct numbers. All we have to do next, is to&nbsp;save and close&nbsp;the file and&nbsp;then send it to a program <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; which accesses the OpenXML structure and reads those values.&nbsp;&nbsp;</span><br /><br /><span style="font-family: %value;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The only difficult part is finding a way to trigger the update every time, to ensure that the </span><span style="font-family: %value;"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; information stored in the file is up to date.</span><br /><br /><span style="font-family: %value;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>Advantages:&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt; easy to implement;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp;OpenXML code used to read the values&nbsp;is very simple;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; works&nbsp;for all kinds of input files ... even very complex ones&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(containing&nbsp;embedded charts, shapes, nested tables ..etc);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Disadvantages: <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; we can only force the Word Count update if we rely&nbsp;on a VBA / VSTO<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add-in&nbsp;installed on the client-side;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt; somehow, the&nbsp;automated&nbsp;Statistics Update&nbsp;Add-in has to be <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; deployed to all&nbsp;end-users;&nbsp;</strong></span><br /><span style="font-family: %value;">&nbsp;<span style="color: #000080;"><strong>Method&nbsp;#2:<span style="color: #000000;"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></strong><span style="color: #000000;">Write our own OpenXML code and count the words ourselves.<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>Advantages:&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt; no need for 'helper' tools;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Disadvantages: <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp;because the OpenXML format is VERY complex, the code will run <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reliably&nbsp;only for basic input files; If you want to extend the program <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to be able to&nbsp;handle all&nbsp;kinds&nbsp;of input documents you will find that <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the <span style="color: #ff0000;">complexity of the&nbsp;code increases&nbsp;</span><span style="color: #ff0000;">up to the point where it is not <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; feasible to continue</span> with the&nbsp;project (you will very&nbsp;likely&nbsp;be forced <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to&nbsp;write individual code rules for targeting&nbsp;all kinds of <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exceptions&nbsp;and special conditions for XML text tags, that may <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; appear in&nbsp;different&nbsp;combinations);<br /></strong><br /></span></span></span></p>
<p><span style="font-family: %value;"><span style="color: #000080;"><span style="color: #000000;">In this article, I would like to present the first method, where we use VBA to count our words. But first, we have to trigger the problem:<br /></span></span></span></p>
<p>&nbsp;</p>
<p><strong>Triggering the Word statistics mismatch problem</strong></p>
<p><span style="font-family: arial, helvetica, sans-serif;"><span><span style="color: #ff0000;"><strong>1.</strong></span>&nbsp;&nbsp; Just create a new Word document, type "<strong>=rand(1)</strong>" (without the quotes), then&nbsp;press <strong>Enter</strong> key;<br /><span style="color: #ff0000;"><strong>2.</strong></span>&nbsp;&nbsp;&nbsp;Save it&nbsp;file using <strong>.docx</strong>&nbsp;type, then close it;<br /><span style="color: #ff0000;"><strong>3.&nbsp;&nbsp;&nbsp;</strong><span style="color: #000000;">Open the file using an OpenXML editor, or r</span><span style="color: #000000;">ename the document from <strong>.docx</strong> to <strong>.zip</strong>, open the <strong>docProps</strong>&nbsp;folder and then edit the <strong>app.xml</strong>&nbsp;file;&nbsp;&nbsp;Note the values of these XML items:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp; <span style="background-color: #ebebeb;">Pages</span>;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt;&nbsp; <span style="background-color: #ebebeb;">Words</span>;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt;&nbsp;&nbsp;<span style="background-color: #ebebeb;">Characters</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp;<span style="background-color: #ebebeb;"> Lines</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp;&nbsp;<span style="background-color: #ebebeb;">Paragraphs</span>;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp;&nbsp;<span style="background-color: #ebebeb;">CharactersWithSpaces</span>;</span></span><br /><span style="color: #ff0000;"><strong>4.</strong></span>&nbsp;&nbsp; Close the editor, or if you renamed the file to <strong>.zip</strong>, restore its original extension; Open it again in Word;<br /><span style="color: #ff0000;"><strong>5.</strong></span>&nbsp;&nbsp; On the <strong>Review</strong> tab, in the <strong>Proofing</strong> group, click <strong>Word Count</strong>;<br /><span style="color: #ff0000;"><strong>6.&nbsp;&nbsp; </strong><span style="color: #000000;">Compare the statistics in the<strong> Word Count</strong> dialog with those noted from the <strong>app.xml</strong> file;</span></span></span></span></p>
<table style="width: 550px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0488.1.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0488.1.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0488.1.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0488.1.jpg" alt="" border="0" /></a></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;<strong>Result:</strong> we easily notice that the numbers are different ...<br /><br /><span style="color: #ff0000;"><strong>7.&nbsp;&nbsp; </strong><span style="color: #000000;">Close the document again, you should be prompted to <strong>Save</strong> it. Go ahead and click <strong>OK</strong> to store the updated <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; document information;<br /><span style="color: #ff0000;"><strong>8.</strong></span>&nbsp;&nbsp; Open&nbsp;its internal OpenXML structure and this time you should see that the numbers match;&nbsp;<br /></span></span>&nbsp;</p>
<p>If we slightly change the order of execution for the aforementioned steps: <br /><br />&nbsp;&nbsp; &gt;&nbsp;create a new file;<br />&nbsp;&nbsp; &gt;&nbsp;add some text;<br />&nbsp;&nbsp; &gt; save the file;<br />&nbsp;&nbsp; &gt;&nbsp;keep the document open, then go to '<strong>Review</strong>' &gt; '<strong>Proofing</strong>';<br />&nbsp;&nbsp; &gt; click on '<strong>Word Count</strong>';<br />&nbsp;&nbsp; &gt; close the file; <br />&nbsp;&nbsp; &gt;&nbsp;open it&nbsp;using an OpenXML editor, or r<span style="color: #000000;">ename the document from <strong>.docx</strong> to <strong>.zip</strong>, open the <strong>docProps </strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; folder and then edit the <strong>app.xml</strong>&nbsp;file;</span><br /><br />... you'll notice that the correct statistics information is&nbsp;stored into the document.<br /><br /><br />But something interesting happens ... when&nbsp;we try to close the Word document after viewing the <strong>Statistics</strong>, even&nbsp;though we didn't add any modification (we simply clicked on '<strong>Word Count</strong>') the application prompts us to save the file again!<br /><br />The same behavior occurs if I go to VBA and execute: <br /><br />"<span style="background-color: #ededed; font-family: courier new,courier;"><strong>Debug.Print ActiveDocument.ComputeStatistics(wdStatisticCharactersWithSpaces)</strong></span>".</p>
<p>What this means is that when we first saved the file, Word just entered a rough estimation of the Character count, but when we clicked on '<strong>Word Count</strong>', the application updated its <strong>Statistics</strong>.</p>
<p>Since we know that it&rsquo;s enough to click on the '<strong>Word Count</strong>' button or execute the VBA instruction to have the correct value stored in OpenXML, we can take advantage of it to force a computation before the user triggers a <strong>Save</strong> in Word.</p>
<p>In this way, each time the end-user sends his file to an automated code or script, it will contain the most up-to-date <strong>Statistics </strong>information.</p>
<p>&nbsp;</p>
<p><strong>A simple solution using&nbsp;VBA ...<br /></strong>&nbsp;<br />I wrote a simple Word DOTM add-in which will trigger the statistics update before each save:</p>
<table style="background-color: #000000; width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td style="text-align: left;">
<p><span style="font-family: courier new, courier; color: #ffffff; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000; font-size: medium;"><strong>DISCLAIMER</strong></span><br /><br /></span><span style="font-family: courier new, courier; color: #ffffff;">Sample Code is provided for the purpose of illustration only and is not intended to be used in a production environment!</span></p>
<p><span style="font-family: courier new, courier; color: #ffffff;">THIS SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,&nbsp;</span><span style="font-family: courier new, courier; color: #ffffff;">INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.</span></p>
<p><span style="font-family: courier new, courier; color: #ffffff;">We grant You a nonexclusive, royalty-free right to use and modify the<br />Sample Code and to reproduce and distribute the object</span><span style="font-family: courier new, courier; color: #ffffff;">&nbsp;code form of <br />the Sample Code, provided that. You agree: <br />&nbsp;&nbsp; (i)&nbsp;&nbsp; to not use Our name, logo, or trademarks to market Your <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; software&nbsp;</span><span style="font-family: courier new, courier; color: #ffffff;">product&nbsp;in which the Sample Code is embedded; <br />&nbsp;&nbsp; (ii)&nbsp; to include a valid copyright notice on Your software<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;product&nbsp;in&nbsp;which the&nbsp;</span><span style="font-family: courier new, courier; color: #ffffff;">Sample Code is embedded; and <br />&nbsp;&nbsp; (iii) to indemnify, hold harmless, and defend Us and Our <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; suppliers&nbsp;from&nbsp;and against any claims&nbsp;</span><span style="font-family: courier new, courier; color: #ffffff;">or lawsuits,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;including&nbsp;attorneys&rsquo;&nbsp;fees, that&nbsp;arise or result from the<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;use or&nbsp;distribution of&nbsp;t</span><span style="font-family: courier new, courier; color: #ffffff;">he Sample Code.</span></p>
</td>
</tr>
</tbody>
</table>
<br />
<table style="background-color: #dedede; width: 550px; height: 10px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><span style="font-family: courier new,courier; font-size: small;"><strong><br />Module1<br /></strong></span><span style="font-family: courier new,courier; font-size: small;">-----------------------------------------------------------------<br /><br /></span><span style="font-family: courier new,courier;">Option Explicit</span>&nbsp;<br /><span style="font-family: courier new,courier;"><br />Public clsWd As Class1</span></p>
<p><span style="font-family: courier new,courier;">Sub AutoExec()<br /></span><span style="font-family: courier new,courier;"><br />&nbsp;&nbsp; Debug.Print "WordFixStatistics: AutoExec fired"<br /></span><span style="font-family: courier new,courier;">&nbsp;&nbsp; Set clsWd = New Class1</span></p>
<p><span style="font-family: courier new,courier;">End Sub<br /><br /><br /></span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><strong>Class1<br /></strong></span><span style="font-family: courier new,courier; font-size: small;">------------------------------------------------------------------</span><span style="font-family: courier new,courier; font-size: small;"><br /></span><span style="font-family: courier new,courier;">Public WithEvents clsWd As Application</span><span style="font-family: courier new,courier;"><br /></span><span style="font-family: courier new,courier;"><br /></span><span style="font-family: courier new,courier;">Private Sub Class_Initialize()</span></p>
<p style="padding-left: 30px;"><span style="font-family: courier new,courier;">Debug.Print "WordFixStatistics: Class_Initialize fired"<br /></span><span style="font-family: courier new,courier;">Set clsWd = Application</span></p>
<p><span style="font-family: courier new,courier;">End Sub</span></p>
<p><span style="font-family: courier new,courier;">Private Sub clsWd_DocumentBeforeSave(ByVal Doc As Document, _ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SaveAsUI As Boolean, _<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Cancel As Boolean)</span></p>
<p><span style="font-family: courier new,courier;">Debug.Print "WordFixStatistics: DocumentBeforeSave event fired"<br /></span><span style="font-family: courier new,courier;">Debug.Print "The document: " &amp; Doc.Name &amp; " has [" &amp; _</span></p>
<p><span style="font-family: courier new,courier;">Doc.ComputeStatistics(wdStatisticCharactersWithSpaces) &amp; "] CharactersWithSpaces."</span>&nbsp;</p>
<p><span style="font-family: courier new,courier;">End Sub</span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>As you can see, everything seems to be&nbsp;working:</p>
<table style="width: 550px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7041.6.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7041.6.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7041.6.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7041.6.jpg" alt="" border="0" /></a></td>
</tr>
</tbody>
</table>
<p>&nbsp;.. but not for all scenarios.</p>
<p>Let's suppose the end-user starts by opening an older <strong>.DOC</strong> file, then he does a <strong>SaveAs</strong> to store it as an OpenXML format document. In this case, the newly saved .DOCX file will contain unreliable word count information ... But why ?<br /><br />It seems this issue&nbsp;is&nbsp;being caused by the fact that&nbsp;my code is receiving a handle&nbsp;that points at&nbsp;the old <strong>.DOC</strong> file when this event&nbsp;occurs:<br /><br /><span style="background-color: #ededed; font-family: courier new,courier; font-size: small;"><strong>Private Sub clsWd_DocumentBeforeSave(ByVal Doc As Document</strong> ..</span><br /><br />.. therefore Word computes the&nbsp;correct <strong>Statistics&nbsp;</strong>for a different file.&nbsp;This is not a problem in a normal <strong>Save</strong> action, but with a <strong>SaveAs</strong>, we get a handle on the new document only after we exit the <strong>BeforeSave </strong>event handler, and by that time it is too late for the code to act.<br /><br /><br /><strong>A less simple solution&nbsp;using&nbsp;VBA :) ...<br /></strong><br />There is no <strong>AfterSave</strong> event in Word, but I tried to simulate one:</p>
<p style="padding-left: 30px;">&gt;&nbsp; first I am saving the name of the present document (<strong>DOC</strong>);<br />&gt;&nbsp; then I am executing a delayed call to another function (<strong>timerCallback</strong>) where I check if the <br />&nbsp;&nbsp;&nbsp; active document (it becomes a&nbsp;<strong>DOCX</strong> format after <strong>SaveAs</strong> completes) has the same name<br />&nbsp;&nbsp; &nbsp;as the&nbsp;one I recorded before;<br />&gt;&nbsp; if the names are not identical, we probably executed a <strong>SaveAs</strong> so we trigger the computation <br />&nbsp;&nbsp;&nbsp; again;<br />&gt; &nbsp;I chose to introduce a 200ms delay .. but it doesn&rsquo;t seem to matter whether this interval is <br />&nbsp;&nbsp;&nbsp; smaller or larger; The <strong>Application.OnTime</strong> call schedules a timer callback at the first available <br />&nbsp;&nbsp;&nbsp; moment, but it is done only after the <strong>SaveAs</strong> function completes .. so by that time we already <br />&nbsp;&nbsp;&nbsp; have a new document name and can detect if we have to trigger a new computation;</p>
<p>The source code became more complex now &hellip; and with the added complexity, there may be problems. It&rsquo;s up to you to decide if you want to keep the first design and just instruct your users to perform a normal Save after they convert a document, or keep this more complicated design.</p>
<table style="background-color: #dedede; width: 550px; height: 10px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><span style="font-family: courier new,courier; font-size: small;"><strong><br /></strong></span></p>
<p>&nbsp;<span style="font-size: small;"><strong><span style="font-family: courier new,courier;">Module1</span></strong></span> <br /><span style="font-family: courier new,courier;">-----------------------------------------------------------------</span></p>
<p><span style="font-family: courier new,courier;">Option Explicit</span></p>
<p><span style="font-family: courier new,courier;">Public currentDocName As String<br /></span><span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;">Public clsWd As Class1<br /></span><br />Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)<br /></span></p>
<p><span style="font-family: courier new,courier;">Sub AutoExec()</span></p>
<p><span style="font-family: courier new,courier;">&nbsp;&nbsp; Debug.Print "WordFixStatistics: AutoExec fired"<br /></span><span style="font-family: courier new,courier;">&nbsp;&nbsp; Set clsWd = New Class1</span></p>
<p><span style="font-family: courier new,courier;">End Sub<br /></span></p>
<p><span style="font-family: courier new,courier;">Sub <span style="background-color: #ccffcc;">timerCallback</span>()</span></p>
<p><span style="font-family: courier new,courier;">&nbsp; DoEvents<br /></span><span style="font-family: courier new,courier;">&nbsp; Sleep 200</span></p>
<p><span style="font-family: courier new,courier;">&nbsp; Debug.Print "TimerCallback triggered."</span></p>
<p><span style="font-family: courier new,courier;">&nbsp; If Not (ActiveDocument Is Nothing) And Len(currentDocName) &gt; 0 Then&nbsp;<br /></span><span style="font-family: courier new,courier;"><br />&nbsp;&nbsp; If <span style="background-color: #ffff99;">ActiveDocument.Name &lt;&gt; currentDocName</span> Then<br /></span><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp; Debug.Print "TimerCallback: SaveAs detected. Old doc. name: " &amp; _<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;currentDocName &amp; ", New&nbsp;</span><span style="font-family: courier new,courier;">doc. name: " &amp; _<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActiveDocument.Name</span></p>
<p><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.Print "The document: " &amp; ActiveDocument.Name &amp; " has [" &amp; _<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;"><span style="background-color: #ffff99;">ActiveDocument.ComputeStatistics</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (wdStatisticCharactersWithSpaces) &amp; _<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;"]</span><span style="font-family: courier new,courier;">&nbsp;CharactersWithSpaces."<br />&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">End If<br /><br />&nbsp; </span><span style="font-family: courier new,courier;">End If</span></p>
<p><span style="font-family: courier new,courier;">End Sub<br /><br /><br /></span></p>
<p><span style="font-family: courier new,courier;"><strong>Class1<br /></strong></span><span style="font-family: courier new,courier;">------------------------------------------------------------------</span></p>
<p><span style="font-family: courier new,courier;">Option Explicit</span></p>
<p><span style="font-family: courier new,courier;">Public WithEvents clsWd As Application<br /></span><span style="font-family: courier new,courier;"><br />Private Sub Class_Initialize()</span></p>
<p><span style="font-family: courier new,courier;">&nbsp; Debug.Print "WordFixStatistics: Class_Initialize fired"<br /></span><span style="font-family: courier new,courier;">&nbsp; Set clsWd = Application</span></p>
<p><span style="font-family: courier new,courier;">End Sub</span></p>
<p><span style="font-family: courier new,courier;">Private Sub clsWd_DocumentBeforeSave(ByVal Doc As Document, _ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SaveAsUI As Boolean, _<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Cancel&nbsp;</span><span style="font-family: courier new,courier;">As Boolean)<br /></span><br /><span style="font-family: courier new,courier;">&nbsp; Debug.Print "WordFixStatistics: DocumentBeforeSave event fired"<br /></span><span style="font-family: courier new,courier;">&nbsp; Debug.Print "The document: " &amp; Doc.Name &amp; " has [" &amp; _</span></p>
<p><span style="font-family: courier new,courier;">&nbsp; Doc.ComputeStatistics(wdStatisticCharactersWithSpaces) &amp; _&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "] CharactersWithSpaces."</span></p>
<p><span style="font-family: courier new,courier;">&nbsp;&nbsp;<span style="background-color: #ffff99;">currentDocName = Doc.Name</span></span></p>
<p><span style="font-family: courier new,courier;">&nbsp; Application.OnTime Now(), "<span style="background-color: #ccffcc;">timerCallback</span>"</span></p>
<p><span style="font-family: courier new,courier;">End Sub</span></p>
</td>
</tr>
</tbody>
</table>
<p><br /><span style="font-family: %value;">Here is the output:</span></p>
<table style="background-color: #ffffff; width: 550px; height: 10px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/8270.7.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/8270.7.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/8270.7.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/8270.7.jpg" alt="" border="0" /></a></p>
</td>
</tr>
</tbody>
</table>
<p><span style="font-family: %value;"><br />As I have shown inside the areas highlighted with red, at first we open an older document format:<strong> rand1.doc</strong>. When we trigger a <strong>SaveAs</strong>, my <strong>BeforeSave</strong> code runs but it just counts the words inside this old file and exits. The <strong>Save</strong> action is automatically performed by Word, and only after we exit that internal function (which is not reachable to us) we notice that the <strong>ActiveDocument</strong> has changed to <strong>rand9.docx</strong>.</span></p>
<p>When the control returns to the VBA macros and they get their chance to run (the <strong>Application.OnTime</strong> schedules my task to execute at the first available slot), my code performs a comparison and detects the new document: <strong>rand9.docx</strong> which is highlighted in blue. It will trigger another word count and exit the routine.</p>
<p><span style="font-size: medium;"><strong><span style="font-family: %value;"><br />The End.<br /></span></strong></span><br />I hope you enjoyed my article.</p>
<p>&nbsp;</p>
<p>For any questions, feel free to add a comment or write me at <a href="mailto:cristib@microsoft.com">cristib@microsoft.com</a>.</p>
<p>&nbsp;</p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>OpenXML &amp; VSTO &amp; VBA - Finding a reliable mechanism for reading the correct value of CharactersWithSpaces 'extended-properties' in Word documents [part 1/2].</title>
      <link>https://docs.microsoft.com/archive/blogs/cristib/openxml-vsto-vba-finding-a-reliable-mechanism-for-reading-the-correct-value-of-characterswithspaces-extended-properties-in-word-documents-part-12</link>
      <pubDate>Sat, 30 Jun 2012 11:08:00 GMT</pubDate>
      <dc:creator><![CDATA[Cristian.Berescu]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cristib/2012/06/30/openxml-vsto-vba-finding-a-reliable-mechanism-for-reading-the-correct-value-of-characterswithspaces-extended-properties-in-word-documents-part-12/</guid>
      <description><![CDATA[&nbsp;




This article&nbsp;is split across&nbsp;two blog posts and&nbsp;this is&nbsp;part...]]></description>
      <content:encoded><![CDATA[<p>&nbsp;</p>
<table style="width: 597px; height: 1636px;" border="0">
<tbody>
<tr>
<td>
<p><span style="font-family: arial,helvetica,sans-serif; color: #888888;"><span style="font-size: small;">This article&nbsp;is split across&nbsp;two blog posts and&nbsp;this is&nbsp;part #1&nbsp;.. use <a title="Part2" href="https://blogs.msdn.com/b/cristib/archive/2012/07/30/openxml-vsto-vba-finding-a-reliable-mechanism-for-reading-the-correct-value-of-characterswithspaces-_2700_extended_2d00_properties_2700_-in-word-documents-part2.aspx" target="_blank">this link</a> to go to part #2.</span></span></p>
<p><span style="font-family: arial,helvetica,sans-serif;"><span style="font-size: small;"><br />There are many&nbsp;scenarios when we&nbsp;have to know exactly how many words,&nbsp;pages, paragraphs&nbsp;or characters are found in a certain document:<br /><br />&nbsp;&nbsp; &gt;&nbsp;</span><span style="font-size: small;"><span>we might be&nbsp;developing a tool which searches through files;&nbsp;If&nbsp;we&nbsp;want to&nbsp;add <span>OpenXML</span> files to </span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; its list of known formats,&nbsp;then&nbsp;it&nbsp;would be nice&nbsp;it we could offer a progress estimation when&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; users&nbsp;search inside a document (example: display&nbsp;[<strong>x%</strong> completed&nbsp;out of <strong>yyyy&nbsp;</strong>word count);<br /><br />&nbsp;&nbsp; &gt; or you may need to count the number of words for a company that translates documents, to <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; know how much&nbsp;they need to charge&nbsp;customers;<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp; &gt; in case some&nbsp;public&nbsp;institution builds a web-page where documents can be uploaded; If there <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; is&nbsp;a requirement /&nbsp;limitation that&nbsp;forces&nbsp;any uploaded document to contain up to&nbsp;<strong>xxxx</strong> words, <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; then we need a code that reliably reads this information;<br /><br />&nbsp;&nbsp;&nbsp;.. and there are many other scenarios where counting words comes in handy.&nbsp;</span></span></p>
<p><span style="font-family: arial,helvetica,sans-serif; font-size: small;"><br /><span>Let's assume that we have to count the number of words in an <span>OpenXML</span> Word document on&nbsp;a server. </span><br /><br />If the&nbsp;'word counter' tool runs on the server side, then you can't use&nbsp;COM automation,&nbsp;as this action&nbsp;would place you in an unsupported scenario.&nbsp;</span></p>
<table style="background-color: #dedede; width: 550px; height: 10px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><span style="font-family: courier new,courier; font-size: small;"><span>public&nbsp;void <span>WordInteropDocStatistics</span>()</span></span><br />{<br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;object missing = System.Reflection.Missing.Value;</span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;Microsoft.Office.<span>Interop</span>.Word.Application <span>WdApp</span>;</span><br />&nbsp;Microsoft.Office.Interop.Word.Document&nbsp;&nbsp;&nbsp; WdDoc;<br />&nbsp;int&nbsp;CharactersIncludingSpaces;<br /><br /><span>&nbsp;WdApp =&nbsp;new Microsoft.Office.<span>Interop</span>.Word.Application();</span></span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;WdDoc&nbsp;=&nbsp;WdApp.Documents.Open(PathName,&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ref missing,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref missing,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref missing,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref missing,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref missing,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref missing,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref missing,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref missing,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref missing,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref missing,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref missing,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref missing,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref missing,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref missing,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref missing);</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;<br /></span><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;CharactersIncludingSpaces = <span>WdDoc</span>.</span><span style="background-color: #ffff99;">ComputeStatistics</span>(<span style="background-color: #ccffcc;"><span>Microsoft.Office.<span>Interop</span>.Word.<span>WdStatistic</span></span></span>.<br />&nbsp;<span style="background-color: #ccffcc;"><span><span>wdStatisticCharactersWithSpaces</span></span></span>,&nbsp;ref missing);</span><br /><span style="font-family: courier new,courier; font-size: small;"><br />&nbsp;WdApp</span><span style="font-family: courier new,courier; font-size: small;">.Quit(false,&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ref missing,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref missing);</span><br /><span style="font-family: courier new,courier; font-size: small;"><br /><span>&nbsp;System.<span>Runtime</span>.<span>InteropServices</span>.Marshal.<span>ReleaseComObject</span>( <span>WdApp</span> );</span><br /></span><span style="font-family: courier new,courier; font-size: small;">}</span></p>
</td>
</tr>
</tbody>
</table>
<p><br /><span style="font-family: arial,helvetica,sans-serif;"><span>So what&nbsp;alternative do we have? Answer: <strong>use <span>OpenXML</span> API.</strong><br /><br /><span>A quick search on the <span>internet</span> reveals this code snippet:</span></span></span></p>
<table style="background-color: #dedede; width: 550px; height: 10px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><span style="font-family: courier new,courier; font-size: small;">public&nbsp;void WordOpenXMLDocStatistics()</span><br />{<br /><span style="font-family: courier new,courier; color: #000000; font-size: small;">&nbsp;<span style="font-family: courier new,courier; font-size: small;">XmlDocument&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xmlDocStructure;<br /></span></span><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;WordprocessingDocument&nbsp;&nbsp;&nbsp;&nbsp; <span>wordDocContainer</span>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;ExtendedFilePropertiesPart extPropPart;&nbsp;<br /><span>&nbsp;int <span>CharactersIncludingSpaces</span>;&nbsp;</span><br /><br /><span>&nbsp;wordDocContainer&nbsp;= <span>WordprocessingDocument</span>.Open(<span>PathName</span>, false);</span></span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;extPropPart&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&nbsp;wordDocContainer.ExtendedFilePropertiesPart;</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;<br /><span>&nbsp;xmlDocStructure&nbsp;&nbsp;= new <span>XmlDocument</span>();</span></span><span style="font-family: courier new,courier; font-size: small;"><br />&nbsp;xmlDocStructure.Load(extPropPart.GetStream());</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;<br />&nbsp;CharactersIncludingSpaces = <br /><span>&nbsp;int.Parse(<span>xmlDocStructure</span>.<span>GetElementsByTagName</span>(</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"CharactersWithSpaces").Item(0).InnerText);</span><br /><span style="font-family: courier new,courier; font-size: small;">}</span></p>
</td>
</tr>
</tbody>
</table>
<p><br />But&nbsp;will it work&nbsp;as expected? Does it report the same number of words as displayed inside MS&nbsp;Word editor? <br />Answer: <strong><span style="color: #ff0000;">Yes, it works but&nbsp;it's not reliable</span>.</strong>&nbsp;&nbsp;<strong>Sometimes it gives the expected results, sometimes it returns slightly different numbers ....</strong></p>
<p><span style="font-family: arial,helvetica,sans-serif;"><span><br /><br /></span></span></p>
<p><strong>Triggering the Word statistics mismatch problem</strong></p>
<p><span style="font-family: arial,helvetica,sans-serif;"><span><span style="color: #ff0000;"><strong>1.</strong></span>&nbsp;&nbsp; Just create a new Word document, type "<strong>=rand(1)</strong>" (without the quotes), then&nbsp;press <strong>Enter</strong> key;<br /><span style="color: #ff0000;"><strong>2.</strong></span>&nbsp;&nbsp;&nbsp;Save it&nbsp;file using <strong>.docx</strong>&nbsp;type, then close it;<br /><span style="color: #ff0000;"><strong>3.&nbsp;&nbsp;&nbsp;</strong><span style="color: #000000;">Open the file using an OpenXML editor, or r</span><span style="color: #000000;">ename the document from <strong>.docx</strong> to <strong>.zip</strong>, open the <strong>docProps</strong> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; folder and then edit the <strong>app.xml</strong>&nbsp;file;&nbsp;&nbsp;Note the values of these XML items:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp; <span style="background-color: #ebebeb;">Pages</span>;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt;&nbsp; <span style="background-color: #ebebeb;">Words</span>;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt;&nbsp;&nbsp;<span style="background-color: #ebebeb;">Characters</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp;<span style="background-color: #ebebeb;"> Lines</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp;&nbsp;<span style="background-color: #ebebeb;">Paragraphs</span>;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp;&nbsp;<span style="background-color: #ebebeb;">CharactersWithSpaces</span>;</span></span><br /><span style="color: #ff0000;"><strong>4.</strong></span>&nbsp;&nbsp; Close the editor, or if you renamed the file to <strong>.zip</strong>, restore its original extension; Open it again in Word;<br /><span style="color: #ff0000;"><strong>5.</strong></span>&nbsp;&nbsp; On the <strong>Review</strong> tab, in the <strong>Proofing</strong> group, click <strong>Word Count</strong>;<br /><span style="color: #ff0000;"><strong>6.&nbsp;&nbsp; </strong><span style="color: #000000;">Compare the statistics in the<strong> Word Count</strong> dialog with those noted from the <strong>app.xml</strong> file;</span></span></span></span></p>
<table style="width: 550px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0488.1.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0488.1.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0488.1.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0488.1.jpg" alt="" border="0" /></a></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;Result: we easily notice that the numbers are different ...<br /><br /><span style="color: #ff0000;"><strong>7.&nbsp;&nbsp; </strong><span style="color: #000000;">Close the document again, you should be prompted to <strong>Save</strong> it. Go ahead and click <strong>OK</strong> to store the updated <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; document information;<br /><span style="color: #ff0000;"><strong>8.</strong></span>&nbsp;&nbsp; Open&nbsp;its internal OpenXML structure and this time you should see that the numbers match;&nbsp;</span></span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span style="font-family: arial,helvetica,sans-serif;"><br /></span></span></p>
<p><strong>The Word Count difference is&nbsp;by-design</strong></p>
<p>&nbsp;&nbsp;&nbsp;&gt;&nbsp; MS Word has a set of tasks that are scheduled to run when the application is in idle mode;<br />&nbsp;&nbsp; &gt;&nbsp; the <strong>Compute Document Statistics</strong> task has a low priority;<br />&nbsp;&nbsp; &gt;&nbsp; when the user changes&nbsp;content inside a document, Word just estimates the number of characters, <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paragraphs ... etc. The data is stored in a special field inside a documents and is marked as <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'estimated';<br />&nbsp;&nbsp; &gt;&nbsp; when we save a file and the document statistics task has not yet been executed, we just get an <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; estimated value inside the <strong>xmlProperties.GetElementsByTagName("CharactersWithSpaces")</strong> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OpenXML field;</p>
<p style="text-align: justify;">&nbsp;Our Product Group's developers were notified about the inconsistency between <strong>OpenXML</strong> and <strong>COM&nbsp;<br />&nbsp;ObjectModel</strong> results and they replied that it was their decision to store approximate values in OpenXML.<br />&nbsp;&nbsp;<br />The main reason&nbsp;why&nbsp;things are happening in this way&nbsp;is<span style="color: #ff0000;">&nbsp;<span style="background-color: #ffffff;"><strong>performance</strong></span></span>. For a small file, the time needed to compute <strong>Word Count</strong> statistics is not a problem, but for a document with thousands of pages, it may take several seconds or even minutes. If&nbsp;Word application was set to compute all the statistics in real-time, before a save (or more often), the end-users would surely complain about application hangs during saves. <br /><br />So the Product Group decided to&nbsp;compromise between speed and accuracy. As you have noticed, the difference between the estimated values and the real values are not bigger than 1 ~ 2% which is more than enough for regular users.&nbsp;</p>
<p>&nbsp;</p>
<p><strong>Can we&nbsp;obtain&nbsp;100%&nbsp;reliable statistics?</strong><br /><br /><span style="color: #000080;"><strong>Method&nbsp;#1:</strong></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The OpenXML data can be forced to update: when Word receives a query about the statistics (through&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;the <strong>Ribbon</strong> graphical interface or the <strong>VBA ObjectModel</strong>), it computes those results and always reports <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the correct numbers.<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The only difficult part is finding a way to trigger the update every time, so that we are sure that the&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;information stored in the file is up to data.<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>Advantages:&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt; easy to implement;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp;OpenXML code is very simple;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; works&nbsp;for all kinds of input files ... even very complex ones (containing <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; embedded charts, shapes, nested tables ..etc);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Disadvantages: <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; we can only force the Word Count update if we rely&nbsp;on a VBA / VSTO<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add-in&nbsp;installed on the client-side;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt; somehow, the&nbsp;automated&nbsp;Statistics Update&nbsp;Add-in has to be deployed to all&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end-users;&nbsp;</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p style="text-align: justify;"><span style="color: #000080;"><strong>Method&nbsp;#2:<br /><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></strong><span style="color: #000000;">Write our own OpenXML code and count the words ourselves.<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>Advantages:&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt; no need for 'helper' tools;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Disadvantages: <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp;because the OpenXML format is VERY complex, the code will run reliably<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; only for basic input files; If you want to extend the program to be able to&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handle all&nbsp;kinds&nbsp;of input documents you will find that the <span style="color: #ff0000;">complexity of the&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; code increases&nbsp;</span><span style="color: #ff0000;">up to the point where it is not fasible to continue</span> with the&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;project (you will very&nbsp;likely&nbsp;be forced to write individual code rules for targeting<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;all kinds of exceptions&nbsp;and special conditions for XML text tags, that may <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; appear in&nbsp;different&nbsp;combinations);<br /></strong><br /></span></span></p>
<p style="text-align: justify;"><span style="font-family: courier new,courier; font-size: small;"><span style="font-family: arial,helvetica,sans-serif;">Hmmm ... something tells me that when you read&nbsp;the lines about the disadvantages of using <strong>Method #2</strong>, some wheels already started turning in your head. You must be thinking: "<em>there must be some trick to get all the words ...</em>"<span style="font-family: arial,helvetica,sans-serif;">.<br /><br />OK, let me show you how you get started on this path ... if you decide that this approach is right for you, then you can further develop my sample code:</span></span></span></p>
<table style="background-color: #000000; width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td style="text-align: left;">
<p><span style="font-family: courier new,courier; color: #ffffff; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000; font-size: medium;"><strong>DISCLAIMER</strong></span><br /><br /></span><span style="font-family: courier new,courier; color: #ffffff;">Sample Code is provided for the purpose of illustration only and is not intended to be used in a production environment!</span></p>
<p><span style="font-family: courier new,courier; color: #ffffff;">THIS SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,&nbsp;</span><span style="font-family: courier new,courier; color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.</span></p>
<p><span style="font-family: courier new,courier; color: #ffffff;">We grant You a nonexclusive, royalty-free right to use and modify the<br />Sample Code and to reproduce and distribute the object</span><span style="font-family: courier new,courier; color: #ffffff;">&nbsp;code form of <br />the Sample Code, provided that. You agree: <br />&nbsp;&nbsp; (i)&nbsp;&nbsp; to not use Our name, logo, or trademarks to market Your <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; software&nbsp;</span><span style="font-family: courier new,courier; color: #ffffff;">product&nbsp;in which the Sample Code is embedded; <br />&nbsp;&nbsp; (ii)&nbsp; to include a valid copyright notice on Your software<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;product&nbsp;in&nbsp;which the&nbsp;</span><span style="font-family: courier new,courier; color: #ffffff;">Sample Code is embedded; and <br />&nbsp;&nbsp; (iii) to indemnify, hold harmless, and defend Us and Our <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; suppliers&nbsp;from&nbsp;and against any claims&nbsp;</span><span style="font-family: courier new,courier; color: #ffffff;">or lawsuits,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;including&nbsp;attorneys&rsquo;&nbsp;fees, that&nbsp;arise or result from the<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;use or&nbsp;distribution of&nbsp;t</span><span style="font-family: courier new,courier; color: #ffffff;">he Sample Code.</span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;<span style="background-color: #ffffff;">Code sample from below can be downloaded from</span> <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/51002E00Program2E00cs" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/5100_2E00_Program_2E00_cs">this link</a>.</p>
<table style="background-color: #dedede; width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><span style="font-family: courier new,courier; color: #0000ff;">using </span><span style="font-family: courier new,courier;">System;<br /></span><span style="font-family: courier new,courier; color: #0000ff;">using </span><span style="font-family: courier new,courier;">System.Collections.Generic;<br /></span><span style="font-family: courier new,courier; color: #0000ff;">using </span><span style="font-family: courier new,courier;">System.Linq;<br /></span><span style="font-family: courier new,courier; color: #0000ff;">using </span><span style="font-family: courier new,courier;">System.Text;<br /></span><span style="font-family: courier new,courier; color: #0000ff;">using </span><span style="font-family: courier new,courier;">DocumentFormat.OpenXml.Packaging;<br /></span><span style="font-family: courier new,courier; color: #0000ff;">using </span><span style="font-family: courier new,courier;">DocumentFormat.OpenXml.Wordprocessing;<br /></span><span style="font-family: courier new,courier; color: #0000ff;">using </span><span style="font-family: courier new,courier;">System.Xml;<br /></span><span style="font-family: courier new,courier; color: #0000ff;">using </span><span style="font-family: courier new,courier;">System.IO;</span></p>
<p><span style="font-family: courier new,courier; color: #0000ff;">namespace </span><span style="font-family: courier new,courier;">ConsoleApp_WordCount_OpenXML<br /></span><span style="font-family: courier new,courier;">{<br />&nbsp;</span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">class </span></span><span style="color: #2b91af;"><span style="color: #2b91af;">Program<br />&nbsp;</span></span></span><span style="font-family: courier new,courier;">{&nbsp;<br />&nbsp;</span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">static</span></span> System.IO.<span style="color: #2b91af;"><span style="color: #2b91af;">StreamWriter</span></span> fileOutput;<br /><br />&nbsp;<span style="color: #0000ff;"><span style="color: #0000ff;">static</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">void</span></span> Main(<span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span>[] args)<br />&nbsp;</span><span style="font-family: courier new,courier;">{<br />&nbsp; </span><span style="font-family: courier new,courier;">fileOutput = </span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span> System.IO.<span style="color: #2b91af;"><span style="color: #2b91af;">StreamWriter</span></span>(<span style="color: #a31515;"><span style="color: #a31515;">"<span style="background-color: #ffff99;">C:\\ConsoleApp_WordCount <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OpenXML.log</span>"</span></span>, <span style="color: #0000ff;"><span style="color: #0000ff;">true</span></span>);<br />&nbsp;<br />&nbsp;<span style="color: #008000;"><span style="color: #008000;">//https://msdn.microsoft.com/en-us/library/cc974107.aspx<br />&nbsp;</span></span><span style="color: #008000;"><span style="color: #008000;">//https://www.devx.com/dotnet/Article/42221/1954<br /></span></span><span style="color: #0000ff;"><span style="color: #0000ff;"><br />&nbsp;string</span></span> document;<br />&nbsp;</span><span style="font-family: courier new,courier;">document = <span style="color: #a31515;"><span style="color: #a31515;">@"<span style="background-color: #ffff99;">C:\Test\WordCountOpenXML\Sample.docx</span>"</span></span>;</span></p>
<p><span style="font-family: courier new,courier;">&nbsp;fileOutput.WriteLine(<br />&nbsp;</span><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"--------------------------------------------------------"</span></span>);<br /></span><span style="font-family: courier new,courier;">&nbsp;fileOutput.WriteLine(</span><span style="font-family: courier new,courier;"><span style="color: #2b91af;"><span style="color: #2b91af;">DateTime</span></span>.Now.ToString() + <span style="color: #a31515;"><span style="color: #a31515;">" Opened input file: "<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>&nbsp;+ document);<br /><br />&nbsp;<span style="color: #008000;"><span style="color: #008000;">//Namespace manager so we can identify the tags according to <br />&nbsp;&nbsp; namespace<br /><br />&nbsp;</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">const </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> wordmlNamespace =&nbsp;<span style="color: #a31515;"><span style="color: #a31515;"><br />&nbsp;"<span style="text-decoration: underline;">https://schemas.openxmlformats.org/wordprocessingml/2006/main</span>"</span></span>;</span></p>
<p><span style="font-family: courier new,courier;">&nbsp;<span style="color: #4682b4;">NameTable</span> nt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = </span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span> <span style="color: #4682b4;">NameTable</span>();<br />&nbsp;</span><span style="font-family: courier new,courier;"><span style="color: #4682b4;">XmlNamespaceManager</span> nsManager = </span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span> <span style="color: #4682b4;">XmlNamespaceManager</span>(nt);<br />&nbsp;</span><span style="font-family: courier new,courier;">nsManager.AddNamespace(</span><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"w"</span></span>, wordmlNamespace);</span></p>
<p><span style="font-family: courier new,courier;">&nbsp;</span><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">//open the Word document<br />&nbsp;</span></span></span><span style="font-family: courier new,courier;"><span style="color: #4682b4;">WordprocessingDocument</span> wordDoc = <span style="color: #4682b4;">WordprocessingDocument</span>.Open(document,</span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">true</span></span>);<br />&nbsp;</span><span style="font-family: courier new,courier;"><span style="color: #4682b4;">MainDocumentPart</span> mainPart = wordDoc.MainDocumentPart;</span></p>
<p><span style="font-family: courier new,courier;">&nbsp;</span><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">//identify the text nodes<br />&nbsp;</span></span></span><span style="font-family: courier new,courier;"><span style="color: #4682b4;">XmlNodeList</span> textnodes = </span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">null</span></span>;<br />&nbsp;</span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> nodeText;<br />&nbsp;</span><span style="font-family: courier new,courier;"><span style="color: #4682b4;">XmlDocument</span> mainpartdoc = </span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span> <span style="color: #4682b4;">XmlDocument</span>(nt);<br /><br />&nbsp;</span><span style="font-family: courier new,courier;">mainpartdoc.Load(mainPart.GetStream());<br />&nbsp;</span><span style="font-family: courier new,courier;">textnodes = mainpartdoc.SelectNodes(</span><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"//w:t"</span></span>, nsManager);<br /><br />&nbsp;<span style="color: #008000;"><span style="color: #008000;">//loop through all text nodes<br />&nbsp;</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">int</span></span> counter = 0;<br />&nbsp;<span style="color: #0000ff;"><span style="color: #0000ff;">int</span></span> strLen = 0;<br />&nbsp;<br />&nbsp;<span style="color: #0000ff;"><span style="color: #0000ff;">foreach</span></span> (<span style="color: #4682b4;">XmlNode</span> textnode <span style="color: #0000ff;"><span style="color: #0000ff;">in</span></span> textnodes)<br />&nbsp; </span><span style="font-family: courier new,courier;">{<br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">nodeText = textnode.FirstChild.InnerText;</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">&nbsp;/* <br />&nbsp;&nbsp; strLen += nodeText.Length; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&gt; the 'FirstChild.InnerText' data may contain characters from <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Unicode;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="color: #008000;"><span style="color: #008000;">&nbsp;&gt;&gt; in this case, the information returned by the .Length method is&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wrong;<br /><br /><br /></span></span><span style="color: #008000;"><span style="color: #008000;">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&gt;&gt; we will use the 'String.ToCharArray()' to get a stream of Bytes, <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; then we count all non-empty characters;<br />&nbsp;*/</span></span></span></p>
<p><span style="font-family: courier new,courier;">&nbsp; strLen += GetBytesCount_Unicode(nodeText);</span></p>
<p>&nbsp;&nbsp; <span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">if</span></span> (nodeText.IndexOf(<span style="color: #a31515;"><span style="color: #a31515;">' '</span></span>, 0) &gt;= 0)<br /></span><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span>[] strWords = nodeText.Split(<span style="color: #a31515;"><span style="color: #a31515;">' '</span></span>);&nbsp;<br /><span style="color: #008000;"><span style="color: #008000;">&nbsp;&nbsp;&nbsp; /* &gt;&gt; the 'String.Split(&lt;blank&gt;)' method is unreliable!<br />&nbsp;&nbsp;&nbsp; </span></span><span style="color: #008000;"><span style="color: #008000;">&nbsp;&nbsp; &gt;&gt; it will fail to recognize Unicode characters and will&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</span></span></span><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">return a wrong number of array elements;<br />&nbsp;&nbsp;&nbsp; </span></span><span style="color: #008000;"><span style="color: #008000;">&nbsp;&nbsp; &gt;&gt; I used it here just to show the characters in my program's&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; output&nbsp;Console;<br />&nbsp;&nbsp;&nbsp; */</span></span></span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">&nbsp;&nbsp;&nbsp; /* if you put a break-point here and evaluate these 2 Byte arrays,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">&nbsp;you&nbsp;will notice that </span></span><span style="color: #008000;"><span style="color: #008000;">when this string '</span></span></span><span style="color: #008000;">&raquo;</span> <span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">' is parsed, the first<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">&nbsp;byte array contains:</span></span></span></p>
<p><span style="background-color: #dedede; font-family: courier new,courier; color: #008000;"><span style="background-color: #ffff00;"><span style="background-color: #dedede;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> bWordsAsc[0] = 63 (?)</span><br /></span><span style="background-color: #dedede; font-family: courier new,courier; color: #008000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bWordsAsc[1] = 32 (&lt;blank&gt;)<br /></span></p>
<p><span style="background-color: #dedede; font-family: courier new,courier; color: #008000;">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;... which is obviously not correct, because the character '&raquo;' is&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; replaced by a '?' symbol, whereas the second array contains:</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background-color: #dedede; font-family: courier new,courier; color: #008000;"><span style="background-color: #ffff00;">bWordsUnicode[0] = 187 ('&raquo;')</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="background-color: #dedede; font-family: courier new,courier; color: #008000;">bWordsUnicode[1] = 0<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="background-color: #dedede; font-family: courier new,courier; color: #008000;">bWordsUnicode[2] = 32 (&lt;blank&gt;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="background-color: #dedede; font-family: courier new,courier; color: #008000;">bWordsUnicode[3] = 0<br /></span><span style="background-color: #dedede; font-family: courier new,courier; color: #008000; font-size: small;">&nbsp;&nbsp;&nbsp;*/</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">byte</span></span>[] <span style="background-color: #ffff00;">bWordsAsc&nbsp;&nbsp;&nbsp;&nbsp;<span style="background-color: #dedede;">&nbsp;</span></span>= <span style="color: #2b91af;"><span style="color: #2b91af;">Encoding</span></span>.ASCII.GetBytes(nodeText);&nbsp;<br /><span style="color: #0000ff;"><span style="color: #0000ff;">&nbsp;&nbsp; byte</span></span>[] <span style="background-color: #ffff00;">bWordsUnicode</span> = GetBytes(nodeText);<br /><br />&nbsp;&nbsp; <span style="color: #0000ff;"><span style="color: #0000ff;">foreach</span></span> (<span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> strWd <span style="color: #0000ff;"><span style="color: #0000ff;">in</span></span> strWords)<br />&nbsp;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: courier new,courier;">{<br />&nbsp;&nbsp; </span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">if</span></span> (strWd.Length &gt; 0)<br />&nbsp;&nbsp;&nbsp;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: courier new,courier;">{<br />&nbsp;&nbsp; </span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: courier new,courier;"><span style="color: #2b91af;"><span style="color: #2b91af;">Console</span></span>.WriteLine(<span style="color: #a31515;"><span style="color: #a31515;">"Word #"</span></span> + <span style="color: #2b91af;"><span style="color: #2b91af;">Convert</span></span>.ToString(counter++) + <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #a31515;"><span style="color: #a31515;">"\t\t Text: "</span></span> + strWd);</span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: courier new,courier;">&nbsp; }<br />&nbsp;</span><span style="font-family: courier new,courier;">}<br /></span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">else<br />&nbsp;</span></span></span><span style="font-family: courier new,courier;">{<br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier;"><span style="color: #2b91af;"><span style="color: #2b91af;">Console</span></span>.WriteLine(<span style="color: #a31515;"><span style="color: #a31515;">"Word #"</span></span> + <span style="color: #2b91af;"><span style="color: #2b91af;">Convert</span></span>.ToString(counter++) + <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #a31515;"><span style="color: #a31515;">"\t\t Text: "</span></span> + nodeText);<br />&nbsp;</span><span style="font-family: courier new,courier;">}<br /></span><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;">wordDoc.Close();</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #2b91af;"><span style="color: #2b91af;">Console</span></span>.WriteLine(<span style="color: #a31515;"><span style="color: #a31515;">"------------------------------------------------------<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \r\nStatistics:\r\n"</span></span>);<br /><span style="color: #2b91af;"><span style="color: #2b91af;">Console</span></span>.WriteLine(<span style="color: #a31515;"><span style="color: #a31515;">"Total characters : "</span></span> + <span style="color: #2b91af;"><span style="color: #2b91af;">Convert</span></span>.ToString(strLen));<br /><span style="color: #2b91af;"><span style="color: #2b91af;">Console</span></span>.WriteLine(<span style="color: #a31515;"><span style="color: #a31515;">"CharactersWithSpaces / 6 : "</span></span> + <span style="color: #2b91af;"><span style="color: #2b91af;">Convert</span></span>.ToString<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (strLen /&nbsp;6) + <span style="color: #a31515;"><span style="color: #a31515;">"\r\n"</span></span>);</span></p>
<p><span style="font-family: courier new,courier;">fileOutput.Close();</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #2b91af;"><span style="color: #2b91af;">Console</span></span>.WriteLine(<span style="color: #a31515;"><span style="color: #a31515;">"Press any key to continue.."</span></span>);<span style="color: #2b91af;"><span style="color: #2b91af;">Console</span></span>.ReadKey();</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">//END OF Main<br /><br /></span></span><span style="color: #0000ff;"><span style="color: #0000ff;">static</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">byte</span></span>[] GetBytes(<span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> str)<br /></span><span style="font-family: courier new,courier;">{<br />&nbsp; </span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">byte</span></span>[] bytes = <span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">byte</span></span>[str.Length * <span style="color: #0000ff;"><span style="color: #0000ff;">sizeof</span></span>(<span style="color: #0000ff;"><span style="color: #0000ff;">char</span></span>)];<br />&nbsp; </span><span style="font-family: courier new,courier;">System.</span><span style="font-family: courier new,courier;"><span style="color: #2b91af;"><span style="color: #2b91af;">Buffer</span></span>.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);<br />&nbsp; <span style="color: #0000ff;"><span style="color: #0000ff;">return</span></span> bytes;<br /></span><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;"><br />static </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">int</span></span> GetBytesCount_Unicode(<span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> str)<br /></span><span style="font-family: courier new,courier;">{<br />&nbsp;</span><span style="font-family: courier new,courier;"><span style="color: #0000ff;"><span style="color: #0000ff;">byte</span></span>[] bytes = <span style="color: #0000ff;"><span style="color: #0000ff;">new</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">byte</span></span>[str.Length * <span style="color: #0000ff;"><span style="color: #0000ff;">sizeof</span></span>(<span style="color: #0000ff;"><span style="color: #0000ff;">char</span></span>)];<br />&nbsp;</span><span style="font-family: courier new,courier;">System.</span><span style="font-family: courier new,courier;"><span style="color: #2b91af;"><span style="color: #2b91af;">Buffer</span></span>.BlockCopy(<span style="background-color: #ffff00;">str.ToCharArray()</span>, 0, bytes, 0, bytes.Length);<br />&nbsp;<span style="color: #0000ff;"><span style="color: #0000ff;">int</span></span> i = 0;<br />&nbsp;<span style="color: #0000ff;"><span style="color: #0000ff;">int</span></span> counter = 0;</span></p>
<p><span style="font-family: courier new,courier;">&nbsp;fileOutput.WriteLine(</span><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"---------------------------------------------<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ---------------------------"</span></span>);<br /><br />&nbsp;<span style="color: #0000ff;"><span style="color: #0000ff;">for</span></span> (i = 0; i &lt; bytes.Length; i++)<br />&nbsp;&nbsp;</span><span style="font-family: courier new,courier;">{<br />&nbsp;&nbsp; </span><span style="font-family: courier new,courier;"><span style="color: #008000;"><span style="color: #008000;">//Console.WriteLine("\t\t &gt; bytes[{0}] = {1}", Convert.ToString(i), (char)<br />&nbsp;&nbsp;&nbsp;&nbsp; bytes[i]);<br /><br />&nbsp;&nbsp; </span></span></span><span style="font-family: courier new,courier;">fileOutput.WriteLine(</span><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"\t\t &gt; bytes[{0}] = {1} \t CharCode: {2}"</span></span>,<span style="color: #2b91af;"><span style="color: #2b91af;">&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Convert</span></span>.ToString(i), (<span style="color: #0000ff;"><span style="color: #0000ff;">char</span></span>)bytes[i], bytes[i]);<br />&nbsp;</span><span style="font-family: courier new,courier; color: #008000;"><br />&nbsp;&nbsp;//when counting the characters without spaces, enable the line from below&nbsp;<br />&nbsp;&nbsp;</span><span style="font-family: courier new,courier;"><br />&nbsp;&nbsp;<span style="color: #008000;"><span style="color: #008000;">//if (bytes[i] != 0 &amp;&amp; bytes[i] != 32 &amp;&amp; bytes[i] != 160)&nbsp;<br />&nbsp;&nbsp;// 160 = Non-breaking space: <br />&nbsp;&nbsp;&nbsp;&nbsp; <a href="https://en.wikipedia.org/wiki/Non-breaking_space">https://en.wikipedia.org/wiki/Non-breaking_space</a><br />&nbsp; // 32 = space, 160 = non-breaking space)<br /><br />&nbsp; </span></span><span style="color: #0000ff;"><span style="color: #0000ff;">if</span></span> (bytes[i] != 0 )<br /></span><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">counter++;<br />&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier;">}<br />&nbsp;</span><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;">&nbsp;fileOutput.WriteLine(</span><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"---------------------------------------<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ---------------------------------"</span></span>);<br />&nbsp;</span><span style="font-family: courier new,courier;">fileOutput.WriteLine(</span><span style="font-family: courier new,courier;"><span style="color: #a31515;"><span style="color: #a31515;">"Subtotal characters count: {0}\r\n"</span></span>,&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #2b91af;"><span style="color: #2b91af;">Convert</span></span>.ToInt16(counter));&nbsp;<br />&nbsp;<span style="color: #0000ff;"><span style="color: #0000ff;">return</span></span> counter;<br />&nbsp;</span><span style="font-family: courier new,courier;">}<br /></span><span style="font-family: courier new,courier;">}</span></p>
<p><span style="font-family: courier new,courier;">}</span></p>
</td>
</tr>
</tbody>
</table>
<p><br /><strong>How&nbsp;the code&nbsp;works?</strong><br /><br />&gt;&nbsp; first of all,&nbsp;we have to start with&nbsp;a&nbsp;very basic&nbsp;sample file and we must&nbsp;try to get the code to run for that input;<br />&gt;&nbsp; for my tests, I used a plain text document, containing 2 paragraphs (produced using the <span style="background-color: #dedede; font-family: courier new,courier;"><strong>=rand(1)</strong></span> command); The 2nd paragraph was truncated .. it&nbsp;contains a special Unicode character: <span style="background-color: #dedede;">&raquo;<span style="background-color: #ffffff;">&nbsp; which is needed to demonstrate an issue that&nbsp;is&nbsp;very likely&nbsp;to be&nbsp;encountered, when&nbsp;building a reliable program that counts characters or </span><span style="background-color: #ffffff;">words;</span></span></p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0726.6.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0726.6.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0726.6.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0726.6.jpg" alt="" border="0" /></a></p>
</td>
</tr>
</tbody>
</table>
<p><br />&gt;&nbsp; we need analyze the internal structure of an<strong> OpenXML</strong> file; There are several <strong>OpenXML</strong> viewers<br />&nbsp;&nbsp; &nbsp;available,&nbsp;but I used the one that comes with&nbsp;the SDK: <strong>OpenXML Productivity Tool</strong>;</p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2158.2.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2158.2.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2158.2.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2158.2.jpg" alt="" border="0" /></a></p>
</td>
</tr>
</tbody>
</table>
<p>&gt;&nbsp; a&nbsp;<strong>WordprocessingML</strong> document contains a body element (named <span style="background-color: #d8d8d8;">w:body</span>) that contains all paragraph (<span style="background-color: #dedede;">w:p</span>)structures. Each paragraph contains one or more <strong>text runs</strong> (named <span style="background-color: #d8d8d8;">w:r</span>). Each <strong>text run</strong> contains one or more text nodes (named <span style="background-color: #d8d8d8;">w:t</span>).</p>
<table style="background-color: #f5f5f5; width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><span style="font-family: courier new,courier; color: #800000;"><span style="color: #000000;">&lt;</span>?xml </span><span style="font-family: courier new,courier;"><span style="color: #ff0000;"><span style="color: #ff0000;">version</span></span>="<span style="color: #0000ff;"><span style="color: #0000ff;">1.0</span></span>"<span style="color: #ff0000;"><span style="color: #ff0000;"> encoding</span></span>="<span style="color: #0000ff;"><span style="color: #0000ff;">UTF-8</span></span>"<span style="color: #ff0000;"><span style="color: #ff0000;"> standalone</span></span>="<span style="color: #0000ff;"><span style="color: #0000ff;">yes</span></span>"?&gt;<br /></span><span style="font-family: courier new,courier; color: #800000;"><span style="color: #000000;">&lt;</span>w:document<br /></span><span style="font-family: courier new,courier;"><span style="color: #ff0000;"><span style="color: #ff0000;">&nbsp; xmlns:ve</span></span>=<span style="color: #0000ff;"><span style="color: #0000ff;"><a href="https://schemas.openxmlformats.org/markup-compatibility/2006">https://schemas.openxmlformats.org/markup-compatibility/2006</a></span></span><span style="color: #ff0000;"><span style="color: #ff0000;">&nbsp;&nbsp; <br />&nbsp; xmlns:o</span></span>="<span style="color: #0000ff;"><span style="color: #0000ff;">urn:schemas-microsoft-com:office:office</span></span>"<span style="color: #ff0000;"><span style="color: #ff0000;">&nbsp;<br />&nbsp;&nbsp;xmlns:r</span></span>=<span style="color: #0000ff;"><span style="color: #0000ff;"><a href="https://schemas.openxmlformats.org/officeDocument/2006/relationships">https://schemas.openxmlformats.org/officeDocument/2006/relationships</a></span></span><span style="color: #ff0000;"><span style="color: #ff0000;">&nbsp;&nbsp;&nbsp;<br />&nbsp; xmlns:m</span></span>=<span style="color: #0000ff;"><span style="color: #0000ff;"><a href="https://schemas.openxmlformats.org/officeDocument/2006/math">https://schemas.openxmlformats.org/officeDocument/2006/math</a></span></span><span style="color: #ff0000;"><span style="color: #ff0000;"> <br />&nbsp; xmlns:v</span></span>="<span style="color: #0000ff;"><span style="color: #0000ff;">urn:schemas-microsoft-com:vml</span></span>"<span style="color: #ff0000;"><span style="color: #ff0000;"><br />&nbsp; xmlns:wp</span></span>="<span style="color: #0000ff;"><span style="color: #0000ff;"><a href="https://schemas.openxmlformats.org/drawingml/2006/">https://schemas.openxmlformats.org/drawingml/2006/</a><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wordprocessingDrawing</span></span>"<span style="color: #ff0000;"><span style="color: #ff0000;"><br />&nbsp; xmlns:w10</span></span>="<span style="color: #0000ff;"><span style="color: #0000ff;">urn:schemas-microsoft-com:office:word</span></span>"<span style="color: #ff0000;"><span style="color: #ff0000;"> <br />&nbsp; xmlns:w</span></span>="<span style="color: #0000ff;"><span style="color: #0000ff;">https://schemas.openxmlformats.org/wordprocessingml/2006/main</span></span>"<span style="color: #ff0000;"><span style="color: #ff0000;"> <br />&nbsp; xmlns:wne</span></span>="<span style="color: #0000ff;"><span style="color: #0000ff;">https://schemas.microsoft.com/office/word/2006/wordml</span></span>"&gt;</span></p>
<p><span style="font-family: courier new,courier;">&lt;</span><span style="font-family: courier new,courier;"><span style="color: #b22222;"><span style="color: #b22222;">w:body</span></span><span>&gt;<br /></span></span><span style="font-family: courier new,courier;"><span style="color: #b22222;"><span style="color: #b22222;">&nbsp;&lt;w:p</span></span><span style="color: #ff0000;"><span style="color: #ff0000;"> w:rsidR</span></span>="<span style="color: #0000ff;"><span style="color: #0000ff;">009C767E</span></span>"<span style="color: #ff0000;"><span style="color: #ff0000;"> w:rsidRDefault</span></span>="<span style="color: #0000ff;"><span style="color: #0000ff;">00B653FD</span></span><span>"&gt;</span></span> <br />&nbsp;&nbsp; <span style="font-family: courier new,courier;">&lt;</span><span style="font-family: courier new,courier;"><span style="color: #b22222;"><span style="color: #b22222;">w:r</span></span><span>&gt;</span></span> <br />&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: courier new,courier;">&lt;</span><span style="font-family: courier new,courier;"><span style="color: #b22222;"><span style="color: #b22222;">w:t</span></span>&gt;On the Insert tab, the galleries include items that are designed to coordinate with the overall look of your document. You can use these galleries to insert tables, headers, footers, lists, cover pages, and other document building blocks. When you create pictures, charts, or diagrams, they also coordinate with your current document look.<br />&nbsp; &lt;<span style="color: #b22222;"><span style="color: #b22222;">/w:t</span></span><span>&gt;</span></span> <br />&nbsp;&nbsp; <span style="font-family: courier new,courier;">&lt;</span><span style="font-family: courier new,courier;"><span style="color: #b22222;"><span style="color: #b22222;">/w:r</span></span><span>&gt;</span></span> <br /><span style="font-family: courier new,courier;">&lt;</span><span style="font-family: courier new,courier;"><span style="color: #b22222;"><span style="color: #b22222;">/w:p</span></span><span>&gt;</span><span style="color: #b22222;"><span style="color: #b22222;">&lt;w:p</span></span><span style="color: #ff0000;"><span style="color: #ff0000;"> w:rsidR</span></span>="<span style="color: #0000ff;"><span style="color: #0000ff;">001D483C</span></span>"<span style="color: #ff0000;"><span style="color: #ff0000;"> w:rsidRDefault</span></span>="<span style="color: #0000ff;"><span style="color: #0000ff;">001D483C</span></span><span>"&gt;</span></span> <br /><br /><span style="font-family: courier new,courier;">...</span></p>
<p><span style="font-family: courier new,courier;">&nbsp;&lt;</span><span style="font-family: courier new,courier;"><span style="color: #b22222;"><span style="color: #b22222;">w</span></span></span><span style="font-family: courier new,courier;"><span style="color: #b22222;"><span style="color: #b22222;">/w:body</span></span><span>&gt;</span></span> <br /><span style="font-family: courier new,courier;">&lt;</span><span style="font-family: courier new,courier;"><span style="color: #b22222;"><span style="color: #b22222;">/w:document</span></span><span>&gt;</span></span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;&gt;&nbsp; I am not going&nbsp;to&nbsp;explain the first part of the sample code which handles the selection of&nbsp;each XML node of text, because the article <a href="https://msdn.microsoft.com/en-us/library/office/bb656295(v=office.12).aspx" target="_blank">Manipulating Word 2007 Files with the Open XML Format API (Part 1 of 3)</a>&nbsp;does a much better job;<br /><br />&nbsp;&gt; once we found <span style="background-color: #ffffff;">a way to</span> loop over each&nbsp;&lt;<span style="background-color: #d8d8d8;">w:t&gt;</span>structure ( <span style="background-color: #dedede; font-family: courier new,courier;"><span style="color: #0000ff;">foreach&nbsp;</span>(<span style="color: #2b91af;"><span style="color: #2b91af;"><span style="color: #2b91af;">XmlNode</span></span></span> textnode <span style="color: #0000ff;"><span style="color: #0000ff;"><span style="color: #0000ff;">in </span></span></span>textnodes)<span style="background-color: #ffffff;">&nbsp;</span></span>), we can&nbsp;quickly&nbsp;c<span style="background-color: #d8d8d8;"><span style="background-color: #ffffff;">ompute the number of characters; If we do a good job, we will get exactly the same value as the one&nbsp;stored in&nbsp;<span style="background-color: #dedede;">ExtendedFilePropertiesPart.CharactersWithSpaces <span style="background-color: #ffffff;">XML package&nbsp;structure, when the document is forced to update its Statistics numbers; </span></span><br /><br />&nbsp;&gt;&nbsp; there are many things which can&nbsp;make our count result in a different number of characters;&nbsp;<span style="background-color: #ffff99;">A complex document contains many hidden formatting&nbsp;characters ... &nbsp;shapes, tables, fields and formatting (bullets, TOC, citations) ... even simple HYPERLINK fields will make the issue noticeable</span>; If we don't ensure that all those characters are detected and summed or discarded, our count&nbsp;will be inaccurate;&nbsp;<br /><br />&nbsp;&gt;&nbsp; my sample code is built to detect the easiest problem we might encounter while counting: the&nbsp;character encoding;<br />&nbsp;&gt;&nbsp;&nbsp;this problem is not noticeable with simple input files; But when the code tries to parse paragraph #2, it will encounter a character which is not part of the ASCII character set;</span></span></p>
<p><span style="background-color: #d8d8d8;"><span style="background-color: #ffffff;">&nbsp;&gt;&nbsp; when counting&nbsp;characters, I tried to convert them into their byte code equivalent, then I used a&nbsp;variable which increases in value whenever a&nbsp;non-empty byte&nbsp;code (0)&nbsp;is encountered;&nbsp;<br />&nbsp;&gt; but, I soon realized that for some characters, my count was producing bad results; I traced the error back&nbsp;to the function which was translating characters to bytes: </span></span><span style="background-color: #dedede;"><strong><span style="font-family: courier new,courier;">Encoding.ASCII.GetBytes<span style="background-color: #ffffff;">;<br /></span></span></strong></span>&nbsp;&gt; when I switched to using <strong><span style="background-color: #dedede; font-family: courier new,courier;">String.ToCharArray()</span></strong>, I got the expected results;</p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2870.5.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2870.5.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2870.5.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2870.5.jpg" alt="" border="0" /></a></p>
</td>
</tr>
</tbody>
</table>
<p><span style="background-color: #d8d8d8;"><span style="background-color: #ffffff;">&nbsp;&gt; you can also see this issue, if you put a breakpoint on the </span></span><span style="background-color: #dedede; font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;">foreach&nbsp;</span>(<span style="color: #0000ff;"><span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span></span> strWd <span style="color: #0000ff;"><span style="color: #0000ff;"><span style="color: #0000ff;">in </span></span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="background-color: #dedede; font-family: courier new,courier; font-size: small;">strWords)</span>&nbsp;</span><span style="background-color: #d8d8d8;"><span style="background-color: #ffffff;">instruction and step through the code until you have to process the 2nd paragraph; Whenever the code encounters a character which is not part of the ASCII code, it encodes it as a "<span style="background-color: #dedede;">?</span>";<br /></span></span></p>
<p><span style="background-color: #d8d8d8;"><span style="background-color: #ffffff;">&nbsp;&gt; after switching to&nbsp;<strong><span style="background-color: #dedede; font-family: courier new,courier;">String.ToCharArray()</span></strong>, we get the Unicode character byte code, so we no longer have unknown character codes;&nbsp;But once we&nbsp;decide to use Unicode,&nbsp;we have to keep into account that <span style="background-color: #ffff99;">all the characters occupy 2 bytes</span>; So we must substract the 2nd byte from our count, if it is 0;<br /><br /><br />&nbsp;&gt; at the end, after counting all characters (including spaces), we&nbsp;can also find the number of words;&nbsp;<br />&nbsp;&gt; searching through the byte array, trying to&nbsp;detect words separated by one or more spaces&nbsp;can be tricky; So I used a faster method (which could be unreliable): I am&nbsp;dividing&nbsp;my total number of characters by&nbsp;a ratio found by experimenting&nbsp;(in my example, I am dividing by <strong>6</strong>); &nbsp;</span></span></p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2703.3.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2703.3.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/2703.3.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/2703.3.jpg" alt="" border="0" /></a></p>
</td>
</tr>
</tbody>
</table>
<p><span style="background-color: #ffffff; font-family: courier new,courier; font-size: small;"><span style="background-color: #ffffff; font-family: courier new,courier; font-size: small;"><br /><br /></span></span></p>
<table style="width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1538.4.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1538.4.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/1538.4.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/1538.4.jpg" alt="" border="0" /></a></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<span style="background-color: #ffffff;">&nbsp;&gt; please note that <span style="color: #ff0000;"><strong>not all spaces have the same Unicode value</strong></span>; The regular space character has the Unicode value of [<strong>00 32</strong>], but we also encounter other types: [<strong>00 160</strong>] = non-breaking space (see <span style="background-color: #dedede;">GetBytesCount_Unicode(<span style="color: #0000ff;"><span style="color: #0000ff;">string</span></span> str)</span> function, where if you wish to count only non-blank characters, you have to enable this line: <span style="background-color: #dedede;">if (bytes[i] != 0 &amp;&amp; bytes[i] != <span style="background-color: #ffff99;">32</span> &amp;&amp; bytes[i] != <span style="background-color: #ffff99;">160</span>)<span style="background-color: #ffffff;">&nbsp;</span></span>);<br /></span><span style="background-color: #ffffff; font-family: courier new,courier;"><br /></span><span style="background-color: #ffffff; font-size: small;">The second part of this article demonstrates how you can move the&nbsp;word count&nbsp;operation on the client side, just by writing a few&nbsp;lines of VBA code. In this way, the end-user will update his document just before he's done working with&nbsp;it, so that your software does nothing else than read the <span style="background-color: #ebebeb;">CharactersWithSpaces</span></span><span style="background-color: #ffffff;"><span style="font-size: small;"> extended property.</span><span style="font-size: small;">&nbsp;&nbsp;</span></span>
<p><span style="background-color: #ffffff; font-family: courier new,courier; font-size: small;">&nbsp;</span></p>
<p>&nbsp;</p>
<p><span style="font-family: courier new, courier; font-size: small;"><strong><span style="background-color: #ffffff;">Thank you for reading my article! Bye :-)</span></strong></span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>VSTO &amp; VBA - Improving Excel's performance when writing data into Sheets by using memory arrays instead of inefficient code loops</title>
      <link>https://docs.microsoft.com/archive/blogs/cristib/vsto-vba-improving-excels-performance-when-writing-data-into-sheets-by-using-memory-arrays-instead-of-inefficient-code-loops</link>
      <pubDate>Thu, 31 May 2012 12:39:00 GMT</pubDate>
      <dc:creator><![CDATA[Cristian.Berescu]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cristib/2012/05/31/vsto-vba-improving-excels-performance-when-writing-data-into-sheets-by-using-memory-arrays-instead-of-inefficient-code-loops/</guid>
      <description><![CDATA[In my previous article (VSTO &amp; VBA - How to troubleshoot Excel memory and performance problems...]]></description>
      <content:encoded><![CDATA[<p><span style="font-family: courier new,courier; font-size: small;">In my previous article (<a title="VSTO &amp; VBA - How to troubleshoot Excel memory and performance problems caused by inefficient code loops" href="https://blogs.msdn.com/b/cristib/archive/2012/04/27/vsto-amp-vba-how-to-troubleshoot-excel-memory-and-performance-problems-caused-by-inefficient-code-loops.aspx" target="_blank">VSTO &amp; VBA - How to troubleshoot Excel memory and performance problems caused by inefficient code loops</a>) I wrote about a few common issues which may be encountered when trying to read data from an Excel workbook using COM automation. </span></p>
<p><span style="font-family: courier new,courier; font-size: small;">But after you finished reading it, maybe you asked yourself: <span style="color: #888888;">What about writing data into Excel sheets? Can we optimize that operation too? </span></span></p>
<p></p>
<p><span style="color: #000000; font-family: courier new,courier; font-size: small;">The answer is: YES, we generally can use the same techniques. Get a handle to the range of cells you wish to write, process and write the data into a memory array structure and finally, write it in one operation.</span></p>
<p><span style="color: #000000; font-family: courier new,courier; font-size: small;">Of course, when we want to write data, most of the time we need to format it properly (cell font color, cell borders, size ..etc). Sometimes we also need to write formulas, or we need to search data one cell at a time. Not every operation can be implemented with this approach, but when the situation allows for this optimization, the results are very good.</span></p>
<p></p>
<p><span style="color: #000000; font-family: courier new,courier; font-size: small;">So, let's start by assuming that we have to write a code which generates a report based on some template which can be customized by the end-user. Thus, the end user is in charge with writing and formatting the column headers and our program has to keep the same look-and-feel and it also has to insert the data. The blank report workbook could look like the one from below:</span></p>
<p><span style="color: #000000; font-family: courier new,courier; font-size: small;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0878.1.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0878.1.jpg"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0878.1.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0878.1.jpg" /></a></span></p>
<p><span style="font-size: small;"><span style="color: #000000; font-family: courier new,courier;"><br /></span><span style="font-family: courier new,courier;"><span style="color: #000000;">You may notice that the range [A1:G1] contains the header, and the data has to be inserted starting from row #2. I have highlighted with red markers the cells which have custom formatting applied:</span><span style="color: #000000;"><br />&nbsp;&nbsp; &gt; cell C2 has its text written in Bold, a light blue Font color and a light<br />&nbsp;&nbsp;&nbsp; &nbsp;blue Background;<br />&nbsp;&nbsp; &gt; cell F2 had an yellow Background;<br />&nbsp;&nbsp; &gt; cell G2 has a text with Italic effect;</span></span></span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span style="color: #000000;"></span>The <strong><span>$<span>varX</span> </span></strong>strings from cell C2 are user-defined variables and our code has to dynamically replace them at run-time with numbers.&nbsp; </span></p>
<p></p>
<p><span style="font-family: courier new,courier; font-size: small;">First I am going to demonstrate how poor the performance is when we attempt to write the values in sequential mode. To preserve the formatting, I am going to <strong>Select</strong> our template row [B2:G2], then I am going to execute a <strong><span>Selection.Insert Shift:=<span>xlDown</span> </span></strong>to shift the information one row lower, then the previous level will be filled in with data.<br /></span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0003.2.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0003.2.jpg"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/0003.2.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/0003.2.jpg" /></a></span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><br />This is the VBA code I used:</span></p>
<table style="background-color: #dedede; width: 550px; border: #000000 1px solid;" border="1">
<tbody>
<tr>
<td>
<p><strong><span style="color: #0000ff; font-family: courier new,courier; font-size: small;">Option Explicit</span></strong></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>Public Declare Function </strong><span style="color: #000000;"><span><span>GetTickCount</span></span></span><strong> Lib "</strong><span style="color: #666699;"><span>kernel32.<span>dll</span></span></span><strong>" </strong><span style="color: #000000;">()</span><strong> As Long<br /></strong></span></span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>Sub</strong></span> Test1()</span><br />&nbsp;&nbsp; <br /><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp; On Error Resume Next</span></strong></span><br />&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span> r&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;"><strong>As Integer</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span> c&nbsp;&nbsp; <span style="color: #0000ff;"><strong>As Integer</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span> sht <span style="color: #0000ff;"><strong>As</strong></span> Worksheet</span><br />&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span> counter1 <span style="color: #0000ff;"><strong>As Integer</strong></span></span><br />&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span><span> <span>rowInput</span>&nbsp; </span><span style="color: #0000ff;"><strong>As Integer</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span><span> <span>colInput</span>&nbsp; </span><span style="color: #0000ff;"><strong>As Integer</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span><span> <span>rngInput</span>&nbsp; <strong><span style="color: #0000ff;">As</span></strong> Range</span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span><span> <span>rngOutput</span> </span><span style="color: #0000ff;"><strong>As Range</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span> t1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>As </strong><strong>Long</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span> t2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>As </strong><strong>Long</strong></span></span><br />&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; </strong></span></span><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>Set</strong></span><span> sht = <span>ActiveWorkbook</span>.Sheets(</span><span style="color: #ff0000;"><strong>1</strong></span>)</span><br />&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; Application.<span>ScreenUpdating</span>&nbsp;&nbsp;&nbsp; = </span><span style="color: #0000ff;"><strong>False</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; Application.<span>EnableEvents</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = </span><span style="color: #0000ff;"><strong>False</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; Application.Calculation&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; = <span>xlCalculationManual</span></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; Application.<span>DisplayAlerts</span>&nbsp;&nbsp;&nbsp;&nbsp; = </span><span style="color: #0000ff;"><strong>False</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; Application.<span>DisplayStatusBar</span>&nbsp; = </span><span style="color: #0000ff;"><strong>False</strong></span></span><br />&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp; counter1 = 0</span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; t1 = <span>GetTickCount</span></span></span><br />&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; For</strong></span> r = <strong><span style="color: #ff0000;">2</span></strong> <span style="color: #0000ff;"><strong>To</strong></span> <strong><span style="color: #ff0000;">10002</span></strong></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small; background-color: #00ff00;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>DoEvents</span></span></span><br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp; 'select the range used as template</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sht.Range(Cells(r, 1), Cells(r, 8)).Select</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp; 'copy the formatting one row down</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Selection.Copy</span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Selection.Insert Shift:=<span>xlDown</span></span></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp; 'save a handle for the row which has to be filled in</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set</strong></span><span> <span>rngInput</span> = sht.Range(sht.Cells(r, </span><span style="color: #ff0000;"><strong>2</strong></span>), sht.Cells(r, <strong><span style="color: #ff0000;">7</span></strong>))</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; For</strong></span><span> <span>colInput</span> = </span><span style="color: #ff0000;"><strong>1</strong></span> <span style="color: #0000ff;"><strong>To</strong></span><strong> <span style="color: #ff0000;">5</span></strong></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dim</strong></span><span> <span>strTmp</span> </span><span style="color: #0000ff;"><strong>As String</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dim</strong></span><span> <span>strIn </span>&nbsp;</span><span style="color: #0000ff;"><strong>As String</strong></span></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>strIn</span> = <span>rngInput</span>.Cells(</span><strong><span style="color: #ff0000;">1</span></strong><span>, <span>colInput</span>).Value2</span></span></p>
<p><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'try to match $var1 and replace it with a dummy value</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If</strong></span><span> <span>InStr</span>(1, <span>strIn</span>, "</span><span style="color: #666699;">$var1</span>") &gt; 0 <span style="color: #0000ff;"><strong>Then</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>strIn</span>&nbsp;&nbsp;&nbsp; = Replace(<span>strIn</span>, "</span><span style="color: #666699;">$var1</span>", counter1)</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; counter1 = counter1 + <span style="color: #ff0000;"><strong>1</strong></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;"><span><span>rngInput</span>.Cells(</span><span style="color: #ff0000;"><strong>1</strong></span><span>, <span>colInput</span>).Value2 = <span>strIn</span></span></span><br /><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; End If</span></strong></span></p>
<p><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'try to match $var2 and replace it with a dummy value</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If</strong></span><span> <span>InStr</span>(1, <span>strIn</span>, "</span><span style="color: #666699;">$var2</span>") &gt; 0 <span style="color: #0000ff;"><strong>Then</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>strIn</span>&nbsp;&nbsp;&nbsp;&nbsp;= Replace(<span>strIn</span>, "</span><span style="color: #666699;">$var2</span>", (counter1 + <span style="color: #ff0000;"><strong>11</strong></span>))</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; counter1 = counter1 + <span style="color: #ff0000;"><strong>1</strong></span></span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>rngInput</span>.Cells(</span><span style="color: #ff0000;"><strong>1</strong></span><span>, <span>colInput</span>).Value2 = <span>strIn</span></span></span><br /><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; End If</span></strong></span></p>
<p><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'try to match $var3 and replace it with a dummy value</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If</strong></span><span> <span>InStr</span>(1, <span>strIn</span>, "</span><span style="color: #666699;">$var3</span>") &gt; 0 <span style="color: #0000ff;"><strong>Then</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>strIn</span>&nbsp;= Replace(<span>strIn</span>, "$var3", "3")</span></span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>rngInput</span>.Cells(</span><span style="color: #ff0000;"><strong>1</strong></span><span>, <span>colInput</span>).Value2 = <span>strIn</span></span></span><br /><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; End If</span></strong></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Next</span></strong></span><br />&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Debug.Print</strong></span> r</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Next</strong></span> r</span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; t2 = <span>GetTickCount</span></span></span><br />&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Debug.Print</strong></span> t1 &amp; " &gt;&gt; " &amp; t2</span><br />&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; Application.<span>ScreenUpdating</span>&nbsp;&nbsp; = </span><span style="color: #0000ff;"><strong>True</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; Application.<span>EnableEvents</span>&nbsp;&nbsp;&nbsp;&nbsp; = </span><span style="color: #0000ff;"><strong>True</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; Application.Calculation&nbsp;&nbsp; &nbsp;&nbsp; = <span>xlCalculationAutomatic</span></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; Application.<span>DisplayAlerts</span>&nbsp;&nbsp; &nbsp;= </span><span style="color: #0000ff;"><strong>True</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; Application.<span>DisplayStatusBar</span> = </span><span style="color: #0000ff;"><strong>True<br /></strong></span></span><br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">'---------------------------------------------------------------</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp; Debug.Print</strong></span> "<span style="color: #666699;">Writing cells sequentially</span><span>" &amp; <span>vbNewLine</span></span></span><br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp;'Debug.Print "Range.Cells.Count&nbsp;&nbsp;&nbsp;: " &amp; r * 6</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp; Debug.Print</strong></span> "<span style="color: #666699;">Range.Columns.Count :</span> " &amp; <span style="color: #ff0000;"><strong>6</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp; Debug.Print</strong></span> "<span style="color: #666699;">Range.Rows.Count&nbsp;&nbsp;&nbsp; :</span><span> " &amp; r &amp; <span>vbNewLine</span></span></span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp; Debug.Print</strong></span> "<span style="color: #666699;">Operation started at (CPU tick count):</span> " &amp; t1</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp; Debug.Print</strong></span> "<span style="color: #666699;">Operation ended at (CPU tick count)&nbsp; :</span> " &amp; t2</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp; Debug.Print</strong></span> "<span style="color: #666699;">Milliseconds duration&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :</span> " &amp; t2 - t1</span></p>
<p><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier; font-size: small;">End Sub</span></strong></span><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier; font-size: small;"></span></strong></span></p>
</td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier; font-size: small;"><span><br /><span style="font-family: courier new,courier;">First of all I want to let you know that this code is so badly written that <span style="color: #ff0000;"><strong>it crashed my Excel 2010</strong></span> around iteration # 200 !!! Then I had to add the <strong>DoEvents</strong> instruction and I had to disable <strong>ScreenUpdating</strong>, Event triggers ...etc.</span></span></span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><br />This is the output:</span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3755.3.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3755.3.jpg"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/3755.3.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/3755.3.jpg" /></a></span></p>
<p>&nbsp;</p>
<table style="background-color: #bcbcbc; width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><span style="font-family: courier new,courier; font-size: small;">Output </span><br /><span style="font-family: courier new,courier; font-size: small;">=================================================================== </span><br /><span style="font-family: courier new,courier; font-size: small;"><br />Writing cells sequentially</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">Range.Columns.Count : 6</span><br /><span style="font-family: courier new,courier; font-size: small;">Range.Rows.Count&nbsp;&nbsp;&nbsp; : 10003</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">Operation started at (CPU tick count): 40921230</span><br /><span style="font-family: courier new,courier; font-size: small;">Operation ended at (CPU tick count)&nbsp; : 41078354</span><br /><span style="font-family: courier new,courier; font-size: small;">Milliseconds duration : <span style="background-color: #00ff00;">157124</span></span></p>
</td>
</tr>
</tbody>
</table>
<p><span style="font-family: courier new,courier; font-size: small;"><span><span><br />OK</span>, so the badly designed code took 157 seconds (157124 milliseconds) to complete. </span></span></p>
<p></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span>Now let's take a look at the optimized version. You will notice that I don't need to use any Excel performance booster (<strong><span>DisableEvents</span></strong>, <strong><span>ScreenUpdating</span></strong>) because it takes too little for anyone to notice my code finished its job :) !<br /></span></span></p>
<table style="background-color: #dedede; width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td>
<p><strong><span style="color: #0000ff; font-family: courier new,courier; font-size: small;">Option Explicit</span></strong></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>Public Declare Function </strong><span style="color: #000000;"><span><span>GetTickCount</span></span></span><strong> Lib "</strong><span style="color: #666699;"><span>kernel32.<span>dll</span></span></span><strong>" </strong><span style="color: #000000;">()</span><strong> As Long<br /></strong></span></span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>Sub</strong></span> Test2()</span><br /><span style="color: #0000ff;"><strong><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; On Error Resume Next</span></strong></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp; Dim</strong></span><span> <span>arrOut</span>(<span style="color: #ff0000;"><strong>0</strong></span> To <span style="color: #ff0000;"><strong>10000</strong></span>, <span style="color: #ff0000;"><strong>0</strong></span> To <strong><span style="color: #ff0000;">5</span></strong>) </span><span style="color: #0000ff;"><strong>As Variant</strong></span></span><br />&nbsp;&nbsp; <br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp; 'if you want to send Formulas to the sheet, use this code ...</span><br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp; 'arrFor(0, 0) = "=R1C2 + R1C3"</span><br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp; 'arrFor(0, 1) = "=R10C2 + R10C3"</span><br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp; 'arrFor(1, 0) = "=R1C4 + R1C4"</span><br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp; 'arrFor(1, 1) = "=R1C3 + R1C3"</span><br />&nbsp;&nbsp; <br /><span style="color: #008000; font-family: courier new,courier; font-size: small;"><span>&nbsp; '<span>ActiveSheet</span>.Range("A1:B2").FormulaR1C1 = <span>arrFor</span></span></span><br />&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span> r <span style="color: #0000ff;"><strong>As Integer</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span> c <span style="color: #0000ff;"><strong>As Integer</strong></span></span><br />&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span> counter1 <span style="color: #0000ff;"><strong>As Integer</strong></span></span><br />&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span><span> <span>rowInput</span>&nbsp; </span><span style="color: #0000ff;"><strong>As Integer</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span><span> <span>colInput</span>&nbsp; </span><span style="color: #0000ff;"><strong>As Integer</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span><span> <span>rngInput</span>&nbsp; </span><span style="color: #0000ff;"><strong>As Range</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp;&nbsp;&nbsp; Dim</strong></span><span> <span>rngOutput</span> </span><span style="color: #0000ff;"><strong>As Range</strong></span></span><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>Dim</strong></span> t1 <strong><span style="color: #0000ff;">As Long</span></strong></span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>Dim</strong></span> t2 <span style="color: #0000ff;"><strong>As Long</strong></span></span><br />&nbsp;&nbsp;<br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;"><strong> Set</strong></span> <span>rngInput</span> = <span>ActiveWorkbook</span>.Sheets(1).Range("<span style="color: #666699;">A2:H2</span>")</span></span><br />&nbsp; <br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; 'obtain a handle on the destination range (10000 cells)</span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>Set</strong></span> <span>rngOutput</span> = <span>ActiveWorkbook</span>.Sheets(<span style="color: #ff0000;"><strong>1</strong></span>).Range("<span style="color: #666699;">A3:H10002</span>")</span></span><br />&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; <span>rowInput</span> = <span style="color: #ff0000;"><strong>1</strong></span>&nbsp;</span><br /><span style="color: #008000;">&nbsp;&nbsp; 'the input file has all the data on row 2, columns 2,3,4,5,6</span></span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; </span></p>
<p><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp; counter1 =<span style="color: #ff0000;"><strong> 0</strong></span></span><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; t1 = <span>GetTickCount</span></span></span><br />&nbsp;&nbsp;&nbsp; <br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; '--------------------------------------------------------------</span><br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; 'format the new cells</span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; <span>rngInput</span>.Select</span></span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp; Selection.Copy</span><br />&nbsp;&nbsp;&nbsp; <br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; <span>rngOutput</span>.Select</span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; Selection.<span>PasteSpecial</span> Paste:=<span>xlPasteFormats</span>, _ </span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Operation:=<span>xlNone</span>, <span>SkipBlanks</span>:=False, Transpose:=False</span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; <span>rngInput</span>.Cells(1, 1).Select</span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; Application.<span>CutCopyMode</span> = <span style="color: #0000ff;"><strong>False</strong></span></span></span><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; 'build the Array structure line by line</span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>Set</strong></span> <span>rngInput</span> = <span>ActiveWorkbook</span>.Sheets(<span style="color: #ff0000;"><strong>1</strong></span>).Range("<span style="color: #666699;">B2:G2</span>")</span></span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>For</strong></span> r = 0 <span style="color: #0000ff;"><strong>To</strong></span> <span style="color: #ff0000;"><strong>10000</strong></span></span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>For</strong></span> c = 0 <span style="color: #0000ff;"><strong>To</strong></span> <span style="color: #ff0000;"><strong>5</strong></span></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>Dim</strong></span> <span>strTmp</span> <span style="color: #0000ff;"><strong>As String</strong></span></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>Dim</strong></span> <span>strIn</span>&nbsp; <span style="color: #0000ff;"><strong>As String</strong></span></span></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>strIn</span> = <span>rngInput</span>.Cells(<span>rowInput</span>, c + <span style="color: #ff0000;"><strong>1</strong></span>).Value</span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>arrOut</span>(r, c) = <span>strIn</span></span></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'try to match $var1 and replace it with a dummy value</span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>If</strong></span> <span>InStr</span>(<span style="color: #ff0000;"><strong>1</strong></span>, <span>strIn</span>, "<span style="color: #666699;">$var1</span>") &gt; 0 <span style="color: #0000ff;"><strong>Then</strong></span></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>strIn</span>&nbsp;&nbsp;&nbsp; = Replace(<span>strIn</span>, "<span style="color: #666699;">$var1</span>", counter1)</span></span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; counter1 = counter1 +<span style="color: #ff0000;"><strong> 1</strong></span></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>arrOut</span>(r, c) = <span>strIn</span></span></span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>End If</strong></span></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'try to match $var2 and replace it with a dummy value</span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>If</strong></span> <span>InStr</span>(<span style="color: #ff0000;"><strong>1</strong></span>, <span>strIn</span>, "<span style="color: #666699;">$var2</span>") &gt; <span style="color: #ff0000;"><strong>0</strong></span> <span style="color: #0000ff;"><strong>Then</strong></span></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>strIn</span>&nbsp;&nbsp;&nbsp; = Replace(<span>strIn</span>, "<span style="color: #666699;">$var2</span>", (counter1 + <span style="color: #ff0000;"><strong>11</strong></span>))</span></span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; counter1 = counter1 + <span style="color: #ff0000;"><strong>1</strong></span></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>arrOut</span>(r, c) = <span>strIn</span></span></span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>End If</strong></span></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'try to match $var3 and replace it with a dummy value</span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>If</strong></span> <span>InStr</span>(<span style="color: #ff0000;"><strong>1</strong></span>, <span>strIn</span>, "<span style="color: #666699;">$var3</span>") &gt; 0<span style="color: #0000ff;"><strong> Then</strong></span></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>strIn</span> = Replace(<span>strIn</span>, "<span style="color: #666699;">$var3</span>", "3")</span></span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>arrOut</span>(r, c) = <span>strIn</span></span></span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>End If</strong></span></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>Next</strong></span> c</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;"><strong>Next</strong></span> r</span><br />&nbsp;&nbsp;&nbsp; <br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp; '---------------------------------------------------------------</span><br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">&nbsp; 'finished building memory array</span></p>
<p></p>
<p><span style="color: #008000; font-family: courier new,courier; font-size: small;">'----------------------------------------------------------------</span><br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">'send the raw data to Excel in one operation</span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp; <span style="color: #0000ff;"><strong>Set</strong></span> <span>rngOutput</span> = <span>ActiveWorkbook</span>.Sheets(<span style="color: #ff0000;"><strong>1</strong></span>).Range("<span style="color: #666699;">B2:G10002</span>")</span></span><br /><span style="font-family: courier new,courier; font-size: small; background-color: #ff0000;"><span>&nbsp; <span>rngOutput</span>.Value2 = <span>arrOut</span></span></span><br />&nbsp; <br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">'----------------------------------------------------------------</span><br /><span style="color: #008000; font-family: courier new,courier; font-size: small;">'done!</span><br /><span style="font-family: courier new,courier; font-size: small;"><span>&nbsp; t2 = <span>GetTickCount</span></span></span><br />&nbsp;&nbsp;<br />&nbsp;&nbsp;<br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;<span style="color: #0000ff;"><strong> Debug.Print</strong></span> "<span style="color: #666699;">Writing memory array to destination range</span>" &amp; _<br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>vbNewLine</span></span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp; Debug.Print</strong></span><span> "<span style="color: #666699;">Range.Cells.Count&nbsp;&nbsp; :</span> " &amp; <span>rngOutput</span>.Cells.Count</span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp; Debug.Print</strong></span><span> "<span style="color: #666699;">Range.Columns.Count :</span> " &amp; <span>rngOutput</span>.Columns.Count</span></span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp; Debug.Print</strong></span><span> "<span style="color: #666699;">Range.Rows.Count&nbsp;&nbsp;&nbsp; :</span> " &amp; <span>rngOutput</span>.Rows.Count &amp; _</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>vbNewLine</span></span></span></p>
<p><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp; De</strong><strong><span style="color: #0000ff;">b</span>ug.Print</strong></span> "<span style="color: #666699;">Operation started at (CPU tick count):</span> " &amp; t1</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp; Debug.Print</strong></span> "<span style="color: #666699;">Operation ended at (CPU tick count)&nbsp; :</span> " &amp; t2</span><br /><span style="font-family: courier new,courier; font-size: small;"><span style="color: #0000ff;"><strong>&nbsp; Debug.Print</strong></span> "<span style="color: #666699;">Milliseconds duration&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :</span> " &amp; t2 - t1</span><br />&nbsp;&nbsp;&nbsp; <br /><strong><span style="color: #0000ff; font-family: courier new,courier; font-size: small;">End Sub</span></strong></p>
</td>
</tr>
</tbody>
</table>
<p></p>
<p><span style="font-family: courier new,courier; font-size: small;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7536.4.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7536.4.jpg"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/41/69/7536.4.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-41-69/7536.4.jpg" /></a></span></p>
<p></p>
<table style="background-color: #bcbcbc; width: 550px; border-width: 1px; border-color: #000000;" border="1">
<tbody>
<tr>
<td><span style="font-family: courier new,courier; font-size: small;">Output </span><br /><span style="font-family: courier new,courier; font-size: small;">=================================================================== <br /><br />Writing memory array to destination range</span>
<p><span style="font-family: courier new,courier; font-size: small;">Range.Cells.Count&nbsp;&nbsp; : 60006</span><br /><span style="font-family: courier new,courier; font-size: small;">Range.Columns.Count : 6</span><br /><span style="font-family: courier new,courier; font-size: small;">Range.Rows.Count&nbsp;&nbsp;&nbsp; : 10001</span></p>
<span style="font-family: courier new,courier; font-size: small;"></span>
<p><span style="font-family: courier new,courier; font-size: small;">Operation started at (CPU tick count): 43972391</span><br /><span style="font-family: courier new,courier; font-size: small;">Operation ended at (CPU tick count)&nbsp; : 43972984</span><br /><span style="font-family: courier new,courier; font-size: small;">Milliseconds duration&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : <span style="background-color: #ff0000;">593</span></span></p>
</td>
</tr>
</tbody>
</table>
<p><br /><span style="font-family: courier new,courier; font-size: small;"><br />The operation was completed 264% faster.</span></p>
<p>&nbsp;</p>
<p><span style="font-family: courier new,courier; font-size: small;">As I wrote before, this can't be implemented in every scenario, but when it fits into your design, the improvement in speed will make you love Excel!</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: courier new,courier; font-size: small;">Thank you for reading my article! Bye :-)</span></strong></p>]]></content:encoded>
    </item>
  </channel>
</rss>