Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

The Microsoft Office support article "Add or register an ActiveX control" says:

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.

However, I cannot find documented anywhere the requirements that are necessary and sufficient for a control to be used directly on a worksheet.

I have created a new C++/ATL Project, to which I have added an ATL Control, accepting the defaults throughout. After compiling, building and registering the control, it appears in Excel's list of "More Controls" (accessed under Developer > Insert > ActiveX Controls > More Controls...) but upon attempting to insert into the worksheet one sees this "Cannot insert object" error.

What changes must I make to fix this?

OR

Where are Excel's requirements of ActiveX controls documented?


For what it's worth, I've verified that the control generated by the wizard does otherwise work fine (tested with ActiveX Control Test Container, which I built from the Visual C++ 2008 samples pack).

Furthermore, I'm aware that the documentation for the ATL Control wizard's "Appearance" tab describes the "Insertable" checkbox as follows:

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.

However, this checkbox (which simply adds the "Insertable" subkey to the registry), only causes the control to appear in the Insert > Text > Object dialog—for the avoidance of doubt, I have tried both with and without this checked and the same error is produced either way.

I'm currently comparing traces of Excel's execution paths when attempting to insert my control against that when attempting to insert a working (Forms 2.0) control. The key difference appears to lie in VBE7.dll whilst loading the type library (which the OLE/COM Object Viewer is able to load correctly from my DLL—yet after Excel has performed all the same reads therefrom, it aborts before writing out an EXD)... I'm digging through some assembly right now in the vain hope that I'll figure it out—but surely someone who has built a working control for Excel and knows what I'm missing can spare me this pain?!


Microsoft Windows 10 Pro v1511 (10.0.10586.164) 64-bit
Microsoft Excel 2016 MSO (16.0.4312.1000) 64-bit
Microsoft Visual Studio Community 2015 (14.0.24720.00 Update 1)

like image 800
eggyal Avatar asked Mar 23 '16 14:03

eggyal


People also ask

How do you use ActiveX control in Excel?

On the Developer tab, in the Controls group, click Insert, and then under ActiveX Controls, select a control, or click More Controls to view all the available ActiveX controls, and then select a control. Click the worksheet location where you want the ActiveX control to appear.

What is form control and ActiveX control in Excel?

As Hans Passant said, Form controls are built in to Excel whereas ActiveX controls are loaded separately. Generally you'll use Forms controls, they're simpler. ActiveX controls allow for more flexible design and should be used when the job just can't be done with a basic Forms control.


1 Answers

To implement an ATL ActiveX Control insertable into MS Excel Sheet, follow these steps:

  1. Make sure you don't have cached ActiveX control information *.exd files in C:\Users\$(UserName)\AppData\Local\Temp\Excel8.0 which might be an unobvious obstacle on the way

  2. Create an ATL DLL project with all defaults

2.1. Add x64 configuration as a copy of already existing Win32 - for 64-bit Excel you will need 64-bit ActiveX control

  1. Add ATL Control class using wizard

enter image description here

3.1. Make sure to fill ProgID field

enter image description here

3.2. Add IPersistStreamInit on the Interfaces page

enter image description here

  1. Build the DLL and have it registered (regsvr32)

  2. In Excel the new control is visible in menu Developer, ..., More Controls

enter image description here

enter image description here

  1. Insert it and have fun from there

enter image description here

Source Code: Subversion/Trac

UPDATE: A question from comments below:

...whether Excel supports windowless activation?

To see control operation in action let's add some code around there:

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

and

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);

This going to print out the members of the control that help identification of windowed/windowless mode. The output is (eventually after activating the object or right from the start):

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

The control can activate both windowed and windowless (unless m_bWindowOnly is set to true in which case windowed mode is forced). The trace shows that control is however in windowed mode, and that container does not have IOleInPlaceSiteWindowless, which is mandatory for windowless.

like image 69
Roman R. Avatar answered Sep 26 '22 16:09

Roman R.