要在 Excel 工作表上直接使用 ActiveX 控件,有哪些必要和充分的要求?

What requirements are necessary and sufficient for an ActiveX control to be used directly on an Excel worksheet?

Microsoft Office 支持文章“Add or register an ActiveX control”说:

IMPORTANT: Not all ActiveX controls can be used directly on worksheets; some can be used only on Microsoft Visual Basic for Applications (VBA) UserForms. When you work with these controls, Excel displays the message Cannot insert object if you try to add them to a worksheet.

但是,我无法在任何地方找到关于直接在工作表上使用控件的必要足够要求的记录。

我创建了一个新的 C++/ATL 项目,并向其中添加了一个 ATL 控件,并始终接受默认设置。编译、构建和注册控件后,它出现在 Excel 的 "More Controls" 列表中(在开发人员 > 插入 > ActiveX 控件 > 更多控件...下访问)但在尝试插入工作表时有人看到这个 "Cannot insert object" 错误。

我必须进行哪些更改才能解决此问题?

Excel 对 ActiveX 控件的要求记录在哪里?


无论其价值如何,我已经验证向导生成的控件在其他方面工作正常(使用 ActiveX Control Test Container, which I built from the Visual C++ 2008 samples pack 测试)。

此外,我知道 documentation for the ATL Control wizard's "Appearance" tab 对 "Insertable" 复选框的描述如下:

Select this option to have your control appear in the Insert Object dialog box of applications such as Word and Excel. Your control can then be inserted by any application that supports embedded objects through this dialog box.

但是,这个复选框(它只是将 "Insertable" 子项添加到注册表)只会导致控件出现在“插入”>“文本”>“对象”对话框中——为避免疑义,我都试过了选中和不选中这两种方式都会产生相同的错误。

我目前正在比较 Excel 尝试插入我的控件时的执行路径与尝试插入工作 (Forms 2.0) 控件时的执行路径。关键区别似乎在于 VBE7.dll 在加载类型库时(OLE/COM Object Viewer 能够从我的 DLL 中正确加载——但在 Excel 执行了所有相同的读取之后,它在写出 EXD 之前中止)...我现在正在挖掘一些程序集,徒劳地希望我能弄清楚 - 但肯定 某人 已经建立了一个工作控制对于 Excel 并且知道我错过了什么可以免除我的痛苦?!


微软 Windows 10 Pro v1511 (10.0.10586.164) 64 位
微软 Excel 2016 MSO (16.0.4312.1000) 64 位
Microsoft Visual Studio 社区 2015(14.0.24720.00 更新 1)

我对 ActiveX 和 COM 技术有一些经验,但还没有深入研究 Excel 的世界。据我所知,除非您确切地知道自己在做什么,否则所有 COM 组件总是散发出过于复杂的味道,但并非总能找到需要做的事情。

无论如何 - 我已经快速扫描/googled - 这些是我能够找到的链接:

从这里开始:http://itdocument.com/6551512544/

Excel 97 & 2000 Issues Excel 97 & 2000 Issues Q171280 Q171280, , Error Message "Cannot insert object" in Excel97.

ActiveX controls must support aggregation to be inserted ActiveX controls must support aggregation to be inserted into a spreadsheet. If they do not support being into a spreadsheet. If they do not support being aggregated, Excel will not allow them to be inserted. aggregated, Excel will not allow them to be inserted. More information on this is provided in More information on this is provided in Q143432 Q143432 at the at the bottom of the article. bottom of the article.

任何尝试查找文章 Q143432 的人通常都以不存在的页面结束 - 但能够找到这篇文章:

https://support.microsoft.com/en-us/kb/143432

这里报告了一些与其使用相关的问题:

http://www.verycomputer.com/418_e81ed24b6ac0cb79_1.htm

然而,我的建议是尽可能避免使用 ActiveX 技术,如果不可能 - 尝试上面的链接 - 或者可能会找到一些类似的开源代码示例。

以下是我设法找到的一些示例:

这是俄语: https://habrahabr.ru/post/149277/

这显然是同一页面的 google 翻译版本: http://developers-club.com/posts/149277/

它是源代码 - 我认为: https://github.com/Lovesan/MyActiveX

我希望这会对你有所帮助,但是 - 不确定 - 我自己还没有尝试过。

要实现可插入 MS Excel Sheet 的 ATL ActiveX 控件,请执行以下步骤:

  1. 确保您没有在 C:\Users\$(UserName)\AppData\Local\Temp\Excel8.0 中缓存 ActiveX 控件信息 *.exd 文件,这可能是一个不明显的障碍方式

  2. 使用所有默认值创建一个 ATL DLL 项目

2.1。添加 x64 配置作为现有 Win32 的副本 - 对于 64 位 Excel 您将需要 64 位 ActiveX 控件

  1. 使用向导添加 ATL 控件 class

3.1。确保填写 ProgID 字段

3.2。在接口页面上添加 IPersistStreamInit

  1. 构建 DLL 并注册 (regsvr32)

  2. 在 Excel 中,新控件在菜单开发人员中可见,...,更多控件

  1. 插入它并从那里玩得开心

源代码:Subversion/Trac

更新:来自以下评论的问题:

...whether Excel supports windowless activation?

要查看实际的控制操作,让我们添加一些代码 around there:

CSample()
{
    CTrace::SetLevel(4);

HRESULT OnDraw(ATL_DRAWINFO& di)
{
    const CComQIPtr<IOleInPlaceSiteWindowless> pOleInPlaceSiteWindowless = m_spClientSite;
    ATLTRACE(_T("m_spClientSite 0x%p, pOleInPlaceSiteWindowless 0x%p, m_hWnd 0x%08X\n"), m_spClientSite, pOleInPlaceSiteWindowless, m_hWnd);

这将打印出有助于识别windowed/windowless模式的控件成员。输出是(最终在激活对象之后或从一开始就正确):

...
Sample.h(118) : atlTraceGeneral - m_spClientSite 0x0000027A9CA7B460, pOleInPlaceSiteWindowless 0x0000000000000000, m_hWnd 0x0105069C
...
Sample.h(118) : atlTraceGeneral - m_spClientSite 0x0000027A9CA7B460, pOleInPlaceSiteWindowless 0x0000000000000000, m_hWnd 0x0105069C

该控件可以同时激活有窗口和无窗口(除非 m_bWindowOnly 设置为 true,在这种情况下强制窗口模式)。跟踪显示控件处于窗口模式,并且该容器没有 IOleInPlaceSiteWindowless,这对于无窗口是强制性的。