1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Adam Lock <adamlock@eircom.net>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
38 #ifndef IOLECOMMANDIMPL_H
39 #define IOLECOMMANDIMPL_H
41 // Implementation of the IOleCommandTarget interface. The template is
42 // reasonably generic and reusable which is a good thing given how needlessly
43 // complicated this interface is. Blame Microsoft for that and not me.
45 // To use this class, derive your class from it like this:
47 // class CComMyClass : public IOleCommandTargetImpl<CComMyClass>
49 // ... Ensure IOleCommandTarget is listed in the interface map ...
50 // BEGIN_COM_MAP(CComMyClass)
51 // COM_INTERFACE_ENTRY(IOleCommandTarget)
54 // ... And then later on define the command target table ...
55 // BEGIN_OLECOMMAND_TABLE()
56 // OLECOMMAND_MESSAGE(OLECMDID_PRINT, NULL, ID_PRINT, L"Print", L"Print the page")
57 // OLECOMMAND_MESSAGE(OLECMDID_SAVEAS, NULL, 0, L"SaveAs", L"Save the page")
58 // OLECOMMAND_HANDLER(IDM_EDITMODE, &CGID_MSHTML, EditModeHandler, L"EditMode", L"Switch to edit mode")
59 // END_OLECOMMAND_TABLE()
60 // ... Now the window that OLECOMMAND_MESSAGE sends WM_COMMANDs to ...
61 // HWND GetCommandTargetWindow() const
65 // ... Now procedures that OLECOMMAND_HANDLER calls ...
66 // static HRESULT _stdcall EditModeHandler(CMozillaBrowser *pThis, const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
69 // The command table defines which commands the object supports. Commands are
70 // defined by a command id and a command group plus a WM_COMMAND id or procedure,
71 // and a verb and short description.
73 // Notice that there are two macros for handling Ole Commands. The first,
74 // OLECOMMAND_MESSAGE sends a WM_COMMAND message to the window returned from
75 // GetCommandTargetWindow() (that the derived class must implement if it uses
78 // The second, OLECOMMAND_HANDLER calls a static handler procedure that
79 // conforms to the OleCommandProc typedef. The first parameter, pThis means
80 // the static handler has access to the methods and variables in the class
83 // The OLECOMMAND_HANDLER macro is generally more useful when a command
84 // takes parameters or needs to return a result to the caller.
87 class IOleCommandTargetImpl
: public IOleCommandTarget
91 const GUID
*pguidCmdGroup
;
99 typedef HRESULT (_stdcall
*OleCommandProc
)(T
*pT
, const GUID
*pguidCmdGroup
, DWORD nCmdID
, DWORD nCmdexecopt
, VARIANT
*pvaIn
, VARIANT
*pvaOut
);
101 struct OleCommandInfo
104 const GUID
*pCmdGUID
;
106 OleCommandProc pfnCommandProc
;
108 wchar_t *szStatusText
;
111 // Query the status of the specified commands (test if is it supported etc.)
112 virtual HRESULT STDMETHODCALLTYPE
QueryStatus(const GUID __RPC_FAR
*pguidCmdGroup
, ULONG cCmds
, OLECMD __RPC_FAR prgCmds
[], OLECMDTEXT __RPC_FAR
*pCmdText
)
114 T
* pT
= static_cast<T
*>(this);
121 OleCommandInfo
*pCommands
= pT
->GetCommandTable();
122 ATLASSERT(pCommands
);
124 BOOL bCmdGroupFound
= FALSE
;
125 BOOL bTextSet
= FALSE
;
127 // Iterate through list of commands and flag them as supported/unsupported
128 for (ULONG nCmd
= 0; nCmd
< cCmds
; nCmd
++)
130 // Unsupported by default
131 prgCmds
[nCmd
].cmdf
= 0;
133 // Search the support command list
134 for (int nSupported
= 0; pCommands
[nSupported
].pCmdGUID
!= &GUID_NULL
; nSupported
++)
136 OleCommandInfo
*pCI
= &pCommands
[nSupported
];
138 if (pguidCmdGroup
&& pCI
->pCmdGUID
&& memcmp(pguidCmdGroup
, pCI
->pCmdGUID
, sizeof(GUID
)) == 0)
142 bCmdGroupFound
= TRUE
;
144 if (pCI
->nCmdID
!= prgCmds
[nCmd
].cmdID
)
149 // Command is supported so flag it and possibly enable it
150 prgCmds
[nCmd
].cmdf
= OLECMDF_SUPPORTED
;
151 if (pCI
->nWindowsCmdID
!= 0)
153 prgCmds
[nCmd
].cmdf
|= OLECMDF_ENABLED
;
156 // Copy the status/verb text for the first supported command only
157 if (!bTextSet
&& pCmdText
)
159 // See what text the caller wants
160 wchar_t *pszTextToCopy
= NULL
;
161 if (pCmdText
->cmdtextf
& OLECMDTEXTF_NAME
)
163 pszTextToCopy
= pCI
->szVerbText
;
165 else if (pCmdText
->cmdtextf
& OLECMDTEXTF_STATUS
)
167 pszTextToCopy
= pCI
->szStatusText
;
171 pCmdText
->cwActual
= 0;
172 memset(pCmdText
->rgwz
, 0, pCmdText
->cwBuf
* sizeof(wchar_t));
175 // Don't exceed the provided buffer size
176 size_t nTextLen
= wcslen(pszTextToCopy
);
177 if (nTextLen
> pCmdText
->cwBuf
)
179 nTextLen
= pCmdText
->cwBuf
;
182 wcsncpy(pCmdText
->rgwz
, pszTextToCopy
, nTextLen
);
183 pCmdText
->cwActual
= nTextLen
;
192 // Was the command group found?
195 OLECMDERR_E_UNKNOWNGROUP
;
202 // Execute the specified command
203 virtual HRESULT STDMETHODCALLTYPE
Exec(const GUID __RPC_FAR
*pguidCmdGroup
, DWORD nCmdID
, DWORD nCmdexecopt
, VARIANT __RPC_FAR
*pvaIn
, VARIANT __RPC_FAR
*pvaOut
)
205 T
* pT
= static_cast<T
*>(this);
206 BOOL bCmdGroupFound
= FALSE
;
208 OleCommandInfo
*pCommands
= pT
->GetCommandTable();
209 ATLASSERT(pCommands
);
211 // Search the support command list
212 for (int nSupported
= 0; pCommands
[nSupported
].pCmdGUID
!= &GUID_NULL
; nSupported
++)
214 OleCommandInfo
*pCI
= &pCommands
[nSupported
];
216 if (pguidCmdGroup
&& pCI
->pCmdGUID
&& memcmp(pguidCmdGroup
, pCI
->pCmdGUID
, sizeof(GUID
)) == 0)
220 bCmdGroupFound
= TRUE
;
222 if (pCI
->nCmdID
!= nCmdID
)
227 // Send ourselves a WM_COMMAND windows message with the associated
228 // identifier and exec data
230 cData
.pguidCmdGroup
= pguidCmdGroup
;
231 cData
.nCmdID
= nCmdID
;
232 cData
.nCmdexecopt
= nCmdexecopt
;
234 cData
.pvaOut
= pvaOut
;
236 if (pCI
->pfnCommandProc
)
238 pCI
->pfnCommandProc(pT
, pCI
->pCmdGUID
, pCI
->nCmdID
, nCmdexecopt
, pvaIn
, pvaOut
);
240 else if (pCI
->nWindowsCmdID
!= 0 && nCmdexecopt
!= OLECMDEXECOPT_SHOWHELP
)
242 HWND hwndTarget
= pT
->GetCommandTargetWindow();
245 ::SendMessage(hwndTarget
, WM_COMMAND
, LOWORD(pCI
->nWindowsCmdID
), (LPARAM
) &cData
);
250 // Command supported but not implemented
257 // Was the command group found?
260 OLECMDERR_E_UNKNOWNGROUP
;
263 return OLECMDERR_E_NOTSUPPORTED
;
267 // Macros to be placed in any class derived from the IOleCommandTargetImpl
268 // class. These define what commands are exposed from the object.
270 #define BEGIN_OLECOMMAND_TABLE() \
271 OleCommandInfo *GetCommandTable() \
273 static OleCommandInfo s_aSupportedCommands[] = \
276 #define OLECOMMAND_MESSAGE(id, group, cmd, verb, desc) \
277 { id, group, cmd, NULL, verb, desc },
279 #define OLECOMMAND_HANDLER(id, group, handler, verb, desc) \
280 { id, group, 0, handler, verb, desc },
282 #define END_OLECOMMAND_TABLE() \
283 { 0, &GUID_NULL, 0, NULL, NULL, NULL } \
285 return s_aSupportedCommands; \