com+, what more are needed?

  • Thread starter Thread starter Lasse Edsvik
  • Start date Start date
Lasse Edsvik said:
in this example i dont have to use transactions..... so i'll skip that and
learn that some other time then...

Serviced components are a bit harder to explain:

The following is an example from Amit Kalani's book for 70-320
It assumes that you have SQL Server with the Northwind database running locally

You can always get this:

Microsoft SQL Server 2000 Desktop Engine (MSDE 2000) Release A
http://www.microsoft.com/downloads/...D1-A0BC-479F-BAFA-E4B278EB9147&displaylang=en


The example involves to serviced components one for shipping, one for billing which
are used by an ordering component and finally a windows form client to use them.

Start by creating a blank solution in Visual Studio: ESTransApp
(File->New->Blank Solution)

CREATE NEW TABLES
-----------------

Open a Visual Studio .NET Command Prompt Window
Navigate to the project directory "ESTransApp" and create a file "ShipBill.sql" with the following contents:

SET quoted_identifier on
USE "Northwind"
GO
IF EXISTS (SELECT 1 FROM sysobjects WHERE id = object_id('dbo.Shipping') and sysstat & 0xf = 3)
drop table "dbo"."Shipping"
GO
IF EXISTS (SELECT 1 FROM sysobjects WHERE id = object_id('dbo.Billing') and sysstat & 0xf = 3)
drop table "dbo"."Billing"
GO
CREATE TABLE "Shipping" (
"ShippingID" "int" IDENTITY (1, 1) NOT NULL,
"CustomerID" "nchar" (5) NOT NULL ,
"ProductID" "int" NOT NULL ,
"DateTime" "datetime" NOT NULL,
CONSTRAINT "PK_Shipping" PRIMARY KEY CLUSTERED (
"ShippingID"
),
CONSTRAINT "FK_Shipping_Customers" FOREIGN KEY (
"CustomerID"
) REFERENCES "dbo"."Customers" (
"CustomerID"
),
CONSTRAINT "FK_Shipping_Products" FOREIGN KEY (
"ProductID"
) REFERENCES "dbo"."Products" (
"ProductID"
)
)
GO
CREATE TABLE "Billing" (
"BillingID" "int" IDENTITY (1, 1) NOT NULL,
"CustomerID" "nchar" (5) NOT NULL ,
"ProductID" "int" NOT NULL ,
"DateTime" "datetime" NOT NULL,
CONSTRAINT "PK_Billing" PRIMARY KEY CLUSTERED (
"BillingID"
),
CONSTRAINT "FK_Billing_Customers" FOREIGN KEY (
"CustomerID"
) REFERENCES "dbo"."Customers" (
"CustomerID"
),
CONSTRAINT "FK_Billing_Products" FOREIGN KEY (
"ProductID"
) REFERENCES "dbo"."Products" (
"ProductID"
)
)
GO



The in the command prompt window run the following command:

osql -E -i ShipBill.sql

This should create the new tables


CREATE Strong Name key
----------------------
The in the command prompt window navigate to the solution directory "ESTransApp"
and the strong name key file "ESTransApp.snk":

sn -k ESTransApp.snk


CREATE Shipping Component
-------------------------

1) Add a new Visual C#: Class Library "ShipTrans" to your "ESTransApp" Solution.

2) Add a reference to enterprise services. Right-Click the project
"Add Reference->.NET System.Enterprise.Services"
Click "Select", Click "OK"

3) Rename the file "Shipping.cs" and enter the following:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.EnterpriseServices;
using System.Runtime.InteropServices;

namespace ShipTrans {

public interface IShipping {
void ShipItem( string customerID, int productID );
}

// Get your own GUID: Tools->Create GUID "Registry Format" - Copy
[Transaction(TransactionOption.Supported)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("8D8B0556-FB6B-4ce6-948C-20F158987236")]
public class Shipping : ServicedComponent, IShipping {

SqlConnection cnn_ = null;

public Shipping() {
cnn_ = new SqlConnection(
"data source=(local)"
+ ";initial catalog=Northwind"
+ ";integrated security=SSPI"
);
}

#region IShipping Members
[AutoComplete(true)]
public void ShipItem(string customerID, int productID) {
SqlDateTime dt = new SqlDateTime( DateTime.Now );
SqlCommand cmd = cnn_.CreateCommand();
cmd.CommandText = string.Format(
"INSERT INTO Shipping ("
+ "CustomerID, ProductID, DateTime"
+ ") VALUES ("
+ "'{0}','{1}','{2}'"
+ ")",
customerID,
productID,
dt
);
cnn_.Open();
cmd.ExecuteNonQuery();
}
#endregion
}
}


4) Add the following at the top to the AssemblyInfo.cs file of the "ShipTrans" project:

using System.EnterpriseServices;

and modify (or add) the following in AssemblyInfo.cs

[assembly: ApplicationName("Shipping Application")]
[assembly: Description("Ship Orders")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: AssemblyVersion("1.0.0")]
[assembly: AssemblyKeyFile("../../../ESTransApp.snk")]
[assembly: ApplicationAccessControl(false)]


5) Build the project

6) Install the component to the Global assembly Cache (not technically required but good practice)
The in the command prompt window navigate to the project output directory "ESTransApp\ShipTrans\bin\Debug"
and issue the following command:

gacutil -i ShipTrans.dll

7) Register the serviced component with the COM+ Catalog:
The in the command prompt window navigate to the project output directory "ESTransApp\ShipTrans\bin\Debug"
and issue the following command:

regsvcs ShipTrans.dll

Ignore - WARNING: The class 'ShipTrans.Shipping' has no class interface, which means that unmanaged
late bound calls cannot take advantage of AutoComplete methods.

8) Check Serviced components.
Open the "Component Services" MMI plugin (Control Panel->Adminstrative Tools->Component Services) or
on the command line:

%SystemRoot%\system32\Com\comexp.msc

Drill down

Component Services->Computers->My Computers->COM+ Applications

One of the applications should state "Shipping Application" - the recently registered serviced component.


CREATE Billing Component
-------------------------

1) Add a new Visual C#: Class Library "BillTrans" to your "ESTransApp" Solution.

2) Add a reference to enterprise services. Right-Click the project
"Add Reference->.NET System.Enterprise.Services"
Click "Select", Click "OK"

3) Rename the file "Billing.cs" and enter the following:


using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.EnterpriseServices;
using System.Runtime.InteropServices;

namespace BillTrans {

public interface IBilling {
void BillCustomer( string customerID, int productID );
}

// Get your own GUID: Tools->Create GUID "Registry Format" - Copy
[Transaction(TransactionOption.Supported)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("2B2A9DE2-2CD9-40cf-BA34-2323B52B0F31")]
public class Billing : ServicedComponent, IBilling {

SqlConnection cnn_ = null;

public Billing() {
cnn_ = new SqlConnection(
"data source=(local)"
+ ";initial catalog=Northwind"
+ ";integrated security=SSPI"
);
}

#region IBilling Members
[AutoComplete(true)]
public void BillCustomer(string customerID, int productID) {
SqlDateTime dt = new SqlDateTime( DateTime.Now );
SqlCommand cmd = cnn_.CreateCommand();
cmd.CommandText = string.Format(
"INSERT INTO Billing ("
+ "CustomerID, ProductID, DateTime"
+ ") VALUES ("
+ "'{0}','{1}','{2}'"
+ ")",
customerID,
productID,
dt
);
cnn_.Open();
cmd.ExecuteNonQuery();
}
#endregion
}
}


4) Add the following at the top to the AssemblyInfo.cs file of the "BillTrans" project:

using System.EnterpriseServices;

and modify (or add) the following in AssemblyInfo.cs

[assembly: ApplicationName("Billing Application")]
[assembly: Description("Bill Customers")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationAccessControl(false)]
[assembly: AssemblyVersion("1.0.0")]
[assembly: AssemblyKeyFile("../../../ESTransApp.snk")]

5) Build the project

6) Install the component to the Global assembly Cache (not technically required but good practice)
The in the command prompt window navigate to the project output directory "ESTransApp\BillTrans\bin\Debug"
and issue the following command:

gacutil -i BillTrans.dll

7) Register the serviced component with the COM+ Catalog:
The in the command prompt window navigate to the project output directory "ESTransApp\BillTrans\bin\Debug"
and issue the following command:

regsvcs BillTrans.dll

Ignore - WARNING: The class 'OrderTrans.Shipping' has no class interface, which means that unmanaged
late bound calls cannot take advantage of AutoComplete methods.

8) Check Serviced components.
Open the "Component Services" MMI plugin (Control Panel->Adminstrative Tools->Component Services) or
on the command line:

%SystemRoot%\system32\Com\comexp.msc

Drill down

Component Services->Computers->My Computers->COM+ Applications

One of the applications should state "Billing Application" - the recently registered serviced component.


CREATE Ordering Component
-------------------------
1) Add a new Visual C#: Class Library "OrderTrans" to your "ESTransApp" Solution.

2) Add a reference to enterprise services. Right-Click the project
"Add Reference->.NET System.Enterprise.Services"
Click "Select", Click "OK"

3) Add references to the other projects. Right-Click the "OrderTrans" project
"Add Reference->Projects BillTrans"
Click "Select"
"Add Reference->Projects ShipTrans"
Click "Select"
Click "OK"


4) Rename the file "Ordering.cs" and enter the following:


using System;
using System.EnterpriseServices;
using System.Runtime.InteropServices;
using ShipTrans;
using BillTrans;

namespace OrderTrans {

public interface IOrdering {
void PlaceOrder( string customerID, int productID );
}

// Get your own GUID: Tools->Create GUID "Registry Format" - Copy
[Transaction(TransactionOption.RequiresNew)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("D229FB99-2FC7-4961-94FA-981E747F215B")]
public class Ordering : ServicedComponent, IOrdering {

public Ordering() {}

#region IOrdering Members
[AutoComplete(true)]
public void PlaceOrder(string customerID, int productID) {
Billing billing = new Billing();
billing.BillCustomer( customerID, productID );

Shipping shipping = new Shipping();
shipping.ShipItem( customerID, productID );
}
#endregion
}
}

5) Add the following at the top to the AssemblyInfo.cs file of the "OrderTrans" project:

using System.EnterpriseServices;

and modify (or add) the following in AssemblyInfo.cs

[assembly: ApplicationName("Ordering Application")]
[assembly: Description("Places an Order")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationAccessControl(false)]
[assembly: AssemblyVersion("1.0.0")]
[assembly: AssemblyKeyFile("../../../ESTransApp.snk")]

6) Build the project

7) Install the component to the Global assembly Cache (not technically required but good practice)
The in the command prompt window navigate to the project output directory "ESTransApp\OrderTrans\bin\Debug"
and issue the following command:

gacutil -i OrderTrans.dll

8) Register the serviced component with the COM+ Catalog:
The in the command prompt window navigate to the project output directory "ESTransApp\BillTrans\bin\Debug"
and issue the following command:

regsvcs OrderTrans.dll

Ignore - WARNING: The class 'OrderTrans.Shipping' has no class interface, which means that unmanaged
late bound calls cannot take advantage of AutoComplete methods.

9) Check Serviced components.
Open the "Component Services" MMI plugin (Control Panel->Adminstrative Tools->Component Services) or
on the command line:

%SystemRoot%\system32\Com\comexp.msc

Drill down

Component Services->Computers->My Computers->COM+ Applications

One of the applications should state "Ordering Application" - the recently registered serviced component.


CREATE Serviced Components Client (Windows Forms)
-------------------------------------------------

1) Add a new Visual C#: Windows Application "OrderApp" to your "ESTransApp" Solution.
Right-Click the project and click "Set As Start-up Project".

2) Add a reference to enterprise services. Right-Click the project
"Add Reference->.NET System.Enterprise.Services"
Click "Select", Click "OK"

3) Add references to the "OrderTrans" project. Right-Click the "OrderApp" project
"Add Reference->Projects OrderTrans"
Click "Select"
Click "OK"

4) Rename the file "Form1.cs" to "OrderForm.cs" and enter the following:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;
using OrderTrans;

namespace OrderApp {

public class OrderForm : System.Windows.Forms.Form {

private System.Windows.Forms.GroupBox gbOrderInfo;
private System.Windows.Forms.Label lblCustomer;
private System.Windows.Forms.Label lblProduct;
private System.Windows.Forms.Button btnOrder;
private System.ComponentModel.Container components = null;
private System.Windows.Forms.ComboBox cboProducts;
private System.Windows.Forms.ComboBox cboCustomers;

private DataSet dsInfo_ = null;

public OrderForm () {
InitializeComponent();
}

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

#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()
{
this.gbOrderInfo = new System.Windows.Forms.GroupBox();
this.lblProduct = new System.Windows.Forms.Label();
this.lblCustomer = new System.Windows.Forms.Label();
this.cboCustomers = new System.Windows.Forms.ComboBox();
this.cboProducts = new System.Windows.Forms.ComboBox();
this.btnOrder = new System.Windows.Forms.Button();
this.gbOrderInfo.SuspendLayout();
this.SuspendLayout();
//
// gbOrderInfo
//
this.gbOrderInfo.Controls.Add(this.btnOrder);
this.gbOrderInfo.Controls.Add(this.cboProducts);
this.gbOrderInfo.Controls.Add(this.lblProduct);
this.gbOrderInfo.Controls.Add(this.lblCustomer);
this.gbOrderInfo.Controls.Add(this.cboCustomers);
this.gbOrderInfo.Location = new System.Drawing.Point(8, 8);
this.gbOrderInfo.Name = "gbOrderInfo";
this.gbOrderInfo.Size = new System.Drawing.Size(336, 136);
this.gbOrderInfo.TabIndex = 0;
this.gbOrderInfo.TabStop = false;
this.gbOrderInfo.Text = "Ordering Information";
//
// lblProduct
//
this.lblProduct.Location = new System.Drawing.Point(16, 57);
this.lblProduct.Name = "lblProduct";
this.lblProduct.Size = new System.Drawing.Size(64, 23);
this.lblProduct.TabIndex = 2;
this.lblProduct.Text = "&Product";
this.lblProduct.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lblCustomer
//
this.lblCustomer.Location = new System.Drawing.Point(16, 25);
this.lblCustomer.Name = "lblCustomer";
this.lblCustomer.Size = new System.Drawing.Size(64, 23);
this.lblCustomer.TabIndex = 0;
this.lblCustomer.Text = "&Customer";
this.lblCustomer.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// cboCustomers
//
this.cboCustomers.Location = new System.Drawing.Point(96, 24);
this.cboCustomers.Name = "cboCustomers";
this.cboCustomers.Size = new System.Drawing.Size(216, 24);
this.cboCustomers.TabIndex = 1;
//
// cboProducts
//
this.cboProducts.Location = new System.Drawing.Point(96, 56);
this.cboProducts.Name = "cboProducts";
this.cboProducts.Size = new System.Drawing.Size(216, 24);
this.cboProducts.TabIndex = 3;
//
// btnOrder
//
this.btnOrder.Location = new System.Drawing.Point(104, 96);
this.btnOrder.Name = "btnOrder";
this.btnOrder.Size = new System.Drawing.Size(96, 23);
this.btnOrder.TabIndex = 4;
this.btnOrder.Text = "Place Order";
this.btnOrder.Click += new System.EventHandler(this.btnOrder_Click);
//
// OrderForm
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);
this.ClientSize = new System.Drawing.Size(352, 153);
this.Controls.Add(this.gbOrderInfo);
this.Name = "OrderForm";
this.Text = "Order Form";
this.Load += new System.EventHandler(this.OrderForm_Load);
this.gbOrderInfo.ResumeLayout(false);
this.ResumeLayout(false);

}
#endregion

[STAThread]
static void Main() {
Application.Run(new OrderForm());
}

private void OrderForm_Load(object sender, System.EventArgs e) {

SqlConnection cnn = new SqlConnection(
"data source=(local)"
+ ";initial catalog=Northwind"
+ ";integrated security=SSPI"
);

// Load Customers
SqlCommand cmdCustomers = cnn.CreateCommand();
cmdCustomers.CommandType = CommandType.Text;
cmdCustomers.CommandText =
"SELECT CompanyName, CustomerID FROM Customers";

SqlDataAdapter daCustomers = new SqlDataAdapter();
daCustomers.SelectCommand = cmdCustomers;

// Load Products
SqlCommand cmdProducts = cnn.CreateCommand();
cmdProducts.CommandType = CommandType.Text;
cmdProducts.CommandText =
"SELECT ProductName, ProductID FROM Products";

SqlDataAdapter daProducts = new SqlDataAdapter();
daProducts.SelectCommand = cmdProducts;

dsInfo_ = new DataSet();

daCustomers.Fill( dsInfo_, "Customers" );
daProducts.Fill( dsInfo_, "Products" );

// Bind comboboxes
cboCustomers.DataSource = dsInfo_;
cboCustomers.DisplayMember = "Customers.CompanyName";
cboCustomers.ValueMember = "Customers.CustomerID";

cboProducts.DataSource = dsInfo_;
cboProducts.DisplayMember = "Products.ProductName";
cboProducts.ValueMember = "Products.ProductID";

} // end event handler OrderForm_Load

private void btnOrder_Click(object sender, System.EventArgs e) {
try {
// Ordering Serviced component is used here
Ordering ordering = new Ordering();
ordering.PlaceOrder(
cboCustomers.SelectedValue.ToString(),
(int) cboProducts.SelectedValue
);
MessageBox.Show( "Order Placed Successfully" );


} catch ( Exception ex ) {
MessageBox.Show( ex.Message );
}
} // end event handler btnOrder_Click
}
}


5) Build the project

6) Run OrderApp. You should be able to place an order.

7) Now go into the "Component Services" console and disable the "Shipping Application".
If you try to place an order now, an exception will be thrown and the transaction is aborted;
i.e. there will be no Billing record without a shipping record.
 
This is an example (a rather long one at that). It has been my experience to
learn the "why" and "what" of a technology is just as important as "how."
You need to know why you would want or need a distributed transaction before
you go off and see how to do it. ES/COM+ is also a lot more than this.
Without the need for Distributed Transactions, and he doesn't, basic COM
Interop applies and the article I cited explains the "why" of COM Interop
and then an example on how to do it.

--
--------------------------------------------------------------
Sam Gentile [C#/.NET MVP]
..NET Blog http://samgentile.com/blog/
MSDN Column:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/bridge.asp
Please reply only to the newsgroup so that others can benefit.
This posting is provided "AS IS" with no warranties, and confers no rights.
---------------------------------------------------------------
UAError said:
Serviced components are a bit harder to explain:

The following is an example from Amit Kalani's book for 70-320
It assumes that you have SQL Server with the Northwind database running locally

You can always get this:

Microsoft SQL Server 2000 Desktop Engine (MSDE 2000) Release A
http://www.microsoft.com/downloads/...D1-A0BC-479F-BAFA-E4B278EB9147&displaylang=en


The example involves to serviced components one for shipping, one for billing which
are used by an ordering component and finally a windows form client to use them.

Start by creating a blank solution in Visual Studio: ESTransApp
(File->New->Blank Solution)

CREATE NEW TABLES
"ShipBill.sql" with the following contents:
SET quoted_identifier on
USE "Northwind"
GO
IF EXISTS (SELECT 1 FROM sysobjects WHERE id = object_id('dbo.Shipping') and sysstat & 0xf = 3)
drop table "dbo"."Shipping"
GO
IF EXISTS (SELECT 1 FROM sysobjects WHERE id = object_id('dbo.Billing') and sysstat & 0xf = 3)
drop table "dbo"."Billing"
GO
CREATE TABLE "Shipping" (
"ShippingID" "int" IDENTITY (1, 1) NOT NULL,
"CustomerID" "nchar" (5) NOT NULL ,
"ProductID" "int" NOT NULL ,
"DateTime" "datetime" NOT NULL,
CONSTRAINT "PK_Shipping" PRIMARY KEY CLUSTERED (
"ShippingID"
),
CONSTRAINT "FK_Shipping_Customers" FOREIGN KEY (
"CustomerID"
) REFERENCES "dbo"."Customers" (
"CustomerID"
),
CONSTRAINT "FK_Shipping_Products" FOREIGN KEY (
"ProductID"
) REFERENCES "dbo"."Products" (
"ProductID"
)
)
GO
CREATE TABLE "Billing" (
"BillingID" "int" IDENTITY (1, 1) NOT NULL,
"CustomerID" "nchar" (5) NOT NULL ,
"ProductID" "int" NOT NULL ,
"DateTime" "datetime" NOT NULL,
CONSTRAINT "PK_Billing" PRIMARY KEY CLUSTERED (
"BillingID"
),
CONSTRAINT "FK_Billing_Customers" FOREIGN KEY (
"CustomerID"
) REFERENCES "dbo"."Customers" (
"CustomerID"
),
CONSTRAINT "FK_Billing_Products" FOREIGN KEY (
"ProductID"
) REFERENCES "dbo"."Products" (
"ProductID"
)
)
GO



The in the command prompt window run the following command:

osql -E -i ShipBill.sql

This should create the new tables


CREATE Strong Name key
----------------------
The in the command prompt window navigate to the solution directory "ESTransApp"
and the strong name key file "ESTransApp.snk":

sn -k ESTransApp.snk


CREATE Shipping Component
-------------------------

1) Add a new Visual C#: Class Library "ShipTrans" to your "ESTransApp" Solution.

2) Add a reference to enterprise services. Right-Click the project
"Add Reference->.NET System.Enterprise.Services"
Click "Select", Click "OK"

3) Rename the file "Shipping.cs" and enter the following:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.EnterpriseServices;
using System.Runtime.InteropServices;

namespace ShipTrans {

public interface IShipping {
void ShipItem( string customerID, int productID );
}

// Get your own GUID: Tools->Create GUID "Registry Format" - Copy
[Transaction(TransactionOption.Supported)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("8D8B0556-FB6B-4ce6-948C-20F158987236")]
public class Shipping : ServicedComponent, IShipping {

SqlConnection cnn_ = null;

public Shipping() {
cnn_ = new SqlConnection(
"data source=(local)"
+ ";initial catalog=Northwind"
+ ";integrated security=SSPI"
);
}

#region IShipping Members
[AutoComplete(true)]
public void ShipItem(string customerID, int productID) {
SqlDateTime dt = new SqlDateTime( DateTime.Now );
SqlCommand cmd = cnn_.CreateCommand();
cmd.CommandText = string.Format(
"INSERT INTO Shipping ("
+ "CustomerID, ProductID, DateTime"
+ ") VALUES ("
+ "'{0}','{1}','{2}'"
+ ")",
customerID,
productID,
dt
);
cnn_.Open();
cmd.ExecuteNonQuery();
}
#endregion
}
}


4) Add the following at the top to the AssemblyInfo.cs file of the "ShipTrans" project:

using System.EnterpriseServices;

and modify (or add) the following in AssemblyInfo.cs

[assembly: ApplicationName("Shipping Application")]
[assembly: Description("Ship Orders")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: AssemblyVersion("1.0.0")]
[assembly: AssemblyKeyFile("../../../ESTransApp.snk")]
[assembly: ApplicationAccessControl(false)]


5) Build the project

6) Install the component to the Global assembly Cache (not technically required but good practice)
The in the command prompt window navigate to the project output directory "ESTransApp\ShipTrans\bin\Debug"
and issue the following command:

gacutil -i ShipTrans.dll

7) Register the serviced component with the COM+ Catalog:
The in the command prompt window navigate to the project output directory "ESTransApp\ShipTrans\bin\Debug"
and issue the following command:

regsvcs ShipTrans.dll

Ignore - WARNING: The class 'ShipTrans.Shipping' has no class interface, which means that unmanaged
late bound calls cannot take advantage of AutoComplete methods.

8) Check Serviced components.
Open the "Component Services" MMI plugin (Control Panel->Adminstrative Tools->Component Services) or
on the command line:

%SystemRoot%\system32\Com\comexp.msc

Drill down

Component Services->Computers->My Computers->COM+ Applications

One of the applications should state "Shipping Application" - the recently registered serviced component.


CREATE Billing Component
-------------------------

1) Add a new Visual C#: Class Library "BillTrans" to your "ESTransApp" Solution.

2) Add a reference to enterprise services. Right-Click the project
"Add Reference->.NET System.Enterprise.Services"
Click "Select", Click "OK"

3) Rename the file "Billing.cs" and enter the following:


using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.EnterpriseServices;
using System.Runtime.InteropServices;

namespace BillTrans {

public interface IBilling {
void BillCustomer( string customerID, int productID );
}

// Get your own GUID: Tools->Create GUID "Registry Format" - Copy
[Transaction(TransactionOption.Supported)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("2B2A9DE2-2CD9-40cf-BA34-2323B52B0F31")]
public class Billing : ServicedComponent, IBilling {

SqlConnection cnn_ = null;

public Billing() {
cnn_ = new SqlConnection(
"data source=(local)"
+ ";initial catalog=Northwind"
+ ";integrated security=SSPI"
);
}

#region IBilling Members
[AutoComplete(true)]
public void BillCustomer(string customerID, int productID) {
SqlDateTime dt = new SqlDateTime( DateTime.Now );
SqlCommand cmd = cnn_.CreateCommand();
cmd.CommandText = string.Format(
"INSERT INTO Billing ("
+ "CustomerID, ProductID, DateTime"
+ ") VALUES ("
+ "'{0}','{1}','{2}'"
+ ")",
customerID,
productID,
dt
);
cnn_.Open();
cmd.ExecuteNonQuery();
}
#endregion
}
}


4) Add the following at the top to the AssemblyInfo.cs file of the "BillTrans" project:

using System.EnterpriseServices;

and modify (or add) the following in AssemblyInfo.cs

[assembly: ApplicationName("Billing Application")]
[assembly: Description("Bill Customers")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationAccessControl(false)]
[assembly: AssemblyVersion("1.0.0")]
[assembly: AssemblyKeyFile("../../../ESTransApp.snk")]

5) Build the project

6) Install the component to the Global assembly Cache (not technically required but good practice)
The in the command prompt window navigate to the project output directory "ESTransApp\BillTrans\bin\Debug"
and issue the following command:

gacutil -i BillTrans.dll

7) Register the serviced component with the COM+ Catalog:
The in the command prompt window navigate to the project output directory "ESTransApp\BillTrans\bin\Debug"
and issue the following command:

regsvcs BillTrans.dll

Ignore - WARNING: The class 'OrderTrans.Shipping' has no class interface, which means that unmanaged
late bound calls cannot take advantage of AutoComplete methods.

8) Check Serviced components.
Open the "Component Services" MMI plugin (Control Panel->Adminstrative Tools->Component Services) or
on the command line:

%SystemRoot%\system32\Com\comexp.msc

Drill down

Component Services->Computers->My Computers->COM+ Applications

One of the applications should state "Billing Application" - the recently registered serviced component.


CREATE Ordering Component
-------------------------
1) Add a new Visual C#: Class Library "OrderTrans" to your "ESTransApp" Solution.

2) Add a reference to enterprise services. Right-Click the project
"Add Reference->.NET System.Enterprise.Services"
Click "Select", Click "OK"

3) Add references to the other projects. Right-Click the "OrderTrans" project
"Add Reference->Projects BillTrans"
Click "Select"
"Add Reference->Projects ShipTrans"
Click "Select"
Click "OK"


4) Rename the file "Ordering.cs" and enter the following:


using System;
using System.EnterpriseServices;
using System.Runtime.InteropServices;
using ShipTrans;
using BillTrans;

namespace OrderTrans {

public interface IOrdering {
void PlaceOrder( string customerID, int productID );
}

// Get your own GUID: Tools->Create GUID "Registry Format" - Copy
[Transaction(TransactionOption.RequiresNew)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("D229FB99-2FC7-4961-94FA-981E747F215B")]
public class Ordering : ServicedComponent, IOrdering {

public Ordering() {}

#region IOrdering Members
[AutoComplete(true)]
public void PlaceOrder(string customerID, int productID) {
Billing billing = new Billing();
billing.BillCustomer( customerID, productID );

Shipping shipping = new Shipping();
shipping.ShipItem( customerID, productID );
}
#endregion
}
}

5) Add the following at the top to the AssemblyInfo.cs file of the "OrderTrans" project:

using System.EnterpriseServices;

and modify (or add) the following in AssemblyInfo.cs

[assembly: ApplicationName("Ordering Application")]
[assembly: Description("Places an Order")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationAccessControl(false)]
[assembly: AssemblyVersion("1.0.0")]
[assembly: AssemblyKeyFile("../../../ESTransApp.snk")]

6) Build the project

7) Install the component to the Global assembly Cache (not technically required but good practice)
The in the command prompt window navigate to the project output directory "ESTransApp\OrderTrans\bin\Debug"
and issue the following command:

gacutil -i OrderTrans.dll

8) Register the serviced component with the COM+ Catalog:
The in the command prompt window navigate to the project output directory "ESTransApp\BillTrans\bin\Debug"
and issue the following command:

regsvcs OrderTrans.dll

Ignore - WARNING: The class 'OrderTrans.Shipping' has no class interface, which means that unmanaged
late bound calls cannot take advantage of AutoComplete methods.

9) Check Serviced components.
Open the "Component Services" MMI plugin (Control Panel->Adminstrative Tools->Component Services) or
on the command line:

%SystemRoot%\system32\Com\comexp.msc

Drill down

Component Services->Computers->My Computers->COM+ Applications

One of the applications should state "Ordering Application" - the recently registered serviced component.


CREATE Serviced Components Client (Windows Forms)
-------------------------------------------------

1) Add a new Visual C#: Windows Application "OrderApp" to your "ESTransApp" Solution.
Right-Click the project and click "Set As Start-up Project".

2) Add a reference to enterprise services. Right-Click the project
"Add Reference->.NET System.Enterprise.Services"
Click "Select", Click "OK"

3) Add references to the "OrderTrans" project. Right-Click the "OrderApp" project
"Add Reference->Projects OrderTrans"
Click "Select"
Click "OK"

4) Rename the file "Form1.cs" to "OrderForm.cs" and enter the following:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;
using OrderTrans;

namespace OrderApp {

public class OrderForm : System.Windows.Forms.Form {

private System.Windows.Forms.GroupBox gbOrderInfo;
private System.Windows.Forms.Label lblCustomer;
private System.Windows.Forms.Label lblProduct;
private System.Windows.Forms.Button btnOrder;
private System.ComponentModel.Container components = null;
private System.Windows.Forms.ComboBox cboProducts;
private System.Windows.Forms.ComboBox cboCustomers;

private DataSet dsInfo_ = null;

public OrderForm () {
InitializeComponent();
}

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

#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()
{
this.gbOrderInfo = new System.Windows.Forms.GroupBox();
this.lblProduct = new System.Windows.Forms.Label();
this.lblCustomer = new System.Windows.Forms.Label();
this.cboCustomers = new System.Windows.Forms.ComboBox();
this.cboProducts = new System.Windows.Forms.ComboBox();
this.btnOrder = new System.Windows.Forms.Button();
this.gbOrderInfo.SuspendLayout();
this.SuspendLayout();
//
// gbOrderInfo
//
this.gbOrderInfo.Controls.Add(this.btnOrder);
this.gbOrderInfo.Controls.Add(this.cboProducts);
this.gbOrderInfo.Controls.Add(this.lblProduct);
this.gbOrderInfo.Controls.Add(this.lblCustomer);
this.gbOrderInfo.Controls.Add(this.cboCustomers);
this.gbOrderInfo.Location = new System.Drawing.Point(8, 8);
this.gbOrderInfo.Name = "gbOrderInfo";
this.gbOrderInfo.Size = new System.Drawing.Size(336, 136);
this.gbOrderInfo.TabIndex = 0;
this.gbOrderInfo.TabStop = false;
this.gbOrderInfo.Text = "Ordering Information";
//
// lblProduct
//
this.lblProduct.Location = new System.Drawing.Point(16, 57);
this.lblProduct.Name = "lblProduct";
this.lblProduct.Size = new System.Drawing.Size(64, 23);
this.lblProduct.TabIndex = 2;
this.lblProduct.Text = "&Product";
this.lblProduct.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lblCustomer
//
this.lblCustomer.Location = new System.Drawing.Point(16, 25);
this.lblCustomer.Name = "lblCustomer";
this.lblCustomer.Size = new System.Drawing.Size(64, 23);
this.lblCustomer.TabIndex = 0;
this.lblCustomer.Text = "&Customer";
this.lblCustomer.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// cboCustomers
//
this.cboCustomers.Location = new System.Drawing.Point(96, 24);
this.cboCustomers.Name = "cboCustomers";
this.cboCustomers.Size = new System.Drawing.Size(216, 24);
this.cboCustomers.TabIndex = 1;
//
// cboProducts
//
this.cboProducts.Location = new System.Drawing.Point(96, 56);
this.cboProducts.Name = "cboProducts";
this.cboProducts.Size = new System.Drawing.Size(216, 24);
this.cboProducts.TabIndex = 3;
//
// btnOrder
//
this.btnOrder.Location = new System.Drawing.Point(104, 96);
this.btnOrder.Name = "btnOrder";
this.btnOrder.Size = new System.Drawing.Size(96, 23);
this.btnOrder.TabIndex = 4;
this.btnOrder.Text = "Place Order";
this.btnOrder.Click += new System.EventHandler(this.btnOrder_Click);
//
// OrderForm
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);
this.ClientSize = new System.Drawing.Size(352, 153);
this.Controls.Add(this.gbOrderInfo);
this.Name = "OrderForm";
this.Text = "Order Form";
this.Load += new System.EventHandler(this.OrderForm_Load);
this.gbOrderInfo.ResumeLayout(false);
this.ResumeLayout(false);

}
#endregion

[STAThread]
static void Main() {
Application.Run(new OrderForm());
}

private void OrderForm_Load(object sender, System.EventArgs e) {

SqlConnection cnn = new SqlConnection(
"data source=(local)"
+ ";initial catalog=Northwind"
+ ";integrated security=SSPI"
);

// Load Customers
SqlCommand cmdCustomers = cnn.CreateCommand();
cmdCustomers.CommandType = CommandType.Text;
cmdCustomers.CommandText =
"SELECT CompanyName, CustomerID FROM Customers";

SqlDataAdapter daCustomers = new SqlDataAdapter();
daCustomers.SelectCommand = cmdCustomers;

// Load Products
SqlCommand cmdProducts = cnn.CreateCommand();
cmdProducts.CommandType = CommandType.Text;
cmdProducts.CommandText =
"SELECT ProductName, ProductID FROM Products";

SqlDataAdapter daProducts = new SqlDataAdapter();
daProducts.SelectCommand = cmdProducts;

dsInfo_ = new DataSet();

daCustomers.Fill( dsInfo_, "Customers" );
daProducts.Fill( dsInfo_, "Products" );

// Bind comboboxes
cboCustomers.DataSource = dsInfo_;
cboCustomers.DisplayMember = "Customers.CompanyName";
cboCustomers.ValueMember = "Customers.CustomerID";

cboProducts.DataSource = dsInfo_;
cboProducts.DisplayMember = "Products.ProductName";
cboProducts.ValueMember = "Products.ProductID";

} // end event handler OrderForm_Load

private void btnOrder_Click(object sender, System.EventArgs e) {
try {
// Ordering Serviced component is used here
Ordering ordering = new Ordering();
ordering.PlaceOrder(
cboCustomers.SelectedValue.ToString(),
(int) cboProducts.SelectedValue
);
MessageBox.Show( "Order Placed Successfully" );


} catch ( Exception ex ) {
MessageBox.Show( ex.Message );
}
} // end event handler btnOrder_Click
}
}


5) Build the project

6) Run OrderApp. You should be able to place an order.

7) Now go into the "Component Services" console and disable the "Shipping Application".
If you try to place an order now, an exception will be thrown and the transaction is aborted;
i.e. there will be no Billing record without a shipping record.
 
Sam,

could you translate this into C#?


interface IMSDNComServer : IDispatch
{
[id(1), helpstring("method SquareIt")] HRESULT SquareIt([in] double dNum,
[out] double *dTheSquare);
};

coclass MSDNComServer
{
[default] interface IMSDNComServer;
};

In the file MSDNComServer.cpp, the SquareIt method looks like the following:

STDMETHODIMP CMSDNComServer::SquareIt(double dNum, double *dTheSquare)
{

*dTheSquare = dNum * dNum;

return S_OK;
}





Sam Gentile said:
To have a full understanding of how to do "regular" COM Interop, please read
my MSDN piece
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/bridge.asp

I am told that many people have found it very useful to understand all the
questions you are asking. Please read and then I'll be happy to answer any
remaining questions.
--------------------------------------------------------------
Sam Gentile [C#/.NET MVP]
.NET Blog http://samgentile.com/blog/
MSDN Column:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/bridge.asp
Please reply only to the newsgroup so that others can benefit.
This posting is provided "AS IS" with no warranties, and confers no rights.
---------------------------------------------------------------
Lasse Edsvik said:
Sam,

in this example i dont have to use transactions..... so i'll skip that and
learn that some other time then...

how i make this a "regular" COM app?


using System;

using System.EnterpriseServices;

[assembly: ApplicationName("COMTest")]

[assembly: AssemblyKeyFile("COMTest.snk")]

namespace COMTest

{

public class Class1 : ServicedComponent

{

public Class1() {}

public string WriteShit()

{

return "shite";

}

}

}



Sam Gentile said:
trying to build a simple COM app that i'll use in regular ASP-pages
Why are using ES/COM+ then? Do you have distributed transactions or other
needs that require COM+/ES services? If not, all you need is COM Interop

--
Sam Gentile [C#/.NET MVP]
.NET Blog http://samgentile.com/blog/
MSDN Column:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/bridge.asp
Please reply only to the newsgroup so that others can benefit.
This posting is provided "AS IS" with no warranties, and confers no rights.
Sam,

trying to build a simple COM app that i'll use in regular ASP-pages

/Lasse


Are you creating a COM+ server or library component? It makes a
difference.
This is controlled by:
[assembly: ApplicationActivation(ActivationOption.Server)]

Or

[assembly: ApplicationActivation(ActivationOption.Library)]



While convenient, the lazy registration in step 9 does not work
in
many
scenarios as it requires Admin rights as well as other issues. So really
the
right way. So the correct way that will work in all scenarios is replace
step 9 by:

9) gacutil.exe - i COMtest.dll (this puts it in the GAC)

10) regsvcs.exe COMtest.sll (this makes it a configured
coomponent in the COM+ catalog)


--
Sam Gentile [C#/.NET MVP]
.NET Blog http://samgentile.com/blog/
MSDN Column:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/bridge.asp should
it
be
in
AssemblyInfo.cs?


looks like this now:

using System;

using System.EnterpriseServices;

[assembly: ApplicationName("COMTest")]

[assembly: AssemblyKeyFile("COMTest.snk")]

namespace COMTest

{

public class Class1 : ServicedComponent

{

public Class1() {}

public string WriteShit()

{

return "shite";

}







in Assemblyinfo.cs its:





[assembly: AssemblyDelaySign(false)]

[assembly: AssemblyKeyFile("")]

[assembly: AssemblyKeyName("")]





You are missing a few steps, basically the assembly attributes so
that
"Lazy
registration" can occur in the COM+ catalog. Without that step you
have
to
do an explicit regsvcs.exe. Here are the steps from a blog
post
of
mine:
1.. Create a DLL project
2.. Add a Reference to System.EnterpriseServices
3.. Add a using declaration: using System.EnterpriseServices;
4.. Inherit your classes from ServicedComponent (i.e. public
Widget
:
ServicedComponent)
5.. Stick an [assembly: ApplicationName("ComPlusApp")] at
the
top
so
that
"COMPlusApp" or whatever is the name of the application when
it
is
registered in the COM+ catalog.
6.. Stick a strong name attribute at the top of the file
[assembly:
AssemblyKeyFile("ComPlus.snk")]
7.. Go to the command line and generate a Strong Name sn -k
ComPlus.snk
8.. If you have some method that performs a transaction, put
[AutoComplete] on top of it
9.. Build - This will lazy register the COM+ app in the COM+
catalog
(In
some circumstances I will go into detail in a future article, you
may
have
to do use regsvcs.exe ComPlusApp.dll)
10.. Create a client that references
System.EnterpriseServices
and
calls
your COM+ method(s)
11.. Run it
See http://samgentile.com/blog/archive/2003/06/25/7844.aspx

----
Sam Gentile [C#/.NET MVP]
.NET Blog http://samgentile.com/blog/
MSDN Column:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/bridge.asp
confers
no
http://msdn.microsoft.com/library/en-us/dndotnet/html/entserv.asp?frame=true
 
Sam Gentile said:
This is an example (a rather long one at that). It has been my experience to
learn the "why" and "what" of a technology is just as important as "how."
You need to know why you would want or need a distributed transaction before
you go off and see how to do it. ES/COM+ is also a lot more than this.
Without the need for Distributed Transactions, and he doesn't, basic COM
Interop applies and the article I cited explains the "why" of COM Interop
and then an example on how to do it.

--
--------------------------------------------------------------
Sam Gentile [C#/.NET MVP]
.NET Blog http://samgentile.com/blog/
MSDN Column:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/bridge.asp
Please reply only to the newsgroup so that others can benefit.
This posting is provided "AS IS" with no warranties, and confers no rights.
---------------------------------------------------------------

(Sorry for posting this out-of-sequence but my news server seems to be sluggish...
above came from google)

I couldn't agree with you more. The reason why I posted this was the OP's statement
"...transactions..... so i'll skip that and learn that some other time then...". I simply
wanted to provide a working sample for him to "play" with, something that could be easily
broken and fixed again (learing by disection). It should provide plenty of material
for many trips to the MSDN to learn more about Enterprise Services.

Unfortunately many people balk at learning about COM/COM+ with C++ source even though
it is the "mother-language" of that technology (which also explains why most of the better
COM+ books use C++).
 
Lasse Edsvik said:
works in a .vbs file, but why cant i use it in a .asp page?

<%
set cls = CreateObject("shit.shitclass")
a=cls.WriteShit()
response.write(a)
%>


i get error on the createobject line........ and it doesnt matter if its
server.createobject......

/Lasse

Just ran the following without any problems (as COMApp.asp):

<%@ Language = "VBScript" %>

<html>

<%
Dim oCsC
Dim msg
Set oCsC = CreateObject("COMApp.CSharpClass")
msg = oCsC.MyMethod
%>

<head>
</head>
<body>
<p><% =msg %></p>
</body>
and when i register it in component manager the method wont show
anywhere......

/Lasse

I don't know what you mean by "Component Manager". I haven't been looking
at anything but VS.NET 2003 for months now ...

Instead of

regasm /nologo /codebase COMApp.dll

try

regasm /nologo /codebase /tlb:COMApp.tlb COMApp.dll

That will create the type library for the COMApp.dll and enter it in the registry.
Thats what it took for the COMApp to show up in the "Add Reference" Dialog COM tab in
VS.NET.
 
Lasse Edsvik said:
Sam,

could you translate this into C#?


interface IMSDNComServer : IDispatch
{
[id(1), helpstring("method SquareIt")] HRESULT SquareIt([in] double dNum,
[out] double *dTheSquare);
};

coclass MSDNComServer
{
[default] interface IMSDNComServer;
};

In the file MSDNComServer.cpp, the SquareIt method looks like the following:

STDMETHODIMP CMSDNComServer::SquareIt(double dNum, double *dTheSquare)
{

*dTheSquare = dNum * dNum;

return S_OK;
}


I think you are missing the point. That code is destined to create a COM component
that is to be accessed FROM the .NET environment.

You are concerned with making a .NET assembly and the classes therein available TO
the COM environment. So really, the pertinent section of that article is:

"The COM Callable Wrapper (CCW)"

the remainder of the article deals with .NET using a COM component (not the other way around).
The same sort of principles apply in reverse but the "execution" is quite different.

You will have to become familiar with:

..NET Framework Developer's Guide: Packaging an Assembly for COM
http://msdn.microsoft.com/library/d...cpguide/html/cpconpackagingassemblyforcom.asp

..NET Framework Developer's Guide: Assembly to Type Library Conversion Summary
http://msdn.microsoft.com/library/d...conAssemblyToTypeLibraryConversionSummary.asp

..NET Framework Developer's Guide: Exported Type Conversion
http://msdn.microsoft.com/library/d...us/cpguide/html/cpcontlbexptypeconversion.asp


To control aspects of the COM interface that will be generated you will have to become familiar with:

..NET Framework Class Library: System.Runtime.InteropServices Namespace
http://msdn.microsoft.com/library/d...ef/html/frlrfsystemruntimeinteropservices.asp

..NET Framework Class Library: ComVisibleAttribute Class
http://msdn.microsoft.com/library/d...eropservicescomvisibleattributeclasstopic.asp

..NET Framework Class Library: InterfaceTypeAttribute Class
http://msdn.microsoft.com/library/d...pservicesinterfacetypeattributeclasstopic.asp

and so on...

which unfortunately means you are going to have to learn how COM works (to some extent) even though you working in .NET.

This might be more to your liking:

COM and .NET Interoperability
by Andrew Troelsen
Paperback: 816 pages
Publisher: APress; 1st edition (April 25, 2002)
ISBN: 1590590112

http://www.amazon.com/exec/obidos/t...f=sr_1_2/103-9037164-2087023?v=glance&s=books
http://www.apress.com/book/bookDisplay.html?bID=81
http://www.apress.com/ApressCorporate/supplement/1/81/1590590112-371.pdf
 
UAError is right. You are taking my article's code and twisting it and
missing the point. There is a COM component in C++ in the article. You don't
need to care about it. You need to learn how to call COM components from C#.
Did you read the article at all or just go to the code? It's all there. You
don't need to translate the IMSDNComServer into C#!



UAError said:
Lasse Edsvik said:
Sam,

could you translate this into C#?


interface IMSDNComServer : IDispatch
{
[id(1), helpstring("method SquareIt")] HRESULT SquareIt([in] double dNum,
[out] double *dTheSquare);
};

coclass MSDNComServer
{
[default] interface IMSDNComServer;
};

In the file MSDNComServer.cpp, the SquareIt method looks like the following:

STDMETHODIMP CMSDNComServer::SquareIt(double dNum, double *dTheSquare)
{

*dTheSquare = dNum * dNum;

return S_OK;
}


I think you are missing the point. That code is destined to create a COM component
that is to be accessed FROM the .NET environment.

You are concerned with making a .NET assembly and the classes therein available TO
the COM environment. So really, the pertinent section of that article is:

"The COM Callable Wrapper (CCW)"

the remainder of the article deals with .NET using a COM component (not the other way around).
The same sort of principles apply in reverse but the "execution" is quite different.

You will have to become familiar with:

.NET Framework Developer's Guide: Packaging an Assembly for COM
http://msdn.microsoft.com/library/d...cpguide/html/cpconpackagingassemblyforcom.asp

.NET Framework Developer's Guide: Assembly to Type Library Conversion Summaryhttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconAssemblyToTypeLibraryConversionSummary.asp

.NET Framework Developer's Guide: Exported Type Conversion
http://msdn.microsoft.com/library/d...us/cpguide/html/cpcontlbexptypeconversion.asp


To control aspects of the COM interface that will be generated you will have to become familiar with:

.NET Framework Class Library: System.Runtime.InteropServices Namespace
http://msdn.microsoft.com/library/d...ef/html/frlrfsystemruntimeinteropservices.asp

.NET Framework Class Library: ComVisibleAttribute Class
http://msdn.microsoft.com/library/d...eropservicescomvisibleattributeclasstopic.asp

.NET Framework Class Library: InterfaceTypeAttribute Class
http://msdn.microsoft.com/library/d...pservicesinterfacetypeattributeclasstopic.asp

and so on...

which unfortunately means you are going to have to learn how COM works (to
some extent) even though you working in .NET.
 
Back
Top