HOWTO: Build a Microsoft Word Add-in (WLL) Using Visual C++
ID: Q183758
|
The information in this article applies to:
-
Microsoft Office 2000 Developer
-
Microsoft Visual C++, 32-bit Editions, version 5.0
-
Microsoft Word 97 for Windows
SUMMARY
A WLL is an add-in for Microsoft Word that you can build with any compiler
that supports building DLLs (dynamic link libraries). This article is
designed to get you started building WLLs with Microsoft Visual C++ 5.0. To
follow the steps outlined in this article, you should have some experience
building DLLs and you should have the Microsoft Word Developer's Kit, which
contains the necessary files to build a WLL.
For information about how to obtain the Word Developer's Kit, see the
Microsoft Press Web site at the following address:
http://mspress.microsoft.com/
MORE INFORMATIONCreate a WLL
- Create a new MFC AppWizard (.dll) project called ANewWLL.
- Copy capilib.c, capilib.h, wdcapi.h, wdcmds.h, wderror.h, wdfid.h, and config.h from the Microsoft Word Developer's kit to your project directory.
- Rename capilib.c to capilib.cpp.
- Add capilib.c, capilib.h, wdcapi.h, wdcmds.h, wderror.h, wdfid.h, and
config.h to your project.
- Add the following as the very first line of capilib.cpp to avoid
compiler errors about pre-compiled headers:
#include "stdafx.h"
- In the CallCapi() function in capilib.cpp, change the following line:
InitWCB( lpwcb, retType, lpBuffer, cBufferSize );
to the following:
InitWCB( lpwcb, retType, (UCHAR *)lpBuffer, cBufferSize );
Change the following lines:
case 's':
AddStringParam( lpwcb, va_arg(marker, LPSTR));
to the following:
case 's':
AddStringParam( lpwcb, (UCHAR *)va_arg(marker, LPSTR));
- At the end of the capilib.cpp file, change the following lines:
static short (WINAPI *pfn_wdCommandDispatch) ();
short WINAPI wdCommandDispatch(short CommandID, // fci
short DlgOptions, // grfDlg
short cArgs,
LPWDOPR lpwdoprArgs,
LPWDOPR lpwdoprReturn)
{
if (pfn_wdCommandDispatch == NULL)
FARPROC) pfn_wdCommandDispatch = GetProcAddress(
GetModuleHandle(NULL), "wdCommandDispatch"
);
return ((*pfn_wdCommandDispatch)(
CommandID, DlgOptions, cArgs, lpwdoprArgs, lpwdoprReturn)
);
}
to the following:
typedef unsigned short (CALLBACK *URET) (
short, short, short, LPWDOPR, LPWDOPR
);
URET pfn_wdCommandDispatch;
short WINAPI wdCommandDispatch(short CommandID, // fci
short DlgOptions, // grfDlg
short cArgs,
LPWDOPR lpwdoprArgs,
LPWDOPR lpwdoprReturn)
{
if (pfn_wdCommandDispatch == NULL)
pfn_wdCommandDispatch = (URET)GetProcAddress(
GetModuleHandle(NULL), "wdCommandDispatch"
);
return ((*pfn_wdCommandDispatch)(
CommandID, DlgOptions, cArgs, lpwdoprArgs, lpwdoprReturn)
);
}
- In the wdcapi.h, change the following lines:
typedef struct
{
short cArrayDimensions;
short ArrayDimensions[];
} ARRAY_DEF;
to the following:
typedef struct
{
short cArrayDimensions;
short *ArrayDimensions;
} ARRAY_DEF;
- Add the following lines after #include "ANewWLL.h" in ANewWll.cpp:
#include "capilib.h"
#include "wdcmds.h"
#include "wdfid.h"
- Add the following code to the end of ANewWll.cpp:
// DocId of WLL session...
short g_docId;
// General-purpose variables...
static char buf[8192];
int err;
// Routine to report errors encountered...
void ReportError(char *msg) {
static char errBuf[1024];
sprintf(errBuf, "%s, Error = %d", msg, err);
::MessageBox(NULL, errBuf, "WLL Error", MB_SETFOREGROUND);
}
// Table of functions that we will register...
struct {
char *name; // Function name...
char *desc; // Function description...
} g_funcTbl[] =
{
{"MyMotd", "Message of the day"},
{"InsertTime", "Insert Time"},
{0, 0} // List is null-terminated
};
// Menu name
UCHAR *g_menuName = (UCHAR *)"&Custom Menu";
// wdAutoOpen() - entry point for WLLs...
short __stdcall wdAutoOpen(short DocID) {
// Some diagnostic output, remove from your final code ...
::MessageBox(NULL, "In wdAutoOpen()!", "Msg", MB_SETFOREGROUND);
// Store the docId for later use...
g_docId = DocID;
// Register our functions...
int i;
for(i=0; g_funcTbl[i].name; i++) {
err = CAPIRegister(
DocID, (UCHAR *)g_funcTbl[i].name,
(UCHAR*)g_funcTbl[i].desc
);
if(err) {
sprintf(buf, "CAPIRegister(%s, %s)",
g_funcTbl[i].name, g_funcTbl[i].desc);
ReportError(buf);
}
}
// Add our menu...
err = CAPIAddMenu(DocID, g_menuName, 1, 0);
if(err) ReportError("CAPIAddMenu()");
// Add our menu items...
for(i=0; g_funcTbl[i].name; i++) {
err = CAPIAddMenuItem(
DocID, g_menuName, (UCHAR *)g_funcTbl[i].name,
(UCHAR *)g_funcTbl[i].desc, -2, 0
);
if(err) {
sprintf(buf, "CAPIAddMenuItem() for %s",
g_funcTbl[i].name);
ReportError(buf);
}
}
// Initialize crt pseudo-random number generator...
srand(time(0));
return TRUE;
}
// Displays a message of the day (MOTD)...
short __stdcall MyMotd(void) {
char *name[] = {
"Rebekah",
"Brent",
"Michael",
"Joseph",
"Bob",
0
};
char *quote[] = {
"An apple a day, keeps the doctor away!",
"Carpe Diem: Seize the Day!",
"What you dare to dream, dare to do!",
"I think, therefore I am.",
"A place for everything, and everything in its place.",
"Home is where the heart is.",
0
};
int nNames, nQuotes;
for(nNames=0; name[nNames]; nNames++);
for(nQuotes=0; quote[nQuotes]; nQuotes++);
sprintf(buf, "%s says '%s'",
name[rand()%nNames], quote[rand()%nQuotes]
);
::MessageBox(NULL, buf, "XLL MOTD", MB_SETFOREGROUND );
return 0;
}
// Inserts time at current document location...
void __stdcall InsertTime(void) {
WCB wcb;
InitWCB(&wcb, TypeShort, NULL, 0);
_strtime(buf);
AddStringParam(&wcb, (UCHAR *)buf);
err = wdCommandDispatch(
wdInsert, CommandAction, wcb.cArgs, wcb.wdoprArgs, lpwdoprNil
);
if(err) {
ReportError("wdInsert");
}
}
- You will see a ANewWLL.DEF file in your project. Open that and add the names of the functions your .wll will export, so that the file looks like the following:
; ANewWLL.def : Declares the module parameters for the DLL.
LIBRARY "ANewWLL"
DESCRIPTION "ANewWLL Windows Dynamic Link Library
EXPORTS
; Explicit exports can go here
wdAutoOpen
MyMotd
InsertTime
- Compile and rename your ANewWLL.dll to ANewWLL.wll.
Use the Add-in with Microsoft Word 97
- Start Microsoft Word 97.
- On the Tools menu, click Templates and Add-ins. Add ANewWLL.wll and click OK. Notice that when you click OK, the wdAutoOpen() function runs, and your new menu is created.
- On the Custom Menu, click Message of the day. When your menu item is clicked, the MyMotd() function runs and displays a MessageBox with a quote such as "Rebekah says 'An Apple a day, keeps the doctor away!'."
- On the Custom Menu, click Insert Time. When you select this menu item, the InsertTime() function runs and inserts the current time into your document.
REFERENCES
Microsoft Word Developer's Kit (ISBN: 1-55615-880-7)
© Microsoft Corporation 1999, All Rights Reserved. Contributions by Joe Crump, Microsoft Corporation
Additional query words:
wll vc wdcommanddispatch capilib wdopr capi wcb
Keywords : kbVC500 kbSDKWord kbWord kbGrpDSO kbOffice2000
Version : :; WINDOWS:97; winnt:5.0
Platform : WINDOWS winnt
Issue type : kbhowto
|