액셀러레이터 키(화살표, 탭 키같은)를 ActiveX 컨트롤 컨테이너의 메시지 펌프가 가로채기 때문에, 컨트롤에 포커스가 있어도 키 메시지를 받지 못한다. MFC 액티브X 컨트롤은 PretranslateMessage 함수를 오버라이드함으로써 이러한 메시지들을 가로챌 수 있다.
그러나, MFC 액티브X 컨트롤의 PreTranslateMessage 함수가 항상 호출되는 것은 아니다.
PreTranslateMessage 함수는 컨트롤의 IOleInPlaceActiveObject 인터페이스의 TranslateAccelerator 메소드가 호출한다. 인터넷 익스플로러는 현재 UI-Active인 컨트롤에 한해서 이 메소드를 호출한다. 한번에 하나의 컨트롤 만이 UI-Active일 수 있다.
인터넷 익스플로러는 페이지가 로드될 때 자동으로 어떠한 컨트롤도 UI-Active하지 않는다. 인터넷 익스플로러는 사용자가 탭키를 눌러 해당 액티브X 컨트롤을 UI-Active할 때까지 기다린다.
COleControlModule -> CWinApp
the server module (that is, the DLL) in which the control is housed
.InitInstance()
.ExitInstance()
COleControl -> CWnd
메소드
프로퍼티
이벤트
OnSetClientSite
OnDraw
.DoPropExchange() // virtural - 여기서 사용자 정의 프로퍼티를 파일로 저장한다. // ATL Property Map
<HTML>
<HEAD>
<TITLE>ActiveX control test page for object CircleCtrl</TITLE>
</HEAD>
<BODY>
<OBJECT
id=CircleCtrl
width=300
height=300
classid=CLSID:7236F083-1DC0-45A8-A3CC-A0CB8DAFB1BC>
<PARAM NAME="Caption" VALUE="Click Here">
<PARAM NAME="ForeColor" VALUE="16711680">
<PARAM NAME="BackColor" VALUE="16777215">
<PARAM NAME="FlashColor" VALUE="65535">
<PARAM Name = "MyName" VALUE = "...">
</OBJECT>
<SCRIPT LANGUAGE="VBScript">
<!--
Sub CircleCtrl_ClickInside(x, y)
CStr str
str = "Click (" & x & ", " & y & ")"
Document.title = str
end Sub
-->
</SCRIPT>
</BODY>
</HTML>
[ uuid(92B2E0C4-50AB-4E78-A928-903116E97DAC),
helpstring("Dispatch interface for Circle Control"), hidden ]
dispinterface _DCircle
{
properties:
// NOTE - ClassWizard will maintain property information here.
// Use extreme caution when editing this section.
//{{AFX_ODL_PROP(CCircleCtrl)
[id(1)] OLE_COLOR FlashColor;
[id(DISPID_FORECOLOR), bindable, requestedit] OLE_COLOR ForeColor;
[id(DISPID_BACKCOLOR), bindable, requestedit] OLE_COLOR BackColor;
[id(DISPID_CAPTION), bindable, requestedit] BSTR Caption;
[id(DISPID_FONT), bindable] IFontDisp* Font;
//}}AFX_ODL_PROP
methods:
// NOTE - ClassWizard will maintain method information here.
// Use extreme caution when editing this section.
//{{AFX_ODL_METHOD(CCircleCtrl)
[id(2)] void Flash();
//}}AFX_ODL_METHOD
[id(DISPID_ABOUTBOX)] void AboutBox();
};
// Event dispatch interface for CCircleCtrl
[ uuid(5635A488-8BA6-4AAB-B3BD-AC9AFD35131E),
helpstring("Event interface for Circle Control") ]
dispinterface _DCircleEvents
{
properties:
// Event interface has no properties
methods:
// NOTE - ClassWizard will maintain event information here.
// Use extreme caution when editing this section.
//{{AFX_ODL_EVENT(CCircleCtrl)
[id(DISPID_MOUSEDOWN)] void MouseDown(short Button, short Shift, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);
[id(DISPID_MOUSEUP)] void MouseUp(short Button, short Shift, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);
[id(1)] void ClickInside(OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);
//}}AFX_ODL_EVENT
};
// Class information for CCircleCtrl
[ uuid(7236F083-1DC0-45A8-A3CC-A0CB8DAFB1BC),
helpstring("Circle Control"), control ]
coclass Circle
{
[default] dispinterface _DCircle;
[default, source] dispinterface _DCircleEvents;
};
if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
return ResultFromScode(SELFREG_E_TYPELIB);
if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
return ResultFromScode(SELFREG_E_CLASS);
// { if (FAILED( CreateComponentCategory(CATID_SafeForScripting, L"Controls that are safely scriptable") )) return ResultFromScode(SELFREG_E_CLASS);
if (FAILED( CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data") )) return ResultFromScode(SELFREG_E_CLASS);
if (FAILED( RegisterCLSIDInCategory(_ctlid, CATID_SafeForScripting) )) return ResultFromScode(SELFREG_E_CLASS);
class CTestFormCtrl : public COleControl
{
...
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CJoyUploadCtrl)
public:
... virtual BOOL PreTranslateMessage(MSG* pMsg);
//}}AFX_VIRTUAL
...
// Message maps
//{{AFX_MSG(CTestFormCtrl) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg int OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
...
// Dispatch and event IDs
public:
enum {
//{{AFX_DISP_ID(CTestFormCtrl)
// NOTE: ClassWizard will add and remove enumeration elements here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_DISP_ID
};
private: CTestFormView *m_pTestFormView;
};
BEGIN_MESSAGE_MAP(CTestFormCtrl, COleControl)
//{{AFX_MSG_MAP(CTestFormCtrl) ON_WM_CREATE()
//}}AFX_MSG_MAP
ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()
... int CTestFormCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (COleControl::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
// { OnActivateInPlace (TRUE, NULL); // == UI-Activate the control
int CTestFormCtrl::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message) { // {
if (!m_bUIActive)
OnActivateInPlace (TRUE, NULL); // == UI-Activate the control // } return COleControl::OnMouseActivate(pDesktopWnd, nHitTest, message); }
// trap keys and forward on to the control BOOL CTestFormCtrl::PreTranslateMessage(MSG* pMsg) {
// {
switch (pMsg->message)
{
case WM_KEYDOWN:
case WM_KEYUP:
switch (pMsg->wParam)
{
case VK_UP:
case VK_DOWN:
case VK_LEFT:
case VK_RIGHT:
case VK_HOME:
case VK_END:
SendMessage (pMsg->message, pMsg->wParam, pMsg->lParam);
// Windowless controls won't be able to call SendMessage.
// Instead, just respond to the message here.
return TRUE;
}
break;
} // } return COleControl::PreTranslateMessage(pMsg); }
class CTestFormView : public CFormView
{ public:
CTestFormView(); // protected constructor used by dynamic creation
protected:
DECLARE_DYNCREATE(CTestFormView)
...
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTestFormView)
public: virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL);
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL