Back to index

lightning-sunbird  0.9+nobinonly
IOleCommandTargetImpl.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Adam Lock <adamlock@eircom.net>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #ifndef IOLECOMMANDIMPL_H
00039 #define IOLECOMMANDIMPL_H
00040 
00041 // Implementation of the IOleCommandTarget interface. The template is
00042 // reasonably generic and reusable which is a good thing given how needlessly
00043 // complicated this interface is. Blame Microsoft for that and not me.
00044 //
00045 // To use this class, derive your class from it like this:
00046 //
00047 // class CComMyClass : public IOleCommandTargetImpl<CComMyClass>
00048 // {
00049 //     ... Ensure IOleCommandTarget is listed in the interface map ...
00050 // BEGIN_COM_MAP(CComMyClass)
00051 //     COM_INTERFACE_ENTRY(IOleCommandTarget)
00052 //     // etc.
00053 // END_COM_MAP()
00054 //     ... And then later on define the command target table ...
00055 // BEGIN_OLECOMMAND_TABLE()
00056 //    OLECOMMAND_MESSAGE(OLECMDID_PRINT, NULL, ID_PRINT, L"Print", L"Print the page")
00057 //    OLECOMMAND_MESSAGE(OLECMDID_SAVEAS, NULL, 0, L"SaveAs", L"Save the page")
00058 //    OLECOMMAND_HANDLER(IDM_EDITMODE, &CGID_MSHTML, EditModeHandler, L"EditMode", L"Switch to edit mode")
00059 // END_OLECOMMAND_TABLE()
00060 //     ... Now the window that OLECOMMAND_MESSAGE sends WM_COMMANDs to ...
00061 //     HWND GetCommandTargetWindow() const
00062 //     {
00063 //         return m_hWnd;
00064 //     }
00065 //     ... Now procedures that OLECOMMAND_HANDLER calls ...
00066 //     static HRESULT _stdcall EditModeHandler(CMozillaBrowser *pThis, const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
00067 // }
00068 //
00069 // The command table defines which commands the object supports. Commands are
00070 // defined by a command id and a command group plus a WM_COMMAND id or procedure,
00071 // and a verb and short description.
00072 //
00073 // Notice that there are two macros for handling Ole Commands. The first,
00074 // OLECOMMAND_MESSAGE sends a WM_COMMAND message to the window returned from
00075 // GetCommandTargetWindow() (that the derived class must implement if it uses
00076 // this macro).
00077 //
00078 // The second, OLECOMMAND_HANDLER calls a static handler procedure that
00079 // conforms to the OleCommandProc typedef. The first parameter, pThis means
00080 // the static handler has access to the methods and variables in the class
00081 // instance.
00082 //
00083 // The OLECOMMAND_HANDLER macro is generally more useful when a command
00084 // takes parameters or needs to return a result to the caller. 
00085 //
00086 template< class T >
00087 class IOleCommandTargetImpl : public IOleCommandTarget
00088 {
00089     struct OleExecData
00090     {
00091         const GUID *pguidCmdGroup;
00092         DWORD nCmdID;
00093         DWORD nCmdexecopt;
00094         VARIANT *pvaIn;
00095         VARIANT *pvaOut;
00096     };
00097 
00098 public:
00099     typedef HRESULT (_stdcall *OleCommandProc)(T *pT, const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
00100 
00101     struct OleCommandInfo
00102     {
00103         ULONG            nCmdID;
00104         const GUID        *pCmdGUID;
00105         ULONG            nWindowsCmdID;
00106         OleCommandProc    pfnCommandProc;
00107         wchar_t            *szVerbText;
00108         wchar_t            *szStatusText;
00109     };
00110 
00111     // Query the status of the specified commands (test if is it supported etc.)
00112     virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID __RPC_FAR *pguidCmdGroup, ULONG cCmds, OLECMD __RPC_FAR prgCmds[], OLECMDTEXT __RPC_FAR *pCmdText)
00113     {
00114         T* pT = static_cast<T*>(this);
00115         
00116         if (prgCmds == NULL)
00117         {
00118             return E_INVALIDARG;
00119         }
00120 
00121         OleCommandInfo *pCommands = pT->GetCommandTable();
00122         ATLASSERT(pCommands);
00123 
00124         BOOL bCmdGroupFound = FALSE;
00125         BOOL bTextSet = FALSE;
00126 
00127         // Iterate through list of commands and flag them as supported/unsupported
00128         for (ULONG nCmd = 0; nCmd < cCmds; nCmd++)
00129         {
00130             // Unsupported by default
00131             prgCmds[nCmd].cmdf = 0;
00132 
00133             // Search the support command list
00134             for (int nSupported = 0; pCommands[nSupported].pCmdGUID != &GUID_NULL; nSupported++)
00135             {
00136                 OleCommandInfo *pCI = &pCommands[nSupported];
00137 
00138                 if (pguidCmdGroup && pCI->pCmdGUID && memcmp(pguidCmdGroup, pCI->pCmdGUID, sizeof(GUID)) == 0)
00139                 {
00140                     continue;
00141                 }
00142                 bCmdGroupFound = TRUE;
00143 
00144                 if (pCI->nCmdID != prgCmds[nCmd].cmdID)
00145                 {
00146                     continue;
00147                 }
00148 
00149                 // Command is supported so flag it and possibly enable it
00150                 prgCmds[nCmd].cmdf = OLECMDF_SUPPORTED;
00151                 if (pCI->nWindowsCmdID != 0)
00152                 {
00153                     prgCmds[nCmd].cmdf |= OLECMDF_ENABLED;
00154                 }
00155 
00156                 // Copy the status/verb text for the first supported command only
00157                 if (!bTextSet && pCmdText)
00158                 {
00159                     // See what text the caller wants
00160                     wchar_t *pszTextToCopy = NULL;
00161                     if (pCmdText->cmdtextf & OLECMDTEXTF_NAME)
00162                     {
00163                         pszTextToCopy = pCI->szVerbText;
00164                     }
00165                     else if (pCmdText->cmdtextf & OLECMDTEXTF_STATUS)
00166                     {
00167                         pszTextToCopy = pCI->szStatusText;
00168                     }
00169                     
00170                     // Copy the text
00171                     pCmdText->cwActual = 0;
00172                     memset(pCmdText->rgwz, 0, pCmdText->cwBuf * sizeof(wchar_t));
00173                     if (pszTextToCopy)
00174                     {
00175                         // Don't exceed the provided buffer size
00176                         size_t nTextLen = wcslen(pszTextToCopy);
00177                         if (nTextLen > pCmdText->cwBuf)
00178                         {
00179                             nTextLen = pCmdText->cwBuf;
00180                         }
00181 
00182                         wcsncpy(pCmdText->rgwz, pszTextToCopy, nTextLen);
00183                         pCmdText->cwActual = nTextLen;
00184                     }
00185                     
00186                     bTextSet = TRUE;
00187                 }
00188                 break;
00189             }
00190         }
00191         
00192         // Was the command group found?
00193         if (!bCmdGroupFound)
00194         {
00195             OLECMDERR_E_UNKNOWNGROUP;
00196         }
00197 
00198         return S_OK;
00199     }
00200 
00201 
00202     // Execute the specified command
00203     virtual HRESULT STDMETHODCALLTYPE Exec(const GUID __RPC_FAR *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT __RPC_FAR *pvaIn, VARIANT __RPC_FAR *pvaOut)
00204     {
00205         T* pT = static_cast<T*>(this);
00206         BOOL bCmdGroupFound = FALSE;
00207 
00208         OleCommandInfo *pCommands = pT->GetCommandTable();
00209         ATLASSERT(pCommands);
00210 
00211         // Search the support command list
00212         for (int nSupported = 0; pCommands[nSupported].pCmdGUID != &GUID_NULL; nSupported++)
00213         {
00214             OleCommandInfo *pCI = &pCommands[nSupported];
00215 
00216             if (pguidCmdGroup && pCI->pCmdGUID && memcmp(pguidCmdGroup, pCI->pCmdGUID, sizeof(GUID)) == 0)
00217             {
00218                 continue;
00219             }
00220             bCmdGroupFound = TRUE;
00221 
00222             if (pCI->nCmdID != nCmdID)
00223             {
00224                 continue;
00225             }
00226 
00227             // Send ourselves a WM_COMMAND windows message with the associated
00228             // identifier and exec data
00229             OleExecData cData;
00230             cData.pguidCmdGroup = pguidCmdGroup;
00231             cData.nCmdID = nCmdID;
00232             cData.nCmdexecopt = nCmdexecopt;
00233             cData.pvaIn = pvaIn;
00234             cData.pvaOut = pvaOut;
00235 
00236             if (pCI->pfnCommandProc)
00237             {
00238                 pCI->pfnCommandProc(pT, pCI->pCmdGUID, pCI->nCmdID, nCmdexecopt, pvaIn, pvaOut);
00239             }
00240             else if (pCI->nWindowsCmdID != 0 && nCmdexecopt != OLECMDEXECOPT_SHOWHELP)
00241             {
00242                 HWND hwndTarget = pT->GetCommandTargetWindow();
00243                 if (hwndTarget)
00244                 {
00245                     ::SendMessage(hwndTarget, WM_COMMAND, LOWORD(pCI->nWindowsCmdID), (LPARAM) &cData);
00246                 }
00247             }
00248             else
00249             {
00250                 // Command supported but not implemented
00251                 continue;
00252             }
00253 
00254             return S_OK;
00255         }
00256 
00257         // Was the command group found?
00258         if (!bCmdGroupFound)
00259         {
00260             OLECMDERR_E_UNKNOWNGROUP;
00261         }
00262 
00263         return OLECMDERR_E_NOTSUPPORTED;
00264     }
00265 };
00266 
00267 // Macros to be placed in any class derived from the IOleCommandTargetImpl
00268 // class. These define what commands are exposed from the object.
00269 
00270 #define BEGIN_OLECOMMAND_TABLE() \
00271     OleCommandInfo *GetCommandTable() \
00272     { \
00273         static OleCommandInfo s_aSupportedCommands[] = \
00274         {
00275 
00276 #define OLECOMMAND_MESSAGE(id, group, cmd, verb, desc) \
00277             { id, group, cmd, NULL, verb, desc },
00278 
00279 #define OLECOMMAND_HANDLER(id, group, handler, verb, desc) \
00280             { id, group, 0, handler, verb, desc },
00281 
00282 #define END_OLECOMMAND_TABLE() \
00283             { 0, &GUID_NULL, 0, NULL, NULL, NULL } \
00284         }; \
00285         return s_aSupportedCommands; \
00286     };
00287 
00288 #endif