Click here to Skip to main content
15,896,111 members
Articles / Programming Languages / C#

Receiving Events from late-bound COM servers

Rate me:
Please Sign up or sign in to vote.
4.98/5 (28 votes)
2 May 2005CPOL6 min read 157.5K   1.1K   42  
An article demonstrating how to receive events from a late-bound COM server using Microsoft Word as an example COM server.
namespace ZetaLateBindingComEvents
{
	#region Using directives.
	// ----------------------------------------------------------------------

	using System;
	using System.ComponentModel;
	using System.Diagnostics;
	using System.IO;
	using System.Reflection;
	using System.Runtime.CompilerServices;
	using System.Runtime.InteropServices;

	// ----------------------------------------------------------------------
	#endregion

	/////////////////////////////////////////////////////////////////////////

	/// <summary>
	/// The main application class of this sample.
	/// </summary>
	public class Program
	{
		#region Public methods.
		// ------------------------------------------------------------------

		/// <summary>
		/// The main entry point of the application.
		/// </summary>
		[STAThread]
		static void Main(
			string[] args )
		{
			// --
			// Create the basic objects.

			// The type of the Word application. Used for dynamically
			// creating.
			Type wordType = Type.GetTypeFromProgID( "Word.Application" );

			// The main Word application object.
			object wordApplication = Activator.CreateInstance( wordType );

			// --
			// Connect the event sink.

			// Get the connection point container.
			UCOMIConnectionPointContainer connectionPointContainer =
				wordApplication as UCOMIConnectionPointContainer;

			// The GUID of the connection point to query for.
			// This is the same as the GUID of the IApplicationEvents2.
			Guid guid = new Guid( "000209FE-0000-0000-C000-000000000046" );

			// Get the connection point of the given GUID.
			UCOMIConnectionPoint connectionPoint;
			connectionPointContainer.FindConnectionPoint( 
				ref guid, 
				out connectionPoint );

			// Create the actual object to receive the event
			// notifications.
			ApplicationEvents2_SinkHelper sink = 
				new ApplicationEvents2_SinkHelper();

			// Connect the sink.
			int sinkCookie;
			connectionPoint.Advise( sink, out sinkCookie );

			try
			{
				// --
				// Do some various late bound-operations.
				// Please note that this is NOT required for the events at
				// all, it is just a sample.

				// Show Word.
				wordType.InvokeMember(
					"Visible",
					BindingFlags.SetProperty,
					null,
					wordApplication,
					new object[]
					{
						true
					} );

				// Get the Documents collection.
				object wordDocuments = wordType.InvokeMember(
					"Documents",
					BindingFlags.GetProperty,
					null,
					wordApplication,
					new object[]
					{
					} );

				// Open a given Word document.
				object wordDocument = wordType.InvokeMember(
					"Open",
					BindingFlags.InvokeMethod,
					null,
					wordDocuments,
					new object[]
					{
						Path.Combine(
						Environment.CurrentDirectory,
						"MyWordDocument.doc" )
					} );

				// ... In a real-world example you would do further operations here ...

				// Close the document.
				wordType.InvokeMember(
					"Close",
					BindingFlags.InvokeMethod,
					null,
					wordDocument,
					new object[]
					{
					} );

				// Close the application.
				wordType.InvokeMember(
					"Quit",
					BindingFlags.InvokeMethod,
					null,
					wordApplication,
					new object[]
					{
					} );
			}
			finally
			{
				// --
				// Disconnect.

				// Disconnect the sink.
				connectionPoint.Unadvise( sinkCookie );

				// Release the com object.
				Marshal.ReleaseComObject( connectionPoint );
			}
		}

		// ------------------------------------------------------------------
		#endregion
	}

	/////////////////////////////////////////////////////////////////////////

	/// <summary>
	/// 1:1 Interface of the Microsoft Word IApplicationEvents2 interface.
	/// </summary>
	/// <remarks>This definition was copied from the disassembly of the
	/// Interop.Word.dll library opened in Lutz Roeder's .NET Reflector.All
	/// well-known-objects that are passed as parameters to the methods and
	/// which are not required in this sample are converted back to "object" types.</remarks>
	[ComImport, Guid("000209FE-0000-0000-C000-000000000046"), TypeLibType((short) 0x10d0)]
	public interface IApplicationEvents2
	{
		#region Interface methods.
		// ------------------------------------------------------------------

		[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(1), TypeLibFunc((short) 0x41)]
		void Startup();

		[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(2)]
		void Quit();

		[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(3)]
		void DocumentChange();

		[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(4)]
		void DocumentOpen([In, MarshalAs(UnmanagedType.Interface)] object Doc);

		[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(6)]
		void DocumentBeforeClose([In, MarshalAs(UnmanagedType.Interface)] object Doc, [In] ref bool Cancel);

		[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(7)]
		void DocumentBeforePrint([In, MarshalAs(UnmanagedType.Interface)] object Doc, [In] ref bool Cancel);

		[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(8)]
		void DocumentBeforeSave([In, MarshalAs(UnmanagedType.Interface)] object Doc, [In] ref bool SaveAsUI, [In] ref bool Cancel);

		[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(9)]
		void NewDocument([In, MarshalAs(UnmanagedType.Interface)] object Doc);

		[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(10)]
		void WindowActivate([In, MarshalAs(UnmanagedType.Interface)] object Doc, [In, MarshalAs(UnmanagedType.Interface)] object Wn);

		[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(11)]
		void WindowDeactivate([In, MarshalAs(UnmanagedType.Interface)] object Doc, [In, MarshalAs(UnmanagedType.Interface)] object Wn);

		[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(12)]
		void WindowSelectionChange([In, MarshalAs(UnmanagedType.Interface)] object Sel);

		[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(13)]
		void WindowBeforeRightClick([In, MarshalAs(UnmanagedType.Interface)] object Sel, [In] ref bool Cancel);

		[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(14)]
		void WindowBeforeDoubleClick([In, MarshalAs(UnmanagedType.Interface)] object Sel, [In] ref bool Cancel);

		// ------------------------------------------------------------------
		#endregion
	}

	/////////////////////////////////////////////////////////////////////////

	/// <summary>
	/// The class that implements the interface and receives the Word 
	/// event notifications.
	/// </summary>
	/// <remarks>This class was copied from the disassembly of the
	/// Interop.Word.dll library opened in Lutz Roeder's .NET Reflector.</remarks>
	[ClassInterface(ClassInterfaceType.None)]
	public sealed class ApplicationEvents2_SinkHelper : 
		IApplicationEvents2
	{
		#region Public methods.
		// ------------------------------------------------------------------

		public void Startup()
		{ 
			Trace.WriteLine( "Startup() called." );
		}

		public void Quit()
		{
			Trace.WriteLine( "Quit() called." );
		}

		public void DocumentChange()
		{
			Trace.WriteLine( "DocumentChange() called." );
		}

		public void DocumentOpen( object Doc)
		{
			Trace.WriteLine( "DocumentOpen() called." );
		}

		public void DocumentBeforeClose( object Doc,  ref bool Cancel)
		{ 
			Trace.WriteLine( "DocumentBeforeClose() called." );
		}

		public void DocumentBeforePrint( object Doc,  ref bool Cancel)
		{ 
			Trace.WriteLine( "DocumentBeforePrint() called." );
		}

		public void DocumentBeforeSave( object Doc,  ref bool SaveAsUI,  ref bool Cancel)
		{
			Trace.WriteLine( "DocumentBeforeSave() called." );
		}

		public void NewDocument( object Doc)
		{
			Trace.WriteLine( "NewDocument() called." );
		}

		public void WindowActivate( object Doc,  object Wn)
		{
			Trace.WriteLine( "WindowActivate() called." );
		}

		public void WindowDeactivate( object Doc,  object Wn)
		{
			Trace.WriteLine( "WindowDeactivate() called." );
		}

		public void WindowSelectionChange( object Sel)
		{ 
			Trace.WriteLine( "WindowSelectionChange() called." );
		}

		public void WindowBeforeRightClick( object Sel,  ref bool Cancel)
		{
			Trace.WriteLine( "WindowBeforeRightClick() called." );
		}

		public void WindowBeforeDoubleClick( object Sel,  ref bool Cancel)
		{ 
			Trace.WriteLine( "WindowBeforeDoubleClick() called." );
		}

		// ------------------------------------------------------------------
		#endregion
	}

	/////////////////////////////////////////////////////////////////////////
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer Zeta Software GmbH
Germany Germany
Uwe does programming since 1989 with experiences in Assembler, C++, MFC and lots of web- and database stuff and now uses ASP.NET and C# extensively, too. He has also teached programming to students at the local university.

➡️ Give me a tip 🙂

In his free time, he does climbing, running and mountain biking. In 2012 he became a father of a cute boy and in 2014 of an awesome girl.

Some cool, free software from us:

Windows 10 Ereignisanzeige  
German Developer Community  
Free Test Management Software - Intuitive, competitive, Test Plans.  
Homepage erstellen - Intuitive, very easy to use.  
Offline-Homepage-Baukasten

Comments and Discussions