Visual C++ COM Summary reference: Using Visual C++ 5 by Kate Gregory, published by QUE 1997
ActiveX summary:

History: Clipboard -> DDE (Dynamic Data Exchange) -> OLE(Object Linking and Embedding) -> ActiveX (or COM) The rationale is to make a file system document-centered , rather than application-centered. It allows embedding or linking of objects associated with other applications in documents Thus: Compound Documents have portions developed in multiple applications.

The ActiveX Container application handles compound documents. The ActiveX Server allows distributed handling of Compound Document objects. Objects can be portions of actual files. When MFC and AppWizards handle most of the complexity of COM, this is called ActiveX.

At the heart of COM is the ActiveX interface, which is just a collection of pure virtual functions. All ActiveX objects must have an interface called IUnknown. This is used to find other interfaces, thru its QueryInterface() function. AddRef() and Release() keep track of applications using the interface.

An ActiveX Automation server application is just a slave to other applications. It exposes functions and data (methods and properties). ActiveX Automations can only be invoked in an ActiveX Automation controller(or Container). Automation servers involve a special interface: IDispatch, which inherits from IUnknown. Added functions: GetTypeInfoCount(UINT *), GetTypeInfo(UINT, LCID, ITypeInfo **), GetIDsOfNames(REFIID, LPOLESTR **, UINT, LCID, DISPID *), and Invoke(DISPID, REFIID, LCID, WORD, DISPPARAMS *, VARIANT *, EXCEPINFO *, UINT *).

ActiveXControls are small ActiveX Automation servers that load in process. History: VBX -> OLE Custom Control (.OCX) -> ActiveX controls. These controls are event-driven.

ActiveX Container Application:

Make a new MDI application using AppWizard

Include compound document support, container, shared DLL
[docking toolbar, staus bar, printing, print preview,
context sensitive help, 3d controls, source file comments] IDR_…TYPE_CNTR_IP menu has a space between File and Window to add server menu items.
IDR_…TYPE menu has, in addition to normal Edit function:
Psste Special, Insert New Object,
Links, and a place holder for OLE verbs like edit, open,…

Class C…App has the following in InitInstance():
If(!AfxOleInit()){ AfxMessageBox(IDP_OLE_INIT_FAILED); return FALSE; }
and before AddDocTemplate (for in-place editting) call:
pDocTemplate->SetContainerInfo(IDR_…TYPE_CNTR_IP);

Class C...Doc (:COleDocument)
include "CntrItem.h" (also added to view .cpp file)
the following message map macros are added in the .cpp file:
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, COleDocument::OnUpdatePaseMenu)
ON_UPDATE_COMMAND_UI(ID_PASTE_LINK, COleDocument::OnUpdatePasteLinkMenu)
ON_UPDATE_COMMAND_UI(ID_OLE_EDIT_CONVERT, COleDocument::OnUpdateObjectVerbMenu)
ON_COMMAND(ID_OLE_EDIT_CONVERT, COleDocument::OnEditConvert)
ON_UPDATE_COMMAND_UI(ID_OLE_EDIT_LINKS, COleDocument::OnUEditLinks)
ON_UPDATE_COMMAND_UI(ID_OLE_VERB_FIRST, COleDocument::OnUpdateObjectVerbMenu)

The above are for Edit/Paste, Edit/PasteLink, Edit/Links, and OLE Verbs Also the C...Doc constuctor has: EnableCompoundFile(); Serialize passes straight thru to COleDocument::Serialize(ar)

Class C...View:

This has the new message map entries: ON_WM_SETFOCUS() ON_WM_SIZE(), ON_COMMAND(ID_OLE_INSERT_NEW, OnInsertObject) ON_COMMAND(ID_CANCEL_EDIT_CNTR, OnCancelEditCntr);

Also a new member variable: C...CntrItem *m_pSelection; which is initialized to null in the constructor OnDraw needs revising. Also following functions will need code added: OnInitialUpdate(), IsSelected(), OnInsertObject(), OnSetFocus(), OnSize(), OnCancelEditCntr().

Class C...CntrItem: (:COleClientItem)

Thisclass describes items contained in the document. It has a dozen functions that can be overridden. including GetDocument(), GetActiveView(), OnChange(), OnActivate(), OnGetItemPosition(), OnDeactivateUI(), OnChangeItemPosition(), AssertValid(), Dump(), and Serialize();The default for OnChange calls GetDocument()->UpdateAllViews(NULL) by default. OnActivate is called when a user tries to edit an object in place.....then put in the specific code...

Contained items can get a tracker rectange (a hashed line around item) can be done with the MFC class CRectTracker: Do this by adding member variable CRect m_rect; Initialize m_rect in the constructor (the only function called once in a container item class). Then replace in C...View::OnDraw(): m_pSelection->Draw(pDC, CRect(...)); with m_pSelection->Draw(pDC, m_pSelection->m_rect); Then change C...CntrItem::OnGetItemPosition() to include rPosition = m_rect; In C...CntrItem::OnChangeItemPositon() after call to COleClientItem::OnChangeItemPosition(), add:
m_rect = rectPos;
GetDocument()->SetModifiedFlag();
GetDocument()->UpdateAllViews(NULL);
Also add to C...CntrItem::Serialize(CArchive& ar):
if(ar.IsStoring()) ar<>m_rect;
Add to C...View::OnDraw(), after call to m_pSelection->Draw():
CRectTracker trackrect; SetupTracker(m_pSelection, &tractrect);
trackrect.Draw(pDC); // NOTE: add these inside the if block.
void C...View::SetupTracker(C...CntrItem* item, CRectTracker *track){
track->m_rect = item->m_rect;
if(item == m_pSelection) track->m_nStyle |= CRectTracker::resizeInside;
if(item->GetType() == OT_LINK) track->m_nStyle |= CRectTracker::dottedLine;
else track->m_nStyle |= CRectTracker::solidLine;
if(item->GetItemState() == COleClientItem::openState ||
item->GetItemState() == COleClientItem::activeUIState)
track->m_nStyle |= CRectTracker::hatchInside;
}

To cach mouse clicks and double clicks for sizing, moving or activating: Add following procedure to C...View.cpp::

C...CntrItem* C...View::HitTest(CPoint point){
  C...Doc* pDoc = GetDocument();
  C...CntrItem* pHitItem = NULL;
  POSITION pos = pDoc->GetStartPosition();
  while(pos){
   C...CntrItem* pCurrentItem = (C...CntrItem*)pDoc->GetNextClientItem(pos);
   if(pCurrentItem->m_rect.PtInRect(point)) pHitItem = pCurrentItem;
  } return pHitItem;
}

Do similar job on C...View::OnDraw():
  POSITION pos = pDoc->GetStartPosition();
  while(pos){
   C...CntrItem* pCurrentItem = (C...CntrlItem*) pDoc->GetNextClientItem(pos);
   pCurrentItem->Draw(pDC, pCurrentItem->m_rect);
   if(pCurrentItem == m_pSelection){
    CRectTracker trackrect; SetupTracker(pCurrentItem, &trackrect);
    trackrect.Draw(pDC);
   }
  }

Select C...View in CLassView, choose Add Windows Message Handler. THen select WM_LBUTTONDOWN, Add and Edit handler, and support:

void C...View::SetSelection(C...CntrItem* item){
  if(item == NULL || item != m_pSelection){
   COleClientItem* pActive = GetDocument->GetInPlaceActiveItem(this);
   if(pActive != NULL && pActive != item) pActive->Close();
   Invalidate(); m_pSelection = item;
 }
}

void C...View::OnLButtonDown(UINT nFlags, CPoint point){
  C...CntrItem* pHitItem = HitTest(point);
  SetSelection(pHitItem); if(pHitItem == NULL) return;
  CRectTracker track;
  SetupTracker(pHitItem, &track); UpdateWindow();
  if(track.Track(this, point)){
   Invalidate(); pHitItem->m_rect = track.m_rect;
   GetDocument()->SetModifiedFlag();
  }
}

ActiveX Server:

MDI + select Full Server in Compound Document Support

Class C...App gets new member: COleTemplateServer m_server
  and an include file, "IpFrame.h" defines CInPlaceFrame
  an App Id is also defined: static const CLSID clsid;
  InitInstance adds:
   if(!AfxOleInit()){ AfxMessageBox(IDP_OLE_INIT_FAILED); return FALSE; }
  and in between MultiDocTemplate initialization and AddDocTemplate:
   pDocTemplate->SetServerInfo(
    IDR_...TYPE_SRVR_EMB, IDR_...TYPE_SRVR_IP,
    RUNTIME_CLASS(CInPlaceFrame));
  and m_server.ConnectTemplate(clsid, pDocTemplate, FALSE);
  NOTE: to guarantee that a new MDI window is opened when a server
  is not launched on an item in place, the procedure COleTemplateServer::RegisterAll() is used, and:
   if(cmdInfo.m_bRunEmbedded || cmdInfo.m_bRunAutomated) return TRUE;
  then, as application is launched stand-alone:
   m_server.UpdateRegistry(OAT_INPLACE_SERVER);
  since ActiveX info is stored in the Registry (not necessary to do an install program)

C...Doc (: COleServerDoc)
  the included file "SrvrItem.h" defines the C..SrvrItem class
  The C..Doc constructor has line: EnableCompoundFile();
  Other functions can access the server item via:

C...SrvrItem *GetEmbeddedItem(){
   return (C..SrvrItem*)COleServerDoc::GetEmbeddedItem(); }
  This, in turn, calls the virtual function OnGetEmbeddedItem,
  which is implemented:
   COleServerItem *C...Doc::OnGetEmbeddedItem(){
    C..SrvrItem* pItem = new C...SrvrItem(this);
    ASSERT_VALID(pItem); return pItem;
   }

  new line in message map:
   ON_COMMAND(ID_CANCEL_EDIT_SRVR, OnCancelEditSrvr)
  and an accelerator to do this connection with ESC
   void C...View::OnCancelEditSrvr(){ GetDocument()->OnDeactivateUI(FALSE);

Class C...SrvrItem provides an interface between container app and the new type of document
  Serialize could add code to handle case where just a portion of doc is linked into another doc
  OnDraw(CDC *pDC, CSize &rSize) draws inactive document view
  OnGetExtent(DVASPECT, CSize&)

Class CInPlaceFrame provides things like toolbars, status bars, dialog-bars and has:
  CToolBar m_wndToolBar;
  COleResizeBar m_wndResizeBar;
  COleDropTarget m_dropTarget;
  OnCreate(LPCREATESTRUCT) registers this as a drop site
  OnCreateControlBars(CFrameWnd *frame, CFrameWnd *doc) creates and defines the toolbar. default is resizable and dockable, but these can be removed.

To change the file type names used by the Registry:
 Open the string table (in Resource View), select and edit IDR_...TYPE properties
   This was set up in Initinstance by:
   pDocTemplate = new CMultiDocTemplate(IDR_...TYPE,
   RUNTIME_CLASS(C...Doc), RUNTIME_CLASS(CChileFrame),
   RUNTIME_CLASS(C...View));
  if this was not set up correctly in AppWizard, it's easier to rebuild app from scratch!

  Then fill in code in ...Doc.h (member variables, Get functions, etc.
  In C..Doc::Serialize put in code that saves/restores member variables
  In C...OnNewDocument() put in code to initialize member variables
  Add necessary menu functions, including those for IDR_...SRVR_IP and IDR_...SRVR_EMB
  Add any accelerators, modify IDD_ABOUTBOX as necessary
  Select IDD_OPTIONS, and View/ClassWizard, creating COptionsDialog class
  Use ClassWizrd to arround for C...Doc to catch the ID_TOOLS_OPTIONS command
  Replace ClassWizard version of C...Doc::OnToolsOptions() to bring up options dialog
  Add #include "OptionsDialog.h" in ...Doc.cpp
  Use ClassWizard to connect dialog box controls to COptionsDialog member variables

  Add code to C..View::OnDraw(CDC*) and C...SrvrItem::OnDraw(CDC *, CSize&) etc.

ActiveX Server AND Container:

  Select both in AppWizard (Both Container And Server radio button)
  No to using same CLSID if working on same file types
  Do same for container and server
  NOTE: you can't edit in-place inside in-place edit sessions.

ActiveX Documents:

If document extension for an ActiveX document server app, following is added to C...App::InitInstance():
  m_pMainWnd->DragAcceptFiles();
  EnableShellOpen();
  RegisterShellFileTypes(TRUE);
  and m_server.UpdateRegistry(OAT_DOC_OBJECT_SERVER); (instead of OAD_INPLACE_SERVER)

ActiveX Automation

ActiveX Automation exposes a collection of functions and data (methods and properties). IDispatch is derived from IUnknown
  VBX -> OLE -> ActiveX
  ...

Embedding ActiveX Control, Java Applet. Video Clip, or Sound in an HTML Document
 <OBJECT ID="--name--"
   CLASSID = "CLSID:--number from ODC file for ActiveX Control--"
   CLODEBASE="--name--.cab#Version--ver no--"
   WIDTH=.. HEIGHT=..>
  <PARAM NAME="--name--" VALUE="--value--">
  <PARAM NAME="--name--" VALUE="--value--">
  ...
  --Alternate Text--
 </OBJECT>

Registering an ActiveX Control as Safe:
  Add 3 functions from the ActiveX SDK:
   CreateComponentCategory(CATID catid, WCHAR *)
   RegisterCLSIDInCategory(REFCLSID clsid, CATID)
   UnRegisterCLSIDInCategory(REFCLSID clsid, CATID)
  Also include "comcat.h" and "objsafe.h"
  Modify UpdateRegistry for control

Compound Document Support OLE/ActiveX

Active Template Library uses actual Win32 SDK functions, rather than MFC. Advantage is no DLLs are required on other end, as only functions actually used are included.

1. In DevStudio: File/New, select ATL COM AppWizard
2. Insert/New ATL Object (use Apartment), ...

Control inherits from numerous template classes

class ATL_NO_VTABLE CyourClass:: public CComObjectRootEx,
  CComCoClass, …

The CStockPropImpl base class is not derived from AppWizard, but from ObjectWizard.

The following COM map is the connection between all the interfaces supported by the control and IUnknown::QueryInterface():

BEGIN_COM_MAP(CyourClass)
  COM_INTERFACE_ENTRY(IyourClass)
  COM_INTERFACE_ENTRY(IDispatch)
  …
END_COM_MAP()

interface IyourClass: IDispatch{
   [propput, id(DISPID_BACKCOLOR)]
     HRESULT BackColor([in]OLE_COLOR clr);
   [propget, id(DISPID_BACKCOLOR)]
     HRESULT BackColor([out, retval(…