<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4197233680252276272</id><updated>2011-11-27T15:54:52.833-08:00</updated><category term='.Net Remoting'/><category term='COM Interop'/><category term='Windows Forms'/><category term='VSTO'/><category term='ADO.Net'/><category term='SQL Server'/><category term='Database Design'/><title type='text'>Chuck's .Net Development Blog</title><subtitle type='html'>Discussion on a Number of Topics Related to .Net Software Application Development</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://chuckc3net.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4197233680252276272/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://chuckc3net.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>chuckc3</name><uri>http://www.blogger.com/profile/07354338553743579477</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://1.bp.blogspot.com/_ARxmfr1lZpo/SxhjF98nd8I/AAAAAAAAAAM/musSGBc7Des/S220/CobbPicture.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>7</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4197233680252276272.post-5965705055591207413</id><published>2010-01-28T07:34:00.001-08:00</published><updated>2010-01-28T08:00:52.927-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VSTO'/><title type='text'>Developing Office 2003 Add-ins with Visual Studio 2008</title><content type='html'>&lt;p&gt;I want to summarize some lessons I had to learn “the hard way”.&amp;#160; Hopefully, it will be of benefit to someone else who has to go down this path.&lt;/p&gt;&lt;p&gt;Creating an Office Add-in in Visual Studio 2008 can be very easy.&amp;#160; Microsoft has done a good job of making that easy to do.&amp;#160; Deploying the Add-in; however, is a different story…that’s where it gets a lot more complicated.&lt;/p&gt;&lt;p&gt;First, you need to be aware of everything in my previous post on this topic:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;a href="http://chuckc3net.blogspot.com/search/label/VSTO" target="_blank"&gt;Developing VSTO Applications&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;There’s another “gotcha” that I recently discovered that you also need to be aware of and it deals with the VSTO runtime.&amp;#160; There are two versions of the VSTO runtime in use:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;VSTO SE Runtime was introduced with Visual Studio 2005 &lt;/li&gt;&lt;li&gt;VSTO 3.0 Runtime was introduced with Visual Studio 2008 &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The natural conclusion that someone would draw is that the VSTO 3.0 Runtime superseded the VSTO SE Runtime because the VSTO SE Runtime isn’t even offered as a choice for a prerequisite in Visual Studio 2008 – that assumption, unfortunately, is wrong.&amp;#160; That’s the lesson I had to learn “the hard way”.&lt;/p&gt;&lt;p&gt;If you’re developing an Office Add-in in Visual Studio 2008 that is targeted for Office 2003 and you develop it using the VSTO 3.0 Runtime, it won’t work.&amp;#160;&amp;#160; It will work in the development environment; however, when you deploy it to a target machine, it will fail to load.&amp;#160; In Visio 2003, if you examine the COM Add-ins, you will see the Add-in is present in the list of Add-in’s and it is unchecked with a message that if failed to load due to a run-time error.&amp;#160; This error can be very difficult to track down because there is nothing that gives you much of a clue of exactly what is causing the error.&lt;/p&gt;&lt;p&gt;The problem as I discovered is that the VSTO 3.0 Runtime doesn’t supersede the VSTO SE runtime as I thought for Office 2003 applications.&amp;#160; &lt;u&gt;If you’re targeting Office 2003 applications, you still need to use the VSTO SE runtime or your Add-in will not load with the symptoms I described&lt;/u&gt;.&amp;#160; The VSTO 3.0 runtime works &lt;u&gt;only&lt;/u&gt; with Office 2007 Add-ins.&lt;/p&gt;&lt;p&gt;Visual Studio 2008 certainly doesn’t make it easy to discover this because it doesn’t even offer the choice of adding the VSTO SE runtime as a prerequisite.&amp;#160; When you create an Office 2003 Add-in with VS2008, it creates the Add-in for you including the Setup project and you think you’re done just by adding the VSTO 3.0 runtime as a prerequisite…that’s where developers will get tripped up.&amp;#160; You have to add the VSTO SE runtime as a prerequisite to the Setup project instead of the VSTO 3.0 runtime and in order to do that, you need to add it as a custom prerequisite to VS2008 because it isn’t even in the list of standard prerequisites offered in VS2008.&amp;#160; &lt;/p&gt;&lt;p&gt;Here are some instructions for doing that:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Download the VSTO SE Deployment Sample from the following location:      &lt;blockquote&gt;&lt;p&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=6991E869-8D5B-45F4-91E7-B527BD236F4C&amp;amp;displaylang=en" target="_blank"&gt;VSTO SE Deployment Sample&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Install it on your development system      &lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;Copy the entire contents of the package to the VS2008 Packages location on your development system:      &lt;p&gt;The files will normally be installed in the following directory:&lt;/p&gt;&lt;p&gt;C:\Program Files\Microsoft Visual Studio 2005 Tools for Office SE Resources\VSTO2005SE Windows Installer Sample Version 3\packages\VSTOSERuntime&lt;/p&gt;&lt;p&gt;In order to get the VSTO SE runtime to show up as a prerequisite in VS2008, copy the files to VSTOSE Runtime files to the following location:&lt;/p&gt;&lt;p&gt;C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bootstrapper\Packages&lt;/p&gt;&lt;/li&gt;&lt;li&gt;Download the VSTO SE runtime redistributable from the following location:      &lt;p&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=F5539A90-DC41-4792-8EF8-F4DE62FF1E81&amp;amp;displaylang=en" target="_blank"&gt;VSTO SE Runtime Redistributable&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;Copy the VSTOR.exe file from the download location to the VS2008 package location in step 3 &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;I hope this helps someone avoid chasing around all over the web to find this information.&amp;#160; What makes this especially confusing is that many of the articles you will find on the web on this subject are written around VS2005 and haven’t been updated for VS2008.&amp;#160; You will need to ignore many of the things in these articles that are specific to VS2005 (For example, most articles talk about using the .Net Framework 2.0 as a prerequisite – that isn’t necessary - .Net Framework 3.5 works fine).&lt;/p&gt;&lt;p&gt;My thanks to Bessie Zhao from Microsoft for helping me unravel this puzzle.&lt;/p&gt;&lt;p&gt;Chuck&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4197233680252276272-5965705055591207413?l=chuckc3net.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chuckc3net.blogspot.com/feeds/5965705055591207413/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://chuckc3net.blogspot.com/2010/01/developing-office-2003-add-ins-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4197233680252276272/posts/default/5965705055591207413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4197233680252276272/posts/default/5965705055591207413'/><link rel='alternate' type='text/html' href='http://chuckc3net.blogspot.com/2010/01/developing-office-2003-add-ins-with.html' title='Developing Office 2003 Add-ins with Visual Studio 2008'/><author><name>chuckc3</name><uri>http://www.blogger.com/profile/07354338553743579477</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://1.bp.blogspot.com/_ARxmfr1lZpo/SxhjF98nd8I/AAAAAAAAAAM/musSGBc7Des/S220/CobbPicture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4197233680252276272.post-206555201718043788</id><published>2009-12-08T12:48:00.001-08:00</published><updated>2009-12-08T12:51:35.616-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Database Design'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>Maintaining Referential Integrity in a Database</title><content type='html'>&lt;p&gt;It can be tricky sometimes to maintain referential integrity in a database that has a number of related tables.&amp;#160; Here’s an approach I’ve found that seems to work well:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Use foreign key constraints in the database to maintain referential integrity between two related tables. &lt;/li&gt;&lt;li&gt;Assign a default value to each table to avoid getting foreign key constraint errors if the value is not specified.&amp;#160;&amp;#160; (This makes it easier to create new records without specifying all the field values to satisfy the foreign key constraints when the record is created). &lt;/li&gt;&lt;li&gt;When specifying foreign key constraints, there are two methods that are particularly critical to specify correctly:      &lt;ul&gt;&lt;li&gt;How the database propagates updates &lt;/li&gt;&lt;li&gt;How the database propagates deletions &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;For updates, set the foreign key constraints to automatically &lt;u&gt;Cascade&lt;/u&gt; updates in all cases &lt;/li&gt;&lt;li&gt;For deletions, there are two ways to handle them depending on the nature of the relationship between the two tables:      &lt;ul&gt;&lt;li&gt;There is a &amp;quot;parent-child&amp;quot; relationship between the tables (For example, the &amp;quot;Orders&amp;quot; table is the parent of the &amp;quot;Order Line Items&amp;quot; table). In this situation, set the foreign key constraint between the two tables to &lt;u&gt;Cascade&lt;/u&gt; the deletions. For example, deleting an order should also delete all the order line items associated with that order and not leave them behind as &amp;quot;orphans&amp;quot;. &lt;/li&gt;&lt;li&gt;There is a &amp;quot;type&amp;quot; or a modifier relationship between the tables rather than an ownership relationship (For example, the &amp;quot;Records&amp;quot; table has a &amp;quot;Record Storage Location&amp;quot; column that is joined to the Record Storage Locations table to specify where the record is stored). In this situation, set the foreign key constraint between the two tables to &lt;u&gt;&amp;quot;Set Default&amp;quot;&lt;/u&gt; on deletion. For example, if the a given record storage location is deleted, you wouldn't necessarily delete all the records that were stored in that location. They should have been moved to another location prior to this if, in fact they are to continue to exist, but if there are stragglers in the database, you would probably want to know about it. By setting the default value for this field which would typically be an unassigned value, you can easily spot these &amp;quot;stragglers&amp;quot; and determine if they need to be reassigned. &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;I hope that is helpful to others...it seems self-evident, but I assure you it wasn't until I took some time to think through it. Chuck&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4197233680252276272-206555201718043788?l=chuckc3net.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chuckc3net.blogspot.com/feeds/206555201718043788/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://chuckc3net.blogspot.com/2009/12/maintaining-referential-integrity-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4197233680252276272/posts/default/206555201718043788'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4197233680252276272/posts/default/206555201718043788'/><link rel='alternate' type='text/html' href='http://chuckc3net.blogspot.com/2009/12/maintaining-referential-integrity-in.html' title='Maintaining Referential Integrity in a Database'/><author><name>chuckc3</name><uri>http://www.blogger.com/profile/07354338553743579477</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://1.bp.blogspot.com/_ARxmfr1lZpo/SxhjF98nd8I/AAAAAAAAAAM/musSGBc7Des/S220/CobbPicture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4197233680252276272.post-6986552237710443345</id><published>2009-12-08T11:45:00.000-08:00</published><updated>2009-12-08T11:46:49.318-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='COM Interop'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net Remoting'/><title type='text'>.Net Remoting versus COM</title><content type='html'>&lt;p&gt;I’ve been looking into .Net Remoting as an alternative to COM for being able to use objects across application boundaries (See my separate article on ROTHook).&lt;/p&gt;&lt;p&gt;.Net Remoting has the potential to do most or perhaps all of the things we’ve done in the past with COM, but it would not seem to be a good use of that technology to do that.&amp;#160; Here’s how I see it:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;COM is designed around objects&lt;/li&gt;&lt;li&gt;.Net Remoting seems to be designed around a service-oriented environment&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;To illustrate the difference, here’s a little analogy that seems to be appropriate.&amp;#160; Suppose you want to hear a dog bark:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Using COM you would tell it to create a “dog” object and COM would give you back the entire “dog” object.&amp;#160; At that point, you could call the “bark” method on the “dog” object to get it to bark.&amp;#160; While you had the “dog” object, you could also call any other methods you wanted to “wag tail”, etc.&lt;/li&gt;&lt;li&gt;With the services approach that .Net Remoting seems to be designed around, you would simply call the “dog bark” service and it would bark for you.&amp;#160; If you want to call other methods like “wag tail”, that would generally be a different service.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;That’s how I see the difference between the two approaches.&amp;#160; I hope that helps others see it…it took me a little while to get there.&lt;/p&gt;&lt;p&gt;Chuck&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4197233680252276272-6986552237710443345?l=chuckc3net.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chuckc3net.blogspot.com/feeds/6986552237710443345/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://chuckc3net.blogspot.com/2009/12/net-remoting-versus-com.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4197233680252276272/posts/default/6986552237710443345'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4197233680252276272/posts/default/6986552237710443345'/><link rel='alternate' type='text/html' href='http://chuckc3net.blogspot.com/2009/12/net-remoting-versus-com.html' title='.Net Remoting versus COM'/><author><name>chuckc3</name><uri>http://www.blogger.com/profile/07354338553743579477</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://1.bp.blogspot.com/_ARxmfr1lZpo/SxhjF98nd8I/AAAAAAAAAAM/musSGBc7Des/S220/CobbPicture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4197233680252276272.post-4460311828807162970</id><published>2009-12-08T07:54:00.001-08:00</published><updated>2009-12-11T10:59:15.375-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ADO.Net'/><title type='text'>ADO.Net Synchronization</title><content type='html'>&lt;p&gt;The ADO.Net Sync Framework has some very nice capabilities for synchronizing a variety of data sources.&amp;#160; It even has capabilities for synchronizing files or if you were ambitious enough, you could develop a custom data source provider to work with sync services.&lt;/p&gt;  &lt;p&gt;The design of the application I’m working on is based on a local SQL Server Compact Edition database on the client machine and a more centralized SQL Server Express database that aggregates data from each client machine.&amp;#160; Sync services will do the job of synchronizing each SQL Server CE database with the SQL Server Express database, but I was wondering if it would also do the job of synching the data in the DataSet with SQL Server CE.&amp;#160; It seems to be a logical capability for it to provide since it is able to synchronize a number of different types of data sources and a DataSet schema looks just like the database it is derived from.&lt;/p&gt;  &lt;p&gt;I found out that ADO.Net synchronization will not provide that capability; however, I found another way of accomplishing that objective that’s very nice and very easy to implement.&amp;#160; The tricky part about database updates comes into play when you have related tables with foreign key constraints and they have to be updated in the proper sequence to avoid a foreign key violation.&amp;#160; In the original design of my application, I had some custom ADO.Net code that did that, but I wanted to find a way to simplify and standardize that code as much as possible.&amp;#160; That was one of the key things I was hoping Sync Services would do for me.&lt;/p&gt;  &lt;p&gt;The technique I wound up using is a TableAdapterManager.&amp;#160; The TAM is a relatively new capability and it does exactly what I was looking for synch services to do to synch the DataSet with the SQL CE database.&amp;#160; You create a TableAdapterManager to consist of one or more TableAdapters for all the tables in a relationship, and simply use the “UpdateAll” method on the TAM and it will update all of the related tables in the proper sequence to avoid foreign key constraint errors.&amp;#160; The TAM is a very nice capability!&lt;/p&gt;  &lt;p&gt;Chuck&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4197233680252276272-4460311828807162970?l=chuckc3net.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chuckc3net.blogspot.com/feeds/4460311828807162970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://chuckc3net.blogspot.com/2009/12/adonet-synchronization.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4197233680252276272/posts/default/4460311828807162970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4197233680252276272/posts/default/4460311828807162970'/><link rel='alternate' type='text/html' href='http://chuckc3net.blogspot.com/2009/12/adonet-synchronization.html' title='ADO.Net Synchronization'/><author><name>chuckc3</name><uri>http://www.blogger.com/profile/07354338553743579477</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://1.bp.blogspot.com/_ARxmfr1lZpo/SxhjF98nd8I/AAAAAAAAAAM/musSGBc7Des/S220/CobbPicture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4197233680252276272.post-7099163535809282856</id><published>2009-12-08T07:40:00.001-08:00</published><updated>2009-12-08T07:55:25.922-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VSTO'/><title type='text'>VSTO Deployment</title><content type='html'>&lt;p&gt;I’ve been working over the past few months to convert a Visio Add-in I originally developed about 5-6 years ago to migrate it from VB.Net to C# and also to Visual Studio 2008, .Net Framework 3.5, and Visual Studio Tools for Office (VSTO).&lt;/p&gt;&lt;p&gt;The original application design used a small stub of VBA code inside the Visio document to launch the COM Add-in.&amp;#160; This is a somewhat crude approach and it wasn’t a true Visio Add-in, but it has worked well for a number of years.&amp;#160; However, much better capabilities are available now through VSTO to make it very easy to create a true Visio Add-in (or an Add-in for any other Office Application).&lt;/p&gt;&lt;p&gt;Deployment of the completed VSTO Add-in can be difficult – especially on Vista and Windows 7 systems that have tightened up code access security to control what an application is allowed to do (and is not allowed to do).&amp;#160; Here are a few notes on what needs to be done to successfully deploy a VSTO Add-in:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;How the application stores and accesses files on the target system needs to be carefully thought out.&amp;#160; In the past, many applications simply put all files (both application files and data files) in the C:\Program Files location.&amp;#160; This approach no longer works on Vista systems because Vista will not allow an application to write or modify files in that area at runtime unless it is running with Administrator privileges.&amp;#160; My recommended strategy is this:      &lt;ul&gt;&lt;li&gt;Use the Program Files directory only for application files that are only written or modified when the application is installed. &lt;/li&gt;&lt;li&gt;Create a folder in the user’s “My Documents” area for any documents that the user might create or modify while he/she is using the application. &lt;/li&gt;&lt;li&gt;Create a folder in the LocalApplicationData area for any other files that are written or modified by the application at run-time that do not need to be easily accessible to the user (for example configuration files and application data files).&amp;#160; On Vista systems this folder is located at C:\Users\&amp;lt;UserName&amp;gt;\AppData\Local &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;The Office Add-in must be granted full trust in order for the VSTO loader to load it at run-time.&amp;#160; Problems with the VSTO loader not loading an application can be elusive to track down because the VSTO loader doesn’t seem to report all errors (even if you have error logging turned on).&amp;#160; Sometimes it just refuses to load the Add-in and doesn’t provide an error message or any indication that the Add-in hasn’t been loaded.&amp;#160; In order to grant full trust to your Add-in, you must include an installer project that creates a code access security policy to grant full-trust to the application.&amp;#160;&amp;#160; I recommend going beyond that and assigning full-trust to the entire installation directory, especially if you have other DLL’s in the installation directory that also must be trusted for the application to run.&amp;#160; Here are some references for more details on how to implement this:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;   &lt;a href="http://msdn.microsoft.com/en-us/library/bb332052.aspx " target="_blank"&gt;SetSecurity Project Code and Instructions&lt;/a&gt; &lt;/li&gt;&lt;li&gt; &lt;a href=" http://social.msdn.microsoft.com/forums/en-US/vsto/thread/cec6abb6-4716-4bde-91f2-25fb68abd54e/" target="_blank"&gt;Modifications to Grant Full Trust to the Install Directory&lt;/a&gt; &lt;/li&gt;&lt;li&gt; &lt;a href="http://social.msdn.microsoft.com/Forums/en-US/vsto/thread/bfa7429b-7ba1-441c-a54f-2542770b63c1" target="_blank"&gt;My MSDN Forum Topic on this Subject&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt;&lt;li&gt; Make sure that all the required prerequisites are included in the installer package.  The obvious ones are:  &lt;ul&gt;&lt;li&gt;.Net Framework 3.5 (or whatever other version you used)&lt;/li&gt;&lt;li&gt;VSTO Runtime&lt;/li&gt;&lt;/ul&gt;One that is not so obvious is the ".Net 3.5 Framework Client Profile".  The "Framework Client Profile" is supposed to be a subset of the full .Net Framework, so it seems redundant to include it &lt;u&gt;and&lt;/u&gt; and the full .Net Framework, but it does seem to be necessary.  &lt;/ol&gt;&lt;br /&gt;Chuck&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4197233680252276272-7099163535809282856?l=chuckc3net.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chuckc3net.blogspot.com/feeds/7099163535809282856/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://chuckc3net.blogspot.com/2009/12/vsto-deployment.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4197233680252276272/posts/default/7099163535809282856'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4197233680252276272/posts/default/7099163535809282856'/><link rel='alternate' type='text/html' href='http://chuckc3net.blogspot.com/2009/12/vsto-deployment.html' title='VSTO Deployment'/><author><name>chuckc3</name><uri>http://www.blogger.com/profile/07354338553743579477</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://1.bp.blogspot.com/_ARxmfr1lZpo/SxhjF98nd8I/AAAAAAAAAAM/musSGBc7Des/S220/CobbPicture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4197233680252276272.post-9164633633233076845</id><published>2009-12-04T08:57:00.001-08:00</published><updated>2009-12-04T09:08:28.729-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='COM Interop'/><title type='text'>COM and the Run-time Object Table (ROT)</title><content type='html'>You would think that it would be relatively easy for one managed code assembly to get a reference to another managed code assembly at runtime that might be running under a different application domain, but it's not. In order to do that you have to do several things:   &lt;ol&gt;&lt;li&gt;Make the server .Net Assembly Com-visible and Com-Compatible&lt;/li&gt;&lt;li&gt;Register the server assembly in the RunTime Object Table (ROT) so that the client assembly can find it at run time&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;The technique for exposing a .Net assembly to COM is not too difficult and is covered in a number of locations on the web.&amp;#160; The task of registering a COM object in the ROT and retrieving a reference to that COM object from another application is a bit tricky.&amp;#160; Here’s some code that I’ve found works for that:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;Option Strict On&lt;br /&gt;Option Explicit On&lt;br /&gt;&lt;br /&gt;Imports &lt;/span&gt;System.Runtime.InteropServices&lt;br /&gt;&lt;span style="color: blue"&gt;Imports &lt;/span&gt;System.Runtime.InteropServices.ComTypes&lt;br /&gt;&lt;span style="color: blue"&gt;Imports &lt;/span&gt;System.Runtime.InteropServices.Marshal&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue"&gt;Public Class &lt;/span&gt;ROTHook&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue"&gt;Private Const &lt;/span&gt;ROTFLAGS_REGISTRATIONKEEPSALIVE &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 1&lt;br /&gt;&lt;span style="color: blue"&gt;Private Const &lt;/span&gt;ROTFLAGS_ALLOWANYCLIENT &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 2&lt;br /&gt;&lt;br /&gt;&amp;lt;DllImport(&lt;span style="color: #a31515"&gt;&amp;quot;ole32.dll&amp;quot;&lt;/span&gt;, ExactSpelling:=&lt;span style="color: blue"&gt;True&lt;/span&gt;, PreserveSig:=&lt;span style="color: blue"&gt;False&lt;/span&gt;)&amp;gt; _&lt;br /&gt;&lt;span style="color: blue"&gt;Private Shared Function &lt;/span&gt;GetRunningObjectTable(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;reserved &lt;span style="color: blue"&gt;As &lt;/span&gt;Int32) &lt;span style="color: blue"&gt;As &lt;/span&gt;IRunningObjectTable&lt;br /&gt;&lt;span style="color: blue"&gt;End Function&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&amp;lt;DllImport(&lt;span style="color: #a31515"&gt;&amp;quot;ole32.dll&amp;quot;&lt;/span&gt;, CharSet:=CharSet.Unicode, ExactSpelling:=&lt;span style="color: blue"&gt;True&lt;/span&gt;, PreserveSig:=&lt;span style="color: blue"&gt;False&lt;/span&gt;)&amp;gt; _&lt;br /&gt;&lt;span style="color: blue"&gt;Private Shared Function &lt;/span&gt;CreateItemMoniker(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;lpszDelim &lt;span style="color: blue"&gt;As String&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;lpszItem &lt;span style="color: blue"&gt;As String&lt;/span&gt;) &lt;span style="color: blue"&gt;As &lt;/span&gt;IMoniker&lt;br /&gt;&lt;span style="color: blue"&gt;End Function&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&amp;lt;DllImport(&lt;span style="color: #a31515"&gt;&amp;quot;ole32.dll&amp;quot;&lt;/span&gt;, ExactSpelling:=&lt;span style="color: blue"&gt;True&lt;/span&gt;, PreserveSig:=&lt;span style="color: blue"&gt;False&lt;/span&gt;)&amp;gt; _&lt;br /&gt;&lt;span style="color: blue"&gt;Private Shared Function &lt;/span&gt;CreateBindCtx(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;reserved &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;) &lt;span style="color: blue"&gt;As &lt;/span&gt;IBindCtx&lt;br /&gt;&lt;span style="color: blue"&gt;End Function&lt;br /&gt;&lt;br /&gt;Public Shared Function &lt;/span&gt;AddToROT(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;obj &lt;span style="color: blue"&gt;As Object&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;classID &lt;span style="color: blue"&gt;As String&lt;/span&gt;) &lt;span style="color: blue"&gt;As Integer&lt;br /&gt;&lt;/span&gt;&lt;span style="color: green"&gt;'----------------------------------------------------------------------------------&lt;br /&gt;' AddToROT&lt;br /&gt;'&lt;br /&gt;' Abstract - Adds a Reference to This Object to the Runtime Object Table&lt;br /&gt;'&lt;br /&gt;' Parameters&lt;br /&gt;'               obj Object to register&lt;br /&gt;'               classID Class ID of object to register&lt;br /&gt;'&lt;br /&gt;' Return Value  cookie to revoke ROT registration&lt;br /&gt;'----------------------------------------------------------------------------------&lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;cookieValue &lt;span style="color: blue"&gt;As Integer&lt;br /&gt;Dim &lt;/span&gt;rot &lt;span style="color: blue"&gt;As &lt;/span&gt;IRunningObjectTable = &lt;span style="color: blue"&gt;Nothing&lt;br /&gt;Dim &lt;/span&gt;moniker &lt;span style="color: blue"&gt;As &lt;/span&gt;IMoniker = &lt;span style="color: blue"&gt;Nothing&lt;br /&gt;&lt;br /&gt;Try&lt;br /&gt;&lt;/span&gt;&lt;span style="color: green"&gt;'---- Get the ROT -------------------------------------------------------------&lt;br /&gt;&lt;/span&gt;rot = GetRunningObjectTable(0)&lt;br /&gt;&lt;br /&gt;&lt;span style="color: green"&gt;'--- Create a moniker ---------------------------------------------------------&lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;objName &lt;span style="color: blue"&gt;As String &lt;/span&gt;= &lt;span style="color: #a31515"&gt;&amp;quot;{&amp;quot; &lt;/span&gt;+ classID + &lt;span style="color: #a31515"&gt;&amp;quot;}&amp;quot;&lt;br /&gt;&lt;/span&gt;moniker = CreateItemMoniker(&lt;span style="color: #a31515"&gt;&amp;quot;!&amp;quot;&lt;/span&gt;, objName)&lt;br /&gt;&lt;br /&gt;&lt;span style="color: green"&gt;'--- Registers the object in the running object table -------------------------&lt;br /&gt;&lt;/span&gt;cookieValue = rot.Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, obj, moniker)&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue"&gt;Return &lt;/span&gt;cookieValue&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue"&gt;Catch &lt;/span&gt;Exc &lt;span style="color: blue"&gt;As &lt;/span&gt;Exception&lt;br /&gt;&lt;span style="color: blue"&gt;Throw &lt;/span&gt;Exc&lt;br /&gt;&lt;span style="color: blue"&gt;Finally&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: green"&gt;'--- Releases the COM objects -----------------------------------------------&lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;If Not &lt;/span&gt;(moniker &lt;span style="color: blue"&gt;Is Nothing&lt;/span&gt;) &lt;span style="color: blue"&gt;Then&lt;br /&gt;Try&lt;br /&gt;While &lt;/span&gt;(Marshal.ReleaseComObject(moniker) &amp;gt; 0)&lt;br /&gt;&lt;span style="color: blue"&gt;End While&lt;br /&gt;Catch &lt;/span&gt;ex &lt;span style="color: blue"&gt;As &lt;/span&gt;Exception&lt;br /&gt;&lt;span style="color: blue"&gt;Exit Try&lt;br /&gt;End Try&lt;br /&gt;End If&lt;br /&gt;If Not &lt;/span&gt;(rot &lt;span style="color: blue"&gt;Is Nothing&lt;/span&gt;) &lt;span style="color: blue"&gt;Then&lt;br /&gt;Try&lt;br /&gt;While &lt;/span&gt;(Marshal.ReleaseComObject(rot) &amp;gt; 0)&lt;br /&gt;&lt;span style="color: blue"&gt;End While&lt;br /&gt;Catch &lt;/span&gt;ex &lt;span style="color: blue"&gt;As &lt;/span&gt;Exception&lt;br /&gt;&lt;span style="color: blue"&gt;Exit Try&lt;br /&gt;End Try&lt;br /&gt;End If&lt;br /&gt;End Try&lt;br /&gt;&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Public Shared Function &lt;/span&gt;GetObjectByClassName(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;objClassName &lt;span style="color: blue"&gt;As String&lt;/span&gt;) &lt;span style="color: blue"&gt;As Object&lt;br /&gt;Return &lt;/span&gt;GetActiveObject(&lt;span style="color: #a31515"&gt;&amp;quot;!&amp;quot; &lt;/span&gt;+ objClassName)&lt;br /&gt;&lt;span style="color: blue"&gt;End Function&lt;br /&gt;&lt;br /&gt;Public Shared Function &lt;/span&gt;GetObjectByClassID(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;objClassID &lt;span style="color: blue"&gt;As String&lt;/span&gt;) &lt;span style="color: blue"&gt;As Object&lt;br /&gt;Return &lt;/span&gt;GetActiveObject(&lt;span style="color: #a31515"&gt;&amp;quot;!{&amp;quot; &lt;/span&gt;+ objClassID + &lt;span style="color: #a31515"&gt;&amp;quot;}&amp;quot;&lt;/span&gt;)&lt;br /&gt;&lt;span style="color: blue"&gt;End Function&lt;br /&gt;&lt;br /&gt;Public Shared Function &lt;/span&gt;GetActiveObject(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;objName &lt;span style="color: blue"&gt;As String&lt;/span&gt;) _&lt;br /&gt;&lt;span style="color: blue"&gt;As Object&lt;br /&gt;&lt;/span&gt;&lt;span style="color: green"&gt;'----------------------------------------------------------------------------------&lt;br /&gt;' GetActiveObject&lt;br /&gt;'&lt;br /&gt;' Abstract - Gets an Instance of this Object from the Runtime Object Table&lt;br /&gt;'&lt;br /&gt;' Parameters&lt;br /&gt;'&lt;br /&gt;' Return Value  Object found or Nothing if Not Found&lt;br /&gt;'----------------------------------------------------------------------------------&lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;Try&lt;br /&gt;&lt;br /&gt;Dim &lt;/span&gt;ROTObject &lt;span style="color: blue"&gt;As Object &lt;/span&gt;= &lt;span style="color: blue"&gt;Nothing&lt;br /&gt;Dim &lt;/span&gt;runningObjectTable &lt;span style="color: blue"&gt;As &lt;/span&gt;IRunningObjectTable&lt;br /&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;monikerEnumerator &lt;span style="color: blue"&gt;As &lt;/span&gt;IEnumMoniker = &lt;span style="color: blue"&gt;Nothing&lt;br /&gt;Dim &lt;/span&gt;monikers(1) &lt;span style="color: blue"&gt;As &lt;/span&gt;IMoniker&lt;br /&gt;&lt;br /&gt;runningObjectTable = GetRunningObjectTable(0)&lt;br /&gt;runningObjectTable.EnumRunning(monikerEnumerator)&lt;br /&gt;monikerEnumerator.Reset()&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;numFetched &lt;span style="color: blue"&gt;As &lt;/span&gt;IntPtr = &lt;span style="color: blue"&gt;New &lt;/span&gt;IntPtr()&lt;br /&gt;&lt;span style="color: blue"&gt;While &lt;/span&gt;(monikerEnumerator.Next(1, monikers, numFetched) = 0)&lt;br /&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;ctx &lt;span style="color: blue"&gt;As &lt;/span&gt;IBindCtx&lt;br /&gt;ctx = CreateBindCtx(0)&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;runningObjectName &lt;span style="color: blue"&gt;As String &lt;/span&gt;= &lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;br /&gt;&lt;/span&gt;monikers(0).GetDisplayName(ctx, &lt;span style="color: blue"&gt;Nothing&lt;/span&gt;, runningObjectName)&lt;br /&gt;runningObjectName = runningObjectName.ToUpper&lt;br /&gt;&lt;span style="color: blue"&gt;If &lt;/span&gt;(runningObjectName.StartsWith(objName.ToUpper)) &lt;span style="color: blue"&gt;Then&lt;br /&gt;Dim &lt;/span&gt;runningObjectVal &lt;span style="color: blue"&gt;As Object &lt;/span&gt;= &lt;span style="color: blue"&gt;Nothing&lt;br /&gt;&lt;/span&gt;runningObjectTable.GetObject(monikers(0), runningObjectVal)&lt;br /&gt;ROTObject = &lt;span style="color: blue"&gt;CType&lt;/span&gt;(runningObjectVal, &lt;span style="color: blue"&gt;Object&lt;/span&gt;)&lt;br /&gt;&lt;span style="color: blue"&gt;Return &lt;/span&gt;ROTObject&lt;br /&gt;&lt;span style="color: blue"&gt;End If&lt;br /&gt;End While&lt;br /&gt;&lt;br /&gt;Return &lt;/span&gt;ROTObject&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue"&gt;Catch &lt;/span&gt;Exc &lt;span style="color: blue"&gt;As &lt;/span&gt;Exception&lt;br /&gt;&lt;span style="color: blue"&gt;Throw &lt;/span&gt;Exc&lt;br /&gt;&lt;span style="color: blue"&gt;End Try&lt;br /&gt;&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Public Shared Sub &lt;/span&gt;RemoveFromROT(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;myCookie &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;)&lt;br /&gt;&lt;span style="color: green"&gt;'----------------------------------------------------------------------------------&lt;br /&gt;' RemoveFromROT&lt;br /&gt;'&lt;br /&gt;' Abstract - Removes a Reference to This Object From the Runtime Object Table&lt;br /&gt;'&lt;br /&gt;' Parameters&lt;br /&gt;'&lt;br /&gt;' Return Value  &lt;br /&gt;'----------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;If &lt;/span&gt;(myCookie = 0) &lt;span style="color: blue"&gt;Then Exit Sub&lt;br /&gt;Dim &lt;/span&gt;rot &lt;span style="color: blue"&gt;As &lt;/span&gt;IRunningObjectTable = &lt;span style="color: blue"&gt;Nothing&lt;br /&gt;&lt;br /&gt;Try&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: green"&gt;'--- Get the running object table and revoke the cookie ----------------&lt;br /&gt;&lt;/span&gt;rot = GetRunningObjectTable(0)&lt;br /&gt;rot.Revoke(myCookie)&lt;br /&gt;myCookie = 0&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue"&gt;Catch &lt;/span&gt;Exc &lt;span style="color: blue"&gt;As &lt;/span&gt;Exception&lt;br /&gt;&lt;span style="color: blue"&gt;Throw &lt;/span&gt;Exc&lt;br /&gt;&lt;span style="color: blue"&gt;Finally&lt;br /&gt;If Not &lt;/span&gt;(rot &lt;span style="color: blue"&gt;Is Nothing&lt;/span&gt;) &lt;span style="color: blue"&gt;Then&lt;br /&gt;While &lt;/span&gt;(Marshal.ReleaseComObject(rot) &amp;gt; 0)&lt;br /&gt;&lt;span style="color: blue"&gt;End While&lt;br /&gt;End If&lt;br /&gt;End Try&lt;br /&gt;&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;End Class&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;You can use the “AddToROT” method to register an object in the ROT by classID – that method will return a cookie that can be used later to remove the object.&amp;#160; The “GetObjectByClassID” can be used to retrieve the object from another process.&lt;/p&gt;&lt;p&gt;Chuck&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4197233680252276272-9164633633233076845?l=chuckc3net.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chuckc3net.blogspot.com/feeds/9164633633233076845/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://chuckc3net.blogspot.com/2009/12/com-and-run-time-object-table-rot.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4197233680252276272/posts/default/9164633633233076845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4197233680252276272/posts/default/9164633633233076845'/><link rel='alternate' type='text/html' href='http://chuckc3net.blogspot.com/2009/12/com-and-run-time-object-table-rot.html' title='COM and the Run-time Object Table (ROT)'/><author><name>chuckc3</name><uri>http://www.blogger.com/profile/07354338553743579477</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://1.bp.blogspot.com/_ARxmfr1lZpo/SxhjF98nd8I/AAAAAAAAAAM/musSGBc7Des/S220/CobbPicture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4197233680252276272.post-1484837982882655470</id><published>2009-12-04T07:55:00.001-08:00</published><updated>2009-12-04T08:38:10.899-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows Forms'/><title type='text'>Correctly Displaying Windows Forms</title><content type='html'>If you have an application that launches a number of different forms and the forms can be launched in different ways by different parent forms or different parts of the application, displaying the form correctly relative to the parent form can be tricky.&amp;nbsp; The way I originally did this was to pass the parent handle of the parent form to the child form.&amp;nbsp; That’s a little cumbersome because you have to pass the parent handle as an argument every time you launch a child form.&amp;nbsp; I’ve found a much better way to do that.&lt;br /&gt;I’ve written a small amount of code that calls a Windows API to get the windows handle of the active window and I use that to launch all forms.&amp;nbsp; It works great.&amp;nbsp; Here’s the code:&lt;br /&gt;&lt;hr /&gt;&lt;pre class="code"&gt;&lt;span style="color: blue;"&gt;Imports &lt;/span&gt;System.Drawing&lt;br /&gt;&lt;span style="color: blue;"&gt;Imports &lt;/span&gt;System.Windows.Forms&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue;"&gt;Public Class &lt;/span&gt;WindowManager&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue;"&gt;Private Sub New&lt;/span&gt;()&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue;"&gt;End Sub&lt;br /&gt;&lt;br /&gt;Public Shared ReadOnly Property &lt;/span&gt;ActiveWindowPointer() &lt;span style="color: blue;"&gt;As &lt;/span&gt;IntPtr&lt;br /&gt;&lt;span style="color: blue;"&gt;Get&lt;br /&gt;Try&lt;br /&gt;Return &lt;/span&gt;WindowsAPI.GetActiveWindow()&lt;br /&gt;&lt;span style="color: blue;"&gt;Catch&lt;br /&gt;Return &lt;/span&gt;0&lt;br /&gt;&lt;span style="color: blue;"&gt;End Try&lt;br /&gt;End Get&lt;br /&gt;End Property&lt;br /&gt;&lt;br /&gt;Public Shared ReadOnly Property &lt;/span&gt;ForegroundWindowPointer() &lt;span style="color: blue;"&gt;As &lt;/span&gt;IntPtr&lt;br /&gt;&lt;span style="color: blue;"&gt;Get&lt;br /&gt;Try&lt;br /&gt;Return &lt;/span&gt;WindowsAPI.GetForegroundWindow()&lt;br /&gt;&lt;span style="color: blue;"&gt;Catch&lt;br /&gt;Return &lt;/span&gt;0&lt;br /&gt;&lt;span style="color: blue;"&gt;End Try&lt;br /&gt;End Get&lt;br /&gt;End Property&lt;br /&gt;&lt;br /&gt;Public Shared ReadOnly Property &lt;/span&gt;ForegroundWindow() &lt;span style="color: blue;"&gt;As &lt;/span&gt;IWin32Window&lt;br /&gt;&lt;span style="color: blue;"&gt;Get&lt;br /&gt;Return New &lt;/span&gt;WindowWrapper(ForegroundWindowPointer)&lt;br /&gt;&lt;span style="color: blue;"&gt;End Get&lt;br /&gt;End Property&lt;br /&gt;&lt;br /&gt;Public Shared ReadOnly Property &lt;/span&gt;ActiveWindowBounds() &lt;span style="color: blue;"&gt;As &lt;/span&gt;Rectangle&lt;br /&gt;&lt;span style="color: blue;"&gt;Get&lt;br /&gt;Dim &lt;/span&gt;r &lt;span style="color: blue;"&gt;As &lt;/span&gt;WindowsAPI.RECT = &lt;span style="color: blue;"&gt;New &lt;/span&gt;WindowsAPI.RECT(0, 0, 0, 0)&lt;br /&gt;&lt;span style="color: blue;"&gt;Dim &lt;/span&gt;found &lt;span style="color: blue;"&gt;As Boolean &lt;/span&gt;= WindowsAPI.GetWindowRect(ActiveWindowPointer, r)&lt;br /&gt;&lt;span style="color: blue;"&gt;If &lt;/span&gt;found &lt;span style="color: blue;"&gt;Then&lt;br /&gt;Return &lt;/span&gt;r.Rectangle&lt;br /&gt;&lt;span style="color: blue;"&gt;Else&lt;br /&gt;Return &lt;/span&gt;Screen.PrimaryScreen.Bounds&lt;br /&gt;&lt;span style="color: blue;"&gt;End If&lt;br /&gt;End Get&lt;br /&gt;End Property&lt;br /&gt;&lt;br /&gt;Public Shared Sub &lt;/span&gt;CenterFormToActiveWindow(&lt;span style="color: blue;"&gt;ByVal &lt;/span&gt;form &lt;span style="color: blue;"&gt;As &lt;/span&gt;Form)&lt;br /&gt;&lt;span style="color: blue;"&gt;Try&lt;br /&gt;&lt;br /&gt;Dim &lt;/span&gt;point &lt;span style="color: blue;"&gt;As &lt;/span&gt;Point = &lt;span style="color: blue;"&gt;New &lt;/span&gt;Point()&lt;br /&gt;&lt;span style="color: blue;"&gt;Dim &lt;/span&gt;formSize &lt;span style="color: blue;"&gt;As &lt;/span&gt;Size = form.Size&lt;br /&gt;&lt;span style="color: blue;"&gt;Dim &lt;/span&gt;workingArea &lt;span style="color: blue;"&gt;As &lt;/span&gt;Rectangle = ActiveWindowBounds&lt;br /&gt;point.X = (workingArea.X + (workingArea.Width / 2)) - (formSize.Width / 2)&lt;br /&gt;point.Y = (workingArea.Y + (workingArea.Height / 2)) - (formSize.Height / 2)&lt;br /&gt;form.Location = point&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue;"&gt;Catch&lt;br /&gt;&lt;br /&gt;End Try&lt;br /&gt;&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;End Class&lt;br /&gt;&lt;br /&gt;Public Class &lt;/span&gt;WindowWrapper&lt;br /&gt;&lt;span style="color: blue;"&gt;Implements &lt;/span&gt;IWin32Window&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue;"&gt;Dim &lt;/span&gt;_hwnd &lt;span style="color: blue;"&gt;As &lt;/span&gt;IntPtr&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue;"&gt;Public Sub New&lt;/span&gt;(&lt;span style="color: blue;"&gt;ByVal &lt;/span&gt;handle &lt;span style="color: blue;"&gt;As &lt;/span&gt;IntPtr)&lt;br /&gt;_hwnd = handle&lt;br /&gt;&lt;span style="color: blue;"&gt;End Sub&lt;br /&gt;&lt;br /&gt;Public ReadOnly Property &lt;/span&gt;Handle() &lt;span style="color: blue;"&gt;As &lt;/span&gt;IntPtr &lt;span style="color: blue;"&gt;Implements &lt;/span&gt;IWin32Window.Handle&lt;br /&gt;&lt;span style="color: blue;"&gt;Get&lt;br /&gt;Return &lt;/span&gt;_hwnd&lt;br /&gt;&lt;span style="color: blue;"&gt;End Get&lt;br /&gt;&lt;br /&gt;End Property&lt;br /&gt;&lt;br /&gt;End Class&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;br /&gt;&lt;hr /&gt;&lt;pre class="code"&gt;&lt;span style="color: blue;"&gt;Declare Function &lt;/span&gt;GetActiveWindow &lt;span style="color: blue;"&gt;Lib &lt;/span&gt;&lt;span style="color: #a31515;"&gt;"user32" &lt;/span&gt;&lt;span style="color: blue;"&gt;Alias &lt;/span&gt;&lt;span style="color: #a31515;"&gt;"GetActiveWindow" &lt;/span&gt;() &lt;span style="color: blue;"&gt;As &lt;/span&gt;IntPtr&lt;br /&gt;&lt;span style="color: blue;"&gt;Declare Function &lt;/span&gt;GetForegroundWindow &lt;span style="color: blue;"&gt;Lib &lt;/span&gt;&lt;span style="color: #a31515;"&gt;"user32" &lt;/span&gt;() &lt;span style="color: blue;"&gt;As &lt;/span&gt;IntPtr&lt;br /&gt;&lt;span style="color: blue;"&gt;Public Declare Function &lt;/span&gt;GetWindowRect &lt;span style="color: blue;"&gt;Lib &lt;/span&gt;&lt;span style="color: #a31515;"&gt;"user32" &lt;/span&gt;(&lt;span style="color: blue;"&gt;ByVal &lt;/span&gt;HWnd &lt;span style="color: blue;"&gt;As &lt;/span&gt;IntPtr, _&lt;br /&gt;&lt;span style="color: blue;"&gt;ByRef &lt;/span&gt;lpRect &lt;span style="color: blue;"&gt;As &lt;/span&gt;RECT) &lt;span style="color: blue;"&gt;As Boolean&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;br /&gt;&lt;hr /&gt;The way to use this is simple: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;If you’re launching a dialog form, just use the following line of code: &lt;p&gt;&lt;br /&gt;frm.ShowDialog(WindowManager.ForegroundWindow) &lt;br /&gt;&lt;br /&gt;and it will launch the form relative to the currently active Window. &lt;br /&gt;&lt;/li&gt;&lt;li&gt;That approach works for all dialog forms - if you’re launching a non-dialog form, you have to set the parent form inside the form constructor before you launch the form. &lt;/li&gt;&lt;/ul&gt;This approach has saved a lot of time and resulted in much cleaner code. &lt;br /&gt;&lt;br /&gt;Chuck&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4197233680252276272-1484837982882655470?l=chuckc3net.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chuckc3net.blogspot.com/feeds/1484837982882655470/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://chuckc3net.blogspot.com/2009/12/correctly-displaying-windows-forms.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4197233680252276272/posts/default/1484837982882655470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4197233680252276272/posts/default/1484837982882655470'/><link rel='alternate' type='text/html' href='http://chuckc3net.blogspot.com/2009/12/correctly-displaying-windows-forms.html' title='Correctly Displaying Windows Forms'/><author><name>chuckc3</name><uri>http://www.blogger.com/profile/07354338553743579477</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://1.bp.blogspot.com/_ARxmfr1lZpo/SxhjF98nd8I/AAAAAAAAAAM/musSGBc7Des/S220/CobbPicture.jpg'/></author><thr:total>0</thr:total></entry></feed>
