Groups | Blog | Home
all groups > dotnet component services > may 2005 >

dotnet component services : Mystical run time error when putting C# library in COM+ application


Thomas Evensen
5/21/2005 1:17:22 PM
Hello!



Short description of problem: My C# library works as a COM object (in
process), but when used in COM+ (out of process), I get some strange cast
error run time.



Long description of problem:

I have a C# library which holds a form with a microsoft web browser
component (AxSHDocVw.AxWebBrowser) in it. I have COM-enabled the library,
and using it as an in-process COM-object works real fine (though I have to
set the threading model from 'both' to 'apartment' in registry).



In adition I have a client which have to use my object out-of-process. I
solved this by creating a COM+ application, and set Activation to 'Server
application'. The client can now nicely load my library as an out-of-process
COM object. Then some really strange happens... :)



This code snippet of mine is invoked by the microsoft web browser component
when its browsing is finished (only the essential code is submitted):





-----8<-------8<-------8<-------8<-------8<-------8<--

private void webBrowser_DocumentComplete(object sender,
AxSHDocVw.DWebBrowserEvents2_DocumentCompleteEvent e)

{

try

{

ICustomDoc custDoc =
(MsHtmHstInterop.ICustomDoc)webBrowser.Document;

}

catch (Exception ex)

{

textBox1.Text += "\r\nwebBrowser_DocumentComplete
exception: " + ex.Message + "\r\n" + ex.StackTrace;

}

}

-----8<-------8<-------8<-------8<-------8<-------8<--



When loaded in-process as a regular COM object, this cast works just fine.
When registered in COM+ and loaded out of process, I get an invalid cast
exception, though the browser window

seems just fine, displaying the web page.



Any idea what causes this? Is there other ways to out-of-process enable a C#
COM object? I am really stuck on this one :)



Additional information:

When compiled as a library interop registered with ThreadingModel = both
(default), I receive the following exception when the library tries to
instantiate the Microsoft Web Browser (Shell.Explorer.2):



-----8<-------8<-------8<-------8<-------8<-------8<--

Invoke() failed with exception: source:'System.Windows.Forms', code:'0',
description:'Could not instantiate ActiveX control
'8856f961-340a-11d0-a96b-00c04fd705a2' because the current thread is not in
a single-threaded apartment.'

-----8<-------8<-------8<-------8<-------8<-------8<--



I solve this problem by manually setting the threading model of my library
to 'Apartment' instead of 'Both', which is default. (done with this registry
file:)



-----8<-------8<-------8<-------8<-------8<-------8<--

Windows Registry Editor Version 5.00



[HKEY_CLASSES_ROOT\CLSID\{FBA1E1CD-4397-11D4-9D5E-0080AD00E0D3}\InprocServer32]

"ThreadingModel"="Apartment"

-----8<-------8<-------8<-------8<-------8<-------8<--





How I create the COM+ application:



- Administrative Tools/Component Services/Com+ applications

- New Application

- Empty Application

- Server Application with name Proxy

- Run as interactive user

- Under Proxy/Components, New component

- Import component, choosing tct.proxy





Thanks!

Thomas Evensen

Thomas Evensen
5/21/2005 2:53:19 PM
The complete source code for my form:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using MsHtmHstInterop;
using mshtml;

namespace ComPlusTest
{
public class TestForm : System.Windows.Forms.Form
{
private AxSHDocVw.AxWebBrowser webBrowser;
private System.Windows.Forms.TextBox textBox1;
private System.ComponentModel.Container components = null;

public TestForm()
{
InitializeComponent();
}

protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

public bool init()
{
try
{
textBox1.Text = "initializing...";
System.Reflection.Assembly browserAssembly =
System.Reflection.Assembly.GetAssembly(typeof(AxSHDocVw.AxWebBrowser));
textBox1.Text += "\r\n" + String.Format("TctMainForm::init()
Initializing MainForm. Browser assemlby is {0} version {1}",
browserAssembly.Location, browserAssembly.GetName().Version.ToString());

System.Reflection.Assembly custDocAssembly =
System.Reflection.Assembly.GetAssembly(typeof(ICustomDoc));
textBox1.Text += "\r\n" + String.Format("TctMainForm::init()
Initializing MainForm. CustDoc assemlby is {0} version {1}",
custDocAssembly.Location, custDocAssembly.GetName().Version.ToString());

this.Location = new System.Drawing.Point(0, 0);
this.TopLevel = true;
}
catch (Exception ex)
{
textBox1.Text = "init error: " + ex.Message;
return false;
}
return true;
}

public void browse()
{
object nullObject = 0;
string str = "";
object nullObjStr = str;
object urlObj = "http://www.google.com";
webBrowser.Navigate2(ref urlObj, ref nullObject, ref nullObjStr, ref
nullObject, ref nullObjStr);
textBox1.Text += "\r\nbrowsing...";
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.Resources.ResourceManager resources = new
System.Resources.ResourceManager(typeof(TestForm));
this.webBrowser = new AxSHDocVw.AxWebBrowser();
this.textBox1 = new System.Windows.Forms.TextBox();
((System.ComponentModel.ISupportInitialize)(this.webBrowser)).BeginInit();
this.SuspendLayout();
//
// webBrowser
//
this.webBrowser.Enabled = true;
this.webBrowser.Location = new System.Drawing.Point(8, 8);
this.webBrowser.OcxState =
((System.Windows.Forms.AxHost.State)(resources.GetObject("webBrowser.OcxState")));
this.webBrowser.Size = new System.Drawing.Size(560, 352);
this.webBrowser.TabIndex = 1;
this.webBrowser.DocumentComplete += new
AxSHDocVw.DWebBrowserEvents2_DocumentCompleteEventHandler(this.webBrowser_DocumentComplete);
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(576, 8);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBox1.Size = new System.Drawing.Size(544, 352);
this.textBox1.TabIndex = 2;
this.textBox1.Text = "";
//
// TestForm
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(1128, 365);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.webBrowser);
this.Name = "TestForm";
this.Text = "TestForm";
((System.ComponentModel.ISupportInitialize)(this.webBrowser)).EndInit();
this.ResumeLayout(false);

}
#endregion

#region web browser stuff
private void webBrowser_DocumentComplete(object sender,
AxSHDocVw.DWebBrowserEvents2_DocumentCompleteEvent e)
{
try
{
textBox1.Text += "\r\ncasting from webBrowser.Document to ICustomDoc";
ICustomDoc custDoc = (MsHtmHstInterop.ICustomDoc)webBrowser.Document;
textBox1.Text += "\r\ncast to ICustomDoc performed";
}
catch (Exception ex)
{
textBox1.Text += "\r\nwebBrowser_DocumentComplete exception: " +
ex.Message + "\r\n" + ex.StackTrace + "\r\n" + ex.;
}
}
#endregion

}
}

AddThis Social Bookmark Button