Word Add-in 函数调用顺序

本文介绍了一个Word插件的实现过程,包括DLL导出函数的实现、注册和注销服务器的处理,以及通过COM接口与Word应用交互的具体代码。特别关注了插件如何在Word中创建自定义工具栏按钮,并处理按钮点击事件。

这个图表明的函数的调用顺序,主要代码如下:

  1 // MyAddin.cpp : Implementation of DLL Exports.
  2 
  3 
  4 // Note: Proxy/Stub Information
  5 //      To merge the proxy/stub code into the object DLL, add the file 
  6 //      dlldatax.c to the project.  Make sure precompiled headers 
  7 //      are turned off for this file, and add _MERGE_PROXYSTUB to the 
  8 //      defines for the project.  
  9 //
 10 //      If you are not running WinNT4.0 or Win95 with DCOM, then you
 11 //      need to remove the following define from dlldatax.c
 12 //      #define _WIN32_WINNT 0x0400
 13 //
 14 //      Further, if you are running MIDL without /Oicf switch, you also 
 15 //      need to remove the following define from dlldatax.c.
 16 //      #define USE_STUBLESS_PROXY
 17 //
 18 //      Modify the custom build rule for MyAddin.idl by adding the following 
 19 //      files to the Outputs.
 20 //          MyAddin_p.c
 21 //          dlldata.c
 22 //      To build a separate proxy/stub DLL, 
 23 //      run nmake -f MyAddinps.mk in the project directory.
 24 
 25 #include "stdafx.h"
 26 #include "resource.h"
 27 #include <initguid.h>
 28 #include "MyAddin.h"
 29 #include "dlldatax.h"
 30 
 31 #include "MyAddin_i.c"
 32 #include "WordAddin.h"
 33 
 34 #ifdef _MERGE_PROXYSTUB
 35 extern "C" HINSTANCE hProxyDll;
 36 #endif
 37 
 38 CComModule _Module;
 39 
 40 BEGIN_OBJECT_MAP(ObjectMap)
 41 OBJECT_ENTRY(CLSID_WordAddin, CWordAddin)
 42 END_OBJECT_MAP()
 43 
 44 /////////////////////////////////////////////////////////////////////////////
 45 // DLL Entry Point
 46 
 47 extern "C"
 48 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
 49 {
 50         MessageBox(NULL,"DllMain",NULL,MB_OK);
 51     lpReserved;
 52 #ifdef _MERGE_PROXYSTUB
 53     if (!PrxDllMain(hInstance, dwReason, lpReserved))
 54         return FALSE;
 55 #endif
 56     if (dwReason == DLL_PROCESS_ATTACH)
 57     {
 58         _Module.Init(ObjectMap, hInstance, &LIBID_MYADDINLib);
 59         DisableThreadLibraryCalls(hInstance);
 60     }
 61     else if (dwReason == DLL_PROCESS_DETACH)
 62         _Module.Term();
 63     return TRUE;    // ok
 64 }
 65 
 66 /////////////////////////////////////////////////////////////////////////////
 67 // Used to determine whether the DLL can be unloaded by OLE
 68 
 69 STDAPI DllCanUnloadNow(void)
 70 {
 71     MessageBox(NULL,"DllCanUnloadNow",NULL,MB_OK);
 72 #ifdef _MERGE_PROXYSTUB
 73     if (PrxDllCanUnloadNow() != S_OK)
 74         return S_FALSE;
 75 #endif
 76     return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;
 77 }
 78 
 79 /////////////////////////////////////////////////////////////////////////////
 80 // Returns a class factory to create an object of the requested type
 81 
 82 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
 83 {
 84         MessageBox(NULL,"DllGetClassObject",NULL,MB_OK);
 85 #ifdef _MERGE_PROXYSTUB
 86     if (PrxDllGetClassObject(rclsid, riid, ppv) == S_OK)
 87         return S_OK;
 88 #endif
 89 
 90     return _Module.GetClassObject(rclsid, riid, ppv);
 91 }
 92 
 93 /////////////////////////////////////////////////////////////////////////////
 94 // DllRegisterServer - Adds entries to the system registry
 95 
 96 STDAPI DllRegisterServer(void)
 97 {
 98     MessageBox(NULL,"DllRegisterServer",NULL,MB_OK);
 99 #ifdef _MERGE_PROXYSTUB
100     HRESULT hRes = PrxDllRegisterServer();
101     if (FAILED(hRes))
102         return hRes;
103 #endif
104     // registers object, typelib and all interfaces in typelib
105     
106     return _Module.RegisterServer(TRUE);
107 }
108 
109 /////////////////////////////////////////////////////////////////////////////
110 // DllUnregisterServer - Removes entries from the system registry
111 
112 STDAPI DllUnregisterServer(void)
113 {
114     MessageBox(NULL,"DllUnregisterServer",NULL,MB_OK);
115 #ifdef _MERGE_PROXYSTUB
116     PrxDllUnregisterServer();
117 #endif
118 
119     return _Module.UnregisterServer(TRUE);
120 }

还有一份代码如下:

  1 // WordAddin.h : Declaration of the CWordAddin
  2 
  3 #ifndef __WORDADDIN_H_
  4 #define __WORDADDIN_H_
  5 
  6 #include "resource.h"       // main symbols
  7 #include "stdafx.h"
  8 #include "StdAfx.h"
  9 #import "C:\Program Files\Common Files\designer\MSADDNDR.dll" raw_interfaces_only, raw_native_types, no_namespace, named_guids 
 10 
 11 extern _ATL_FUNC_INFO OnClickButtonInfo;
 12 
 13 /////////////////////////////////////////////////////////////////////////////
 14 // CWordAddin
 15 class ATL_NO_VTABLE CWordAddin : 
 16     public CComObjectRootEx<CComSingleThreadModel>,
 17     public CComCoClass<CWordAddin, &CLSID_WordAddin>,
 18     public IDispatchImpl<IWordAddin, &IID_IWordAddin, &LIBID_MYADDINLib>,
 19     public IDispatchImpl<_IDTExtensibility2, &IID__IDTExtensibility2, &LIBID_AddInDesignerObjects>,
 20     public IDispEventSimpleImpl<1,CWordAddin,&__uuidof(Office::_CommandBarButtonEvents)>,
 21     public IDispatchImpl<IRibbonExtensibility, &IID_IRibbonExtensibility, &LIBID_Office>
 22 {
 23 public:
 24     CWordAddin()
 25     {
 26         int i = 0;
 27     }
 28 
 29 DECLARE_REGISTRY_RESOURCEID(IDR_WORDADDIN)
 30 
 31 DECLARE_PROTECT_FINAL_CONSTRUCT()
 32 
 33 BEGIN_COM_MAP(CWordAddin)
 34     COM_INTERFACE_ENTRY(IWordAddin)
 35 //DEL     COM_INTERFACE_ENTRY(IDispatch)
 36     COM_INTERFACE_ENTRY2(IDispatch, IWordAddin)
 37     COM_INTERFACE_ENTRY(_IDTExtensibility2)
 38     COM_INTERFACE_ENTRY(IRibbonExtensibility)
 39 END_COM_MAP()
 40 
 41 BEGIN_SINK_MAP(CWordAddin)
 42 SINK_ENTRY_INFO(1, __uuidof(Office::_CommandBarButtonEvents),/*dispid*/ 0x01, OnClickButton1, &OnClickButtonInfo)
 43 END_SINK_MAP()
 44 
 45 // IWordAddin
 46 public:
 47     STDMETHOD(OnMyButton)(/*[in]*/IDispatch* pIDispControl);
 48     CComQIPtr <Word::_Application> m_spApp;
 49     CComPtr < Office::_CommandBarButton> m_spCmdButton;
 50     typedef IDispEventSimpleImpl</*nID =*/ 1,CWordAddin, &__uuidof(Office::_CommandBarButtonEvents)> CommandButton1Events;
 51 // _IDTExtensibility2
 52     STDMETHOD(OnConnection)(IDispatch * Application, ext_ConnectMode ConnectMode, IDispatch * AddInInst, SAFEARRAY * * custom)
 53     {
 54         ::MessageBox(NULL,"OnConnection","",MB_OK);
 55         OutputDebugString("OnConnection");
 56         //Delete it for the Office 2007
 57         
 58         CComPtr < Office::_CommandBars> spCmdBars; 
 59         CComQIPtr <Word::_Application> spApp(Application);     
 60         m_spApp = spApp;
 61         ATLASSERT(spApp);
 62 
 63         HRESULT hr = spApp->get_CommandBars(&spCmdBars);
 64         if(FAILED(hr))
 65             return hr;
 66             
 67         ATLASSERT(spCmdBars);
 68         
 69     
 70         CComVariant vName("MyAddin");
 71         CComPtr <Office::CommandBar> spNewCmdBar;
 72         CComVariant vPos(1); 
 73         CComVariant vTemp(VARIANT_TRUE);    
 74         CComVariant vEmpty(DISP_E_PARAMNOTFOUND, VT_ERROR);            
 75         spNewCmdBar = spCmdBars->Add(vName, vPos, vEmpty, vTemp);
 76         
 77         
 78         CComPtr < Office::CommandBarControls> spBarControls;
 79         spBarControls = spNewCmdBar->GetControls();
 80         ATLASSERT(spBarControls);
 81         
 82         
 83         CComVariant vToolBarType(1);
 84         CComVariant vShow(VARIANT_TRUE);
 85         CComPtr < Office::CommandBarControl> spNewBar; 
 86         spNewBar = spBarControls->Add(vToolBarType, vEmpty, vEmpty, vEmpty, vShow); 
 87         ATLASSERT(spNewBar);
 88         
 89             
 90         
 91         CComQIPtr < Office::_CommandBarButton> spCmdButton(spNewBar);
 92         ATLASSERT(spCmdButton);
 93         
 94         HBITMAP hBmp =(HBITMAP)::LoadImage(_Module.GetResourceInstance(),
 95             MAKEINTRESOURCE(IDB_BITMAP),IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS);
 96         
 97         ::OpenClipboard(NULL);
 98         ::EmptyClipboard();
 99         ::SetClipboardData(CF_BITMAP, (HANDLE)hBmp);
100         ::CloseClipboard();
101         ::DeleteObject(hBmp);        
102         
103         
104         spCmdButton->PutStyle(Office::msoButtonIconAndCaption);
105         hr = spCmdButton->PasteFace();
106         if (FAILED(hr))
107             return hr;
108         
109         spCmdButton->PutVisible(VARIANT_TRUE); 
110         spCmdButton->PutCaption(OLESTR("myAddin")); 
111         spCmdButton->PutEnabled(VARIANT_TRUE);
112         spCmdButton->PutTooltipText(OLESTR("test1")); 
113         spCmdButton->PutTag(OLESTR("test1")); 
114         
115         spNewCmdBar->PutVisible(VARIANT_TRUE); 
116         
117         m_spCmdButton = spCmdButton;
118 
119         CommandButton1Events::DispEventAdvise((IDispatch*)m_spCmdButton);
120         return S_OK;
121     }
122     STDMETHOD(OnDisconnection)(ext_DisconnectMode RemoveMode, SAFEARRAY * * custom)
123     {
124         MessageBox(NULL,"OnDisconnection",NULL,MB_OK);
125         if(m_spCmdButton != NULL)
126             CommandButton1Events::DispEventUnadvise((IDispatch*)m_spCmdButton);
127         return S_OK;
128     }
129     STDMETHOD(OnAddInsUpdate)(SAFEARRAY * * custom)
130     {
131         MessageBox(NULL,"OnAddInsUpdate",NULL,MB_OK);
132         return S_OK;
133     }
134     STDMETHOD(OnStartupComplete)(SAFEARRAY * * custom)
135     {
136         MessageBox(NULL,"OnStartupComplete",NULL,MB_OK);
137         return S_OK;
138     }
139     STDMETHOD(OnBeginShutdown)(SAFEARRAY * * custom)
140     {
141         MessageBox(NULL,"OnBeginShutdown",NULL,MB_OK);
142         return S_OK;
143     }
144 
145     void __stdcall OnClickButton1(IDispatch * /*Office::_CommandBarButton**/ Ctrl,VARIANT_BOOL * CancelDefault);
146 
147     // IRibbonExtensibility
148     STDMETHOD(raw_GetCustomUI)(BSTR RibbonID, BSTR * RibbonXml)
149     {
150         MessageBox(NULL,"raw_GetCustomUI",NULL,MB_OK);
151         OutputDebugString("raw_GetCustomUI");
152         char szRibbon[MAX_PATH*10] = {0x00};
153         LoadString(_Module.GetModuleInstance(),IDS_RIBBON_XML, \
154             szRibbon, MAX_PATH*10);
155         if (RibbonXml == NULL)
156             return E_POINTER;
157 
158         OutputDebugString(szRibbon);
159         
160         CComBSTR bstr(szRibbon);
161         bstr.CopyTo(RibbonXml);//use this to avoid heap destroy
162         bstr.Empty();
163         return S_OK;
164     }
165 };
166 
167 #endif //__WORDADDIN_H_

这是两个主要的文件。

注意两个问题:

160         CComBSTR bstr(szRibbon);
161         bstr.CopyTo(RibbonXml);//use this to avoid heap destroy
162         bstr.Empty();
这三行代码是为了防止程序退出时,插件对word的内存进行修改,导致堆错误,Word会Crash。函数的含义请参考MSDN。

转载于:https://www.cnblogs.com/Dennis-mi/p/3461883.html

<think>好的,我现在需要解决用户遇到的CAPL调用DLL时出现的'Invalid type in DLL'错误的问题。首先,我应该回忆一下CAPL调用DLL的相关知识,尤其是数据类型匹配的部分。根据用户提供的引用内容,CAPL中数据类型在DLL调用时是通过首字母大写来表示的,比如V代表Void,B代表byte,W代表word等等。如果参数类型或返回值类型不一致,就会导致生成的DLL无法使用,出现类型错误。 首先,我应该检查用户是否在声明DLL函数时正确指定了返回类型和参数类型。比如,如果DLL中的函数返回一个int,但在CAPL中声明为L(long),这就会导致类型不匹配的错误。需要确认每个参数的数据类型是否与CAPL中的定义一致。 其次,用户提到使用DiagGetComplexParameter和DiagGetComplexParameterRaw函数时需要注意数据类型的大小。如果参数类型超过4字节,可能需要使用后者。但这个问题更多是关于诊断功能的,不过数据类型大小的匹配可能也是DLL调用错误的一个因素,比如传递了过大的数据导致类型不兼容。 接下来,我应该考虑参数传递方式是否正确。CAPL调用DLL时,参数的传递顺序和调用约定(如stdcall或cdecl)是否正确?如果DLL使用的是不同的调用约定,可能会导致栈不平衡,进而引发错误,但具体到错误信息是类型错误,可能主要还是类型符号的问题。 另外,用户可能没有正确地将参数类型映射到CAPL的符号。例如,如果DLL中的参数是unsigned short,对应CAPL中的W(word),而错误地声明为I(int)就会导致类型不匹配。需要逐个检查参数和返回值的类型符号是否正确。 还需要确认DLL本身的导出函数是否与CAPL声明一致。比如,使用工具如Dependency Walker查看导出的函数名是否被正确修饰,是否存在名称改编(name mangling)的问题,尤其是C++编写的DLL可能需要extern "C"来避免名称改编,否则CAPL可能找不到正确的函数。 另外,检查DLL的位数是否与CAPL环境匹配,比如32位或64位的不兼容也可能导致加载问题,但错误类型是类型错误,可能更直接的原因还是类型符号不正确。 总结可能的解决步骤应该是:1. 检查返回类型和参数类型的符号是否正确;2. 确保参数数量一致;3. 检查调用约定是否匹配;4. 验证DLL导出函数是否正确;5. 测试简单案例排查问题。 用户提供的引用[1]明确指出数据类型必须一致,所以这应该是问题的主要原因。因此,解决方案应重点放在数据类型匹配上,同时考虑其他可能因素如调用约定和DLL导出。</think>### CAPL调用DLL出现'Invalid type in DLL'错误解决方案 #### 1. **检查数据类型映射一致性** - **问题核心**:CAPL通过首字母大写符号标识数据类型(如`B`表示`byte`,`W`表示`word`)。若DLL函数定义中的返回值或参数类型与CAPL声明不匹配,会直接导致该错误[^1]。 - **解决步骤**: 1. **核对返回值类型**:确认DLL函数返回值类型在CAPL中是否用正确符号表示。例如: - DLL返回`int` → CAPL声明`resultType="I"` - DLL返回`float` → CAPL声明`resultType="F"` 2. **逐参数比对**:检查每个参数类型是否与DLL定义严格匹配。例如: - DLL参数为`unsigned short` → CAPL参数类型`parTypes="W"` - DLL参数为`char*` → CAPL参数类型`parTypes="C"`(需注意指针需额外处理) #### 2. **验证参数数量与调用约定** - **常见陷阱**: - 参数数量多于/少于DLL函数定义。 - 调用约定(如`__stdcall`或`__cdecl`)未在CAPL中正确声明。 - **示例**: ```c // DLL函数原型:int __stdcall add(int a, float b); CAPL声明:dllImport("mydll.dll", "stdcall") int add(int a, float b); ``` 需确保CAPL代码中`dllImport`的调用约定与DLL一致。 #### 3. **检查DLL导出函数名称** - **关键点**:C++编译的DLL可能存在名称改编(Name Mangling),需使用`extern "C"`强制使用C风格导出[^1]。 - **验证方法**: 1. 使用工具(如Dependency Walker)查看导出函数名。 2. 若名称包含乱码(如`?add@@YGHHM@Z`),需在DLL源码中添加: ```cpp extern "C" __declspec(dllexport) int add(int a, float b); ``` #### 4. **数据类型边界与特殊处理** - **浮点数处理**:CAPL的`F`对应8字节浮点(`double`),若DLL使用4字节`float`需强制转换。 - **字符串传递**:若参数为字符串,需注意字符编码和指针类型: ```c // DLL函数:void log(char* msg); CAPL声明:dllImport("mydll.dll") void log(byte msg[]); // 使用byte数组传递字符串 ``` #### 5. **测试验证流程** **步骤1:最小化测试函数** ```c // DLL源码(C语言) extern "C" __declspec(dllexport) int add(int a, int b) { return a + b; } ``` **CAPL调用声明**: ```c dllImport("test.dll", "cdecl") int add(int a, int b); ``` **步骤2:执行调用** ```c on key 'a' { int result = add(3, 5); write("Result: %d", result); // 预期输出8 } ``` #### 6. **进阶调试方法** - **日志追踪**:在DLL中添加日志输出,确认函数是否被调用及参数值。 - **内存分析**:使用CAPL的`memcpy`或`getValue`函数检查二进制数据是否符合预期格式[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值