views:

269

answers:

2

I would like to develop an ActiveX control and as I don't own visual studio I'm wondering whether I can use VisualC++ express edition on it's own, or do I also need the Windows Platform SDK?

A: 

This Microsoft Support post from 2006 would indicates that you can use the VC++ Express edition for developing ActiveX controls:

APPLIES TO

Microsoft ActiveX Template Library 3.0, when used with:
Microsoft Visual C++ 6.0 Enterprise Edition
Microsoft Visual C++ 6.0 Professional Edition
Microsoft Visual C++, 32-bit Learning Edition 6.0
Microsoft Visual C++ 2005 Express Edition
Microsoft Visual C++ .NET 2003 Standard Edition
Microsoft Visual C++ .NET 2002 Standard Edition

It's been a while since I developed using ActiveX, but I don't remember having to have the Windows Platform SDK installed.

ChrisF
I don't think the page is correct. The page indicates that the sample uses the ATL and this is one of the things missing from Visual C++ Express edition.
Matt H
+3  A: 

You don't need Visual Studio to write an Active X control. An Active X control is simply a COM object that is registered in a specific way that implements IUnknown and IObjectSafety.

You don't need to create a Visual Studio Active X project. You can just create a normal DLL, add the proper manifest and cab it using the CAB SDK tools.

You don't have to use ATL to write an Active X control. In fact, you're probably better off not using it until you understand how the OLE interfaces work in the IE extensibility model.

So yes, you'll be just fine with Visual Studio Express.

EDIT:

Here is a sample manifest, called YOURCONTROL.inf. Obviously replace YOURCONTROL with whatever you call your guy, and generate your own GUID and version numbers. This is the minimum manifest you'll need.

[version]
signature="$CHICAGO$"
AdvancedINF=2.0

[Add.Code]
YOURCONTROL.dll=YOURCONTROL.dll

[YOURCONTROL.dll]
file-win32-x86=thiscab
clsid={11111111-2222-3333-4444-555555555555}
FileVersion=1,2,3,4567
RegisterServer=yes

You'll need a standard .DEF file in your project that lists the required exported functions for COM and self-registration. DllGetClassObject is where COM will call you to get the class factory for your COM object. RegisterServer and UnregisterServer is where you should write your initial state to the registry (e.g. your COM object registration, etc).

EXPORTS
    DllCanUnloadNow             PRIVATE
    DllGetClassObject   PRIVATE
    DllRegisterServer   PRIVATE
    DllUnregisterServer PRIVATE

You'll need an IDL file too, so you can define your COM object's dispinterface so it can be called from script, and so it can fire events to Javascript. Something like this:

import "oaidl.idl";
import "ocidl.idl";

#include "dispids.h"  // <-- define your DISPIDs here

[
        uuid(<<generate your own guid here>>),
        version(1.0),
]
library YOURCONTROLLIBRARY
{
    [
        uuid(<<generate your own guid here>>),
        hidden
    ]
    dispinterface DYOURCONTROLEvents
    {
        properties:
        methods:
        // Add outgoing events here.
        [id(DISPID_SOME_EVENT)]  void SomeEvent();
    }

    [
        dual,
        uuid(<<generate your own guid here>>)
    ]
    interface IYOURCONTROL : IDispatch
    {
        // Add methods and properties here.
        [id(DISPID_SOMEMETHOD)] HRESULT SomeMethod([in] BSTR bstrFoo);
    }

    [
        uuid(<<generate your own guid here>>)
    ]
    coclass YOURCONTROLCtl
    {
        [default] interface IYOURCONTROL;
        [source, default] dispinterface DYOURCONTROLEvents;
    }
}

And, finally, your DLL entry point should look something like this:

HINSTANCE g_hInstance;
LONG g_nDllRefs;

extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) {
    switch (dwReason) {
        case DLL_PROCESS_ATTACH:
            g_hInstance = hInstance;
            g_nDllRefs = 0;
            break;

        case DLL_PROCESS_DETACH:
            break;
    }

    return true;
}

// Call this whenever you create your object to keep your DLL loaded.
void DllAddRef() {
    InterlockedIncrement(&g_nDllRefs);
}

// Call this when your object is destroyed.
void DllRelease() {
    InterlockedDecrement(&g_nDllRefs);
}

STDAPI DllCanUnloadNow() {
    return (g_nDllRefs == 0 ? S_OK : S_FALSE);
}

// This is where you create your class factory.  See the IClassFactory documentation on msdn.
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
    HRESULT hr;
    if (rclsid == CLSID_YOUROBJECTCtl) {
        CYOUROBJECTFactory *pYOUROBJECTFactory = new CYOUROBJECTFactory;
        if (pYOUROBJECTFactory == NULL) {
            hr = E_OUTOFMEMORY;
        } else {
            hr = pYOUROBJECTFactory ->QueryInterface(riid, ppv);
        }
    } else {
        hr = CLASS_E_CLASSNOTAVAILABLE;
    }
    return hr;
}

STDAPI DllRegisterServer() {
    // Write your registry keys for registering your ActiveX COM Object here.
    return S_OK;
}

STDAPI DllUnregisterServer() {
    // Delete your registry keys here.
    return S_OK;
}
jeffamaphone
Thanks a lot. Can you provide me with a link that describes the process and gives simple examples?
Matt H
How's that then?
jeffamaphone
Thankyou. That's a brilliant start.
Matt H