Microsoft KB Archive/183758

= How To Build a Microsoft Word Add-in (WLL) Using Visual C++ =

Article ID: 183758

Article Last Modified on 2/12/2007

-

APPLIES TO


 * Microsoft Office XP Developer Edition
 * Microsoft Office 2000 Developer Edition
 * Microsoft Visual C++ 5.0 Enterprise Edition
 * Microsoft Visual C++ 6.0 Enterprise Edition
 * Microsoft Visual C++ 5.0 Professional Edition
 * Microsoft Visual C++ 6.0 Professional Edition
 * Microsoft Visual C++ 6.0 Standard Edition
 * Microsoft Word 97 Standard Edition

-



This article was previously published under Q183758



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++. 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/



Create 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:   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));
 * 1) include "stdafx.h"

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)  ); }                   </li>  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; </li>  Add the following lines after #include "ANewWLL.h" in ANewWll.cpp: </li>  Add the following code to the end of ANewWll.cpp: // DocId of WLL session... short g_docId;
 * 1) include "capilib.h"
 * 2) include "wdcmds.h"
 * 3) include "wdfid.h"

// 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"); }

}                   </li>  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 </li> Compile and rename your ANewWLL.dll to ANewWLL.wll.</li></ol>

Use the Add-in with Microsoft Word 97

 * 1) Start Microsoft Word 97.
 * 2) 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.
 * 3) 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!'."
 * 4) 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.

<div class="references_section">