Click here to Skip to main content
15,889,595 members
Articles / Programming Languages / C#
Article

Word Control for .NET

Rate me:
Please Sign up or sign in to vote.
4.85/5 (50 votes)
28 Jan 2003GPL33 min read 1.2M   46.5K   193   229
Writing a control to use MS-Word in your own Application like a windows-form.

Sample Image - winwordcontrol.jpg

Introduction

This control allows you to use MS Word 2000 in your own projects such as a windows form. Of course that's a little "dirty trick". But if you have some documentation to display and you want to use Word for it, here is the solution.

Background

I was working on an internal research project and we developed a tool to teach C++, and there was a problem about how to display the exercises. The main problem was, I had difficult formulas in these descriptions so the only possible solution was to convert the files to PDF or to another file format. With PDF I had a problem, because I couldn't edit the documents afterwards. So, I was looking for an ActiveX or .NET control for MS Word. Finally, I couldn't find one. So I decided to write one for .NET.

How to use the control?

It's almost too easy to use the form. You just need to add a link to the winwordcontrol.dll.  The steps are:

  1. Goto your Toolbox.

    Visual Studio Toolbox
     

  2. Click right. Select "Customize Toolbox".

    Toolbox Cutomizing
     

  3. Select the ".NET Components" tab.
  4. Select the winwordcontrol.dll using the file browse dialog. Click OK. After that you will find a new form in your toolbox called "winwordcontrol".

    Toolbox winwordcontrol/winwordcontrol

Drag and drop it just like any other form. The only thing you should know is how to control it. At this moment, there are four methods:

winwordcontrolinstance.LoadDocument(<string path>); 
With LoadDocument you can load all files Word can handle. Please specify the complete path! This is the only method that is probably useful for everyone. All the other methods are not necessary for normal use.
winwordcontrolinstance.CloseControl(); 
This method closes the actual document. This is mostly not necessary because LoadDocument() can handle multiple calls without calling CloseControl() before.
winwordcontrolinstance.PreActivate(); 
Preloading. This method should be used if you don't want to wait in the main program until Word is finished starting.
winwordcontrolinstance.RestoreWord(); 
Reactivates all the Menubars.

The control will automatically start Word if it's not already open and it will display the document.

How does this work?

The basic idea is to instantiate the Word application, as everybody knows, with:

wordInstance = new Word.Application();
Now we have the Word application in a separate window. How do we get this window in our control? The answer is ... Win32 API. We need to import some API functions from user32.dll as shown here:
[DllImport("user32.dll")]
public static extern int FindWindow(string strclassName, string strWindowName);

[DllImport("user32.dll")]
static extern int SetParent(int hWndChild, int hWndNewParent);

[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
static extern bool SetWindowPos(
	int hWnd,               // handle to window
	int hWndInsertAfter,    // placement-order handle
	int X,                  // horizontal position
	int Y,                  // vertical position
	int cx,                 // width
	int cy,                 // height
	uint uFlags             // window-positioning options
);
		
[DllImport("user32.dll", EntryPoint = "MoveWindow")]
static extern bool MoveWindow(
	int hWnd, 
	int X, 
	int Y, 
	int nWidth, 
	int nHeight, 
	bool bRepaint
);
							
const int SWP_DRAWFRAME = 0x20;
const int SWP_NOMOVE = 0x2;
const int SWP_NOSIZE = 0x1;
const int SWP_NOZORDER = 0x4;
This is the most complicated part... because it's NOT documented at all. We need a Pointer to the Word window, so we use FindWindow to find it. What's the name of the window? - "Opusapp" Actually, I don't know what this name means, but it works perfectly.
wordWnd = FindWindow( "Opusapp", null);
So, now we can define our control as a parent to Word:
SetWindowPos(wordWnd, this.Handle.ToInt32(), 0, 0,
	this.Bounds.Width-20, this.Bounds.Height-20,
	SWP_NOZORDER | SWP_NOMOVE | SWP_DRAWFRAME );
Everything else should be pretty easy and it is well documented in the official documentation for the Word namespace.

Points of Interest

You may be interested in my other projects. Please visit my private homepage www.intercompu.de. If you use this stuff or if you use just parts of it, I would appreciate if you mention my name. ;-)

History

  • 23.01.03 First release
  • 25.01.03 Update minor changes (performance enhancement)

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
CEO
Germany Germany
I am a developer with a Computer Science degree. I am programming Visual C ++ for over 7 year now and C# for about 3 years. If you want to know more about me please look at my homepage: www.intercompu.de

Comments and Discussions

 
QuestionProblem with opening/Saving a Document PinPopular
Rakesh B Singh23-Feb-07 2:21
Rakesh B Singh23-Feb-07 2:21 
AnswerRe: Problem with opening/Saving a Document [modified] Pin
npkinh17-May-07 23:15
npkinh17-May-07 23:15 
AnswerRe: Problem with opening/Saving a Document Pin
bidalah16-Aug-07 10:30
bidalah16-Aug-07 10:30 
AnswerRe: Problem with opening/Saving a Document Pin
aerradi18-Aug-07 17:14
aerradi18-Aug-07 17:14 
AnswerRe: Problem with opening/Saving a Document Pin
Pritesh Aryan20-Nov-12 18:50
Pritesh Aryan20-Nov-12 18:50 
GeneralError While Processing another word document in running state of this control Pin
sdivya12-Jan-07 14:49
sdivya12-Jan-07 14:49 
GeneralHate to say this.... Pin
Ross Holder6-Dec-06 12:49
Ross Holder6-Dec-06 12:49 
GeneralRe: Hate to say this.... Pin
bidalah16-Aug-07 10:40
bidalah16-Aug-07 10:40 
You're right about it being inoperative out of the box. Not sure which platform it was originally coded in. But I've managed to get it up in running on VS2005 using Office Pro2003. Following is the code for winwordcontrol.cs with my changes. In addition, if your solution is referencing the Microsoft 12.0 Object Library (it will be if the code went through VS's conversion routine), you will need to delete that reference and add a reference to the Microsoft 11.0 Object Library. Good Luck!

(Everything below this line)

/// This code is written by Matthias Haenel
/// contact: www.intercopmu.de
///
/// you can use it free of charge, but please
/// mention my name Wink | ;)
///
/// WinWordControl utilizes MS-WinWord2000 and
/// WinWord-XP
///
/// It simulates a form element, with simple tricks.
///


using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Runtime.InteropServices;


namespace WinWordControl
{
public class DocumentInstanceException : Exception
{}

public class ValidDocumentException : Exception
{}

public class WordInstanceException : Exception
{}

///
/// WinWordControl allows you to load doc-Files to your
/// own application without any loss, because it uses
/// the real WinWord.
///

public class WinWordControl : System.Windows.Forms.UserControl
{

[DllImport("user32.dll")]
public static extern int FindWindow(string strclassName, string strWindowName);

[DllImport("user32.dll")]
static extern int SetParent( int hWndChild, int hWndNewParent);

[DllImport("user32.dll", EntryPoint="SetWindowPos")]
static extern bool SetWindowPos(
int hWnd, // handle to window
int hWndInsertAfter, // placement-order handle
int X, // horizontal position
int Y, // vertical position
int cx, // width
int cy, // height
uint uFlags // window-positioning options
);

[DllImport("user32.dll", EntryPoint="MoveWindow")]
static extern bool MoveWindow(
int hWnd,
int X,
int Y,
int nWidth,
int nHeight,
bool bRepaint
);



/* I was testing wheater i could fix some exploid bugs or not.
* I left this stuff in here for people who need to know how to
* interface the Win32-API

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}

[DllImport("user32.dll")]
public static extern int GetWindowRect(int hwnd, ref RECT rc);

[DllImport("user32.dll")]
public static extern IntPtr PostMessage(
int hWnd,
int msg,
int wParam,
int lParam
);
*/

const int SWP_DRAWFRAME = 0x20;
const int SWP_NOMOVE = 0x2;
const int SWP_NOSIZE = 0x1;
const int SWP_NOZORDER = 0x4;


private Word.Document document;
private static Word.ApplicationClass wd = null;
public static int wordWnd = 0;
public static string filename = null;
private static bool deactivateevents = false;

///
/// needed designer variable
///

private System.ComponentModel.Container components = null;

public WinWordControl()
{
InitializeComponent();
}

///
/// cleanup Ressources
///

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

#region Component Designer generated code
///
/// !do not alter this code! It's designer code
///

private void InitializeComponent()
{
//
// WinWordControl
//
this.Name = "WinWordControl";
this.Size = new System.Drawing.Size(440, 336);
this.Resize += new System.EventHandler(this.OnResize);
}
#endregion


///
/// Preactivation
/// It's usefull, if you need more speed in the main Program
/// so you can preload Word.
///

public void PreActivate()
{
if(wd == null) wd = new Word.ApplicationClass();
}


///
/// Close the current Document in the control --> you can
/// load a new one with LoadDocument
///

public void CloseControl()
{
/*
* this code is to reopen Word.
*/

try
{
deactivateevents = true;
object dummy=null;
document.Close(ref dummy, ref dummy, ref dummy);
document.Application.Quit(ref dummy, ref dummy, ref dummy);
deactivateevents = false;
}
catch
{
}
}


///
/// catches Word's close event
/// starts a Thread that send a ESC to the word window Wink | ;)
///

/// <param name="doc" />
/// <param name="test" />
private void OnClose(Word.Document doc, ref bool chancel)
{
if(!deactivateevents)
{
chancel=true;
}
}

///
/// catches Word's open event
/// just close
///

/// <param name="doc" />
private void OnOpenDoc(Word.Document doc)
{
OnNewDoc(doc);
}

///
/// catches Word's newdocument event
/// just close
///

/// <param name="doc" />
private void OnNewDoc(Word.Document doc)
{
if(!deactivateevents)
{
deactivateevents=true;
object dummy = null;
doc.Close(ref dummy,ref dummy,ref dummy);
deactivateevents=false;
}
}




///
/// catches Word's quit event
/// normally it should not fire, but just to be shure
/// safely release the internal Word Instance
///

private void OnQuit()
{
//wd=null;
}


///
/// Loads a document into the control
///

/// <param name="t_filename" />path to the file (every type word can handle)
public void LoadDocument(string t_filename)
{
Object SaveasUI = false;
Object Cancel = true;
Object truy = true;
deactivateevents = true;
filename = t_filename;

if(wd == null) wd = new Word.ApplicationClass();
try
{
wd.AddIns.Add("VisualADP.dot", ref truy);
wd.CommandBars.AdaptiveMenus = false;
wd.DocumentBeforeClose += new Word.ApplicationEvents4_DocumentBeforeCloseEventHandler(OnClose);
((Word.ApplicationEvents4_Event)wd).NewDocument += new Word.ApplicationEvents4_NewDocumentEventHandler(OnNewDoc);
/// wd.NewDocument += new Word.ApplicationEvents4_NewDocumentEventHandler(OnNewDoc);
wd.DocumentOpen += new Word.ApplicationEvents4_DocumentOpenEventHandler(OnOpenDoc);
wd.ApplicationEvents4_Event_Quit += new Word.ApplicationEvents4_QuitEventHandler(OnQuit);
}
/// Word.ApplicationEvents4_NewDocumentEventHandler
catch{}

if(document != null)
{
try
{
object dummy=null;
wd.Documents.Close(ref dummy, ref dummy, ref dummy);
}
catch{}
}

if( wordWnd==0 ) wordWnd = FindWindow( "Opusapp", null);
if (wordWnd!=0)
{
SetParent( wordWnd, this.Handle.ToInt32());

object fileName = filename;
object newTemplate = false;
object docType = 0;
object readOnly = true;
object isVisible = true;
object missing = System.Reflection.Missing.Value;

try
{
if( wd == null )
{
throw new WordInstanceException();
}

if( wd.Documents == null )
{
throw new DocumentInstanceException();
}

if( wd != null && wd.Documents != null )
{
document = wd.Documents.Add(ref fileName, ref newTemplate, ref docType, ref isVisible);
}

if(document == null)
{
throw new ValidDocumentException();
}
}
catch
{
}

try
{
wd.ActiveWindow.DisplayRightRuler=false;
wd.ActiveWindow.DisplayScreenTips=false;
wd.ActiveWindow.DisplayVerticalRuler=false;
wd.ActiveWindow.DisplayRightRuler=false;
wd.ActiveWindow.ActivePane.DisplayRulers=false;
wd.ActiveWindow.ActivePane.View.Type = Word.WdViewType.wdWebView; // .wdNormalView;
}
catch
{

}

int counter = wd.ActiveWindow.Application.CommandBars.Count;
for(int i = 0; i < counter;i++)
{
try
{
wd.ActiveWindow.Application.CommandBars[i].Enabled=false;
}
catch
{

}
}
try
{
wd.Visible = true;
wd.Activate();

SetWindowPos(wordWnd,this.Handle.ToInt32(),0,0,this.Bounds.Width+20,this.Bounds.Height+20, SWP_NOZORDER | SWP_NOMOVE | SWP_DRAWFRAME);
MoveWindow(wordWnd,-5,-23,this.Bounds.Width+10,this.Bounds.Height+57,true);
}
catch
{
MessageBox.Show("Error: do not load the document into the control until the parent window is shown!");
}
this.Parent.Focus();

}
deactivateevents = false;
}


///
/// restores Word.
/// If the program crashed somehow.
/// Sometimes Word saves it's temporary settings Frown | :(
///

public void RestoreWord()
{
try
{
int counter = wd.ActiveWindow.Application.CommandBars.Count;
for(int i = 0; i < counter;i++)
{
try
{
wd.ActiveWindow.Application.CommandBars[i].Enabled=true;
}
catch
{

}
}
}
catch{};
}

///
/// internal resize function
/// utilizes the size of the surrounding control
///
/// optimzed for Word2000 but it works pretty good with WordXP too.
///

/// <param name="sender" />
/// <param name="e" />
private void OnResize(object sender, System.EventArgs e)
{
MoveWindow(wordWnd,-5,-23,this.Bounds.Width+10,this.Bounds.Height+57,true);
}
}
}


Mike Cooper
GeneralMS Project Pin
jamesrgoodwin6-Dec-06 4:46
jamesrgoodwin6-Dec-06 4:46 
GeneralRun more than one instance Pin
ItsKodali4-Dec-06 19:21
ItsKodali4-Dec-06 19:21 
Questionhow to set readonly property for winwordcontrol Pin
tanthanhduy17-Oct-06 17:43
tanthanhduy17-Oct-06 17:43 
QuestionHow to enable document Pin
tanthanhduy15-Oct-06 17:16
tanthanhduy15-Oct-06 17:16 
AnswerRe: How to enable document Pin
Rakesh B Singh23-Feb-07 2:27
Rakesh B Singh23-Feb-07 2:27 
QuestionFocus and Z order Pin
stealth2415-Oct-06 10:05
stealth2415-Oct-06 10:05 
GeneralREAD ONLY Pin
NikeshM22-Jul-06 23:16
NikeshM22-Jul-06 23:16 
QuestionHow do I open documents? Pin
mkamioner20-Jul-06 12:33
mkamioner20-Jul-06 12:33 
GeneralProblem... Pin
sam_g123-Mar-06 1:06
sam_g123-Mar-06 1:06 
Generali wrote a Excel Control follow your idea then how can i close the excel application Pin
StinJia21-Mar-06 21:59
StinJia21-Mar-06 21:59 
GeneralRe: i wrote a Excel Control follow your idea then how can i close the excel application Pin
sam_g122-Mar-06 0:41
sam_g122-Mar-06 0:41 
GeneralRe: i wrote a Excel Control follow your idea then how can i close the excel application Pin
Michael Cowan3-Sep-07 14:19
Michael Cowan3-Sep-07 14:19 
GeneralRe: i wrote a Excel Control follow your idea then how can i close the excel application Pin
Puzzle Fun20-May-08 7:44
Puzzle Fun20-May-08 7:44 
Questionhow to open the existing PPT file through this control Pin
sam_g121-Mar-06 0:45
sam_g121-Mar-06 0:45 
AnswerRe: how to open the existing PPT file through this control Pin
Member 415515116-Mar-09 0:06
Member 415515116-Mar-09 0:06 
GeneralNo overload for 'OnClose' matches delegate 'Microsoft.Office.Interop.PowerPoint.EApplication_PresentationCloseEventHandler' Pin
sam_g121-Mar-06 0:42
sam_g121-Mar-06 0:42 
Questioncan we use it in web applicaiton too... Pin
sam_g119-Mar-06 23:11
sam_g119-Mar-06 23:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.