diff options
author | Bram Moolenaar <Bram@vim.org> | 2004-06-13 20:20:40 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2004-06-13 20:20:40 +0000 |
commit | 071d4279d6ab81b7187b48f3a0fc61e587b6db6c (patch) | |
tree | 221cbe3c40e043163c06f61c52a7ba2eb41e12ce /src/VisVim | |
parent | b4210b3bc14e2918f153a7307530fbe6eba659e1 (diff) |
updated for version 7.0001v7.0001
Diffstat (limited to 'src/VisVim')
-rw-r--r-- | src/VisVim/Commands.cpp | 693 | ||||
-rw-r--r-- | src/VisVim/Commands.h | 127 | ||||
-rw-r--r-- | src/VisVim/DSAddIn.cpp | 160 | ||||
-rw-r--r-- | src/VisVim/DSAddIn.h | 53 | ||||
-rw-r--r-- | src/VisVim/OleAut.cpp | 781 | ||||
-rw-r--r-- | src/VisVim/OleAut.h | 73 | ||||
-rw-r--r-- | src/VisVim/README_VisVim.txt | 322 | ||||
-rw-r--r-- | src/VisVim/Reg.cpp | 56 | ||||
-rw-r--r-- | src/VisVim/Register.bat | 1 | ||||
-rw-r--r-- | src/VisVim/Resource.h | 29 | ||||
-rw-r--r-- | src/VisVim/StdAfx.cpp | 6 | ||||
-rw-r--r-- | src/VisVim/StdAfx.h | 73 | ||||
-rw-r--r-- | src/VisVim/UnRegist.bat | 1 | ||||
-rw-r--r-- | src/VisVim/VisVim.cpp | 152 | ||||
-rw-r--r-- | src/VisVim/VisVim.def | 11 | ||||
-rw-r--r-- | src/VisVim/VisVim.dll | bin | 0 -> 49664 bytes | |||
-rw-r--r-- | src/VisVim/VisVim.h | 33 | ||||
-rw-r--r-- | src/VisVim/VisVim.mak | 205 | ||||
-rw-r--r-- | src/VisVim/VisVim.odl | 61 | ||||
-rw-r--r-- | src/VisVim/VisVim.rc | 199 | ||||
-rw-r--r-- | src/VisVim/VsReadMe.txt | 91 |
21 files changed, 3127 insertions, 0 deletions
diff --git a/src/VisVim/Commands.cpp b/src/VisVim/Commands.cpp new file mode 100644 index 0000000000..254b7a9647 --- /dev/null +++ b/src/VisVim/Commands.cpp @@ -0,0 +1,693 @@ +#include "stdafx.h" +#include <comdef.h> // For _bstr_t +#include "VisVim.h" +#include "Commands.h" +#include "OleAut.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; + +#endif + + +// Change directory before opening file? +#define CD_SOURCE 0 // Cd to source path +#define CD_SOURCE_PARENT 1 // Cd to parent directory of source path +#define CD_NONE 2 // No cd + + +static BOOL g_bEnableVim = TRUE; // Vim enabled +static BOOL g_bDevStudioEditor = FALSE; // Open file in Dev Studio editor simultaneously +static int g_ChangeDir = CD_NONE; // CD after file open? + +static void VimSetEnableState (BOOL bEnableState); +static BOOL VimOpenFile (BSTR& FileName, long LineNr); +static DISPID VimGetDispatchId (COleAutomationControl& VimOle, char* Method); +static void VimErrDiag (COleAutomationControl& VimOle); +static void VimChangeDir (COleAutomationControl& VimOle, DISPID DispatchId, BSTR& FileName); +static void DebugMsg (char* Msg, char* Arg = NULL); + + +///////////////////////////////////////////////////////////////////////////// +// CCommands + +CCommands::CCommands () +{ + // m_pApplication == NULL; M$ Code generation bug!!! + m_pApplication = NULL; + m_pApplicationEventsObj = NULL; + m_pDebuggerEventsObj = NULL; +} + +CCommands::~CCommands () +{ + ASSERT (m_pApplication != NULL); + if (m_pApplication) + { + m_pApplication->Release (); + m_pApplication = NULL; + } +} + +void CCommands::SetApplicationObject (IApplication * pApplication) +{ + // This function assumes pApplication has already been AddRef'd + // for us, which CDSAddIn did in its QueryInterface call + // just before it called us. + m_pApplication = pApplication; + if (! m_pApplication) + return; + + // Create Application event handlers + XApplicationEventsObj::CreateInstance (&m_pApplicationEventsObj); + if (! m_pApplicationEventsObj) + { + ReportInternalError ("XApplicationEventsObj::CreateInstance"); + return; + } + m_pApplicationEventsObj->AddRef (); + m_pApplicationEventsObj->Connect (m_pApplication); + m_pApplicationEventsObj->m_pCommands = this; + +#ifdef NEVER + // Create Debugger event handler + CComPtr < IDispatch > pDebugger; + if (SUCCEEDED (m_pApplication->get_Debugger (&pDebugger)) + && pDebugger != NULL) + { + XDebuggerEventsObj::CreateInstance (&m_pDebuggerEventsObj); + m_pDebuggerEventsObj->AddRef (); + m_pDebuggerEventsObj->Connect (pDebugger); + m_pDebuggerEventsObj->m_pCommands = this; + } +#endif + + // Get settings from registry HKEY_CURRENT_USER\Software\Vim\VisVim + HKEY hAppKey = GetAppKey ("Vim"); + if (hAppKey) + { + HKEY hSectionKey = GetSectionKey (hAppKey, "VisVim"); + if (hSectionKey) + { + g_bEnableVim = GetRegistryInt (hSectionKey, "EnableVim", + g_bEnableVim); + g_bDevStudioEditor = GetRegistryInt(hSectionKey,"DevStudioEditor", + g_bDevStudioEditor); + g_ChangeDir = GetRegistryInt (hSectionKey, "ChangeDir", + g_ChangeDir); + RegCloseKey (hSectionKey); + } + RegCloseKey (hAppKey); + } +} + +void CCommands::UnadviseFromEvents () +{ + ASSERT (m_pApplicationEventsObj != NULL); + if (m_pApplicationEventsObj) + { + m_pApplicationEventsObj->Disconnect (m_pApplication); + m_pApplicationEventsObj->Release (); + m_pApplicationEventsObj = NULL; + } + +#ifdef NEVER + if (m_pDebuggerEventsObj) + { + // Since we were able to connect to the Debugger events, we + // should be able to access the Debugger object again to + // unadvise from its events (thus the VERIFY_OK below--see + // stdafx.h). + CComPtr < IDispatch > pDebugger; + VERIFY_OK (m_pApplication->get_Debugger (&pDebugger)); + ASSERT (pDebugger != NULL); + m_pDebuggerEventsObj->Disconnect (pDebugger); + m_pDebuggerEventsObj->Release (); + m_pDebuggerEventsObj = NULL; + } +#endif +} + + +///////////////////////////////////////////////////////////////////////////// +// Event handlers + +// Application events + +HRESULT CCommands::XApplicationEvents::BeforeBuildStart () +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + return S_OK; +} + +HRESULT CCommands::XApplicationEvents::BuildFinish (long nNumErrors, long nNumWarnings) +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + return S_OK; +} + +HRESULT CCommands::XApplicationEvents::BeforeApplicationShutDown () +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + return S_OK; +} + +// The open document event handle is the place where the real interface work +// is done. +// Vim gets called from here. +// +HRESULT CCommands::XApplicationEvents::DocumentOpen (IDispatch * theDocument) +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + + if (! g_bEnableVim) + // Vim not enabled or empty command line entered + return S_OK; + + // First get the current file name and line number + + // Get the document object + CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc (theDocument); + if (! pDoc) + return S_OK; + + BSTR FileName; + long LineNr = -1; + + // Get the document name + if (FAILED (pDoc->get_FullName (&FileName))) + return S_OK; + + LPDISPATCH pDispSel; + + // Get a selection object dispatch pointer + if (SUCCEEDED (pDoc->get_Selection (&pDispSel))) + { + // Get the selection object + CComQIPtr < ITextSelection, &IID_ITextSelection > pSel (pDispSel); + + if (pSel) + // Get the selection line number + pSel->get_CurrentLine (&LineNr); + + pDispSel->Release (); + } + + // Open the file in Vim and position to the current line + if (VimOpenFile (FileName, LineNr)) + { + if (! g_bDevStudioEditor) + { + // Close the document in developer studio + CComVariant vSaveChanges = dsSaveChangesPrompt; + DsSaveStatus Saved; + + pDoc->Close (vSaveChanges, &Saved); + } + } + + // We're done here + SysFreeString (FileName); + return S_OK; +} + +HRESULT CCommands::XApplicationEvents::BeforeDocumentClose (IDispatch * theDocument) +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + return S_OK; +} + +HRESULT CCommands::XApplicationEvents::DocumentSave (IDispatch * theDocument) +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + return S_OK; +} + +HRESULT CCommands::XApplicationEvents::NewDocument (IDispatch * theDocument) +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + + if (! g_bEnableVim) + // Vim not enabled or empty command line entered + return S_OK; + + // First get the current file name and line number + + CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc (theDocument); + if (! pDoc) + return S_OK; + + BSTR FileName; + HRESULT hr; + + hr = pDoc->get_FullName (&FileName); + if (FAILED (hr)) + return S_OK; + + // Open the file in Vim and position to the current line + if (VimOpenFile (FileName, 0)) + { + if (! g_bDevStudioEditor) + { + // Close the document in developer studio + CComVariant vSaveChanges = dsSaveChangesPrompt; + DsSaveStatus Saved; + + pDoc->Close (vSaveChanges, &Saved); + } + } + + SysFreeString (FileName); + return S_OK; +} + +HRESULT CCommands::XApplicationEvents::WindowActivate (IDispatch * theWindow) +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + return S_OK; +} + +HRESULT CCommands::XApplicationEvents::WindowDeactivate (IDispatch * theWindow) +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + return S_OK; +} + +HRESULT CCommands::XApplicationEvents::WorkspaceOpen () +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + return S_OK; +} + +HRESULT CCommands::XApplicationEvents::WorkspaceClose () +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + return S_OK; +} + +HRESULT CCommands::XApplicationEvents::NewWorkspace () +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + return S_OK; +} + +// Debugger event + +HRESULT CCommands::XDebuggerEvents::BreakpointHit (IDispatch * pBreakpoint) +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + return S_OK; +} + + +///////////////////////////////////////////////////////////////////////////// +// VisVim dialog + +class CMainDialog : public CDialog +{ + public: + CMainDialog (CWnd * pParent = NULL); // Standard constructor + + //{{AFX_DATA(CMainDialog) + enum { IDD = IDD_ADDINMAIN }; + int m_ChangeDir; + BOOL m_bDevStudioEditor; + //}}AFX_DATA + + //{{AFX_VIRTUAL(CMainDialog) + protected: + virtual void DoDataExchange (CDataExchange * pDX); // DDX/DDV support + //}}AFX_VIRTUAL + + protected: + //{{AFX_MSG(CMainDialog) + afx_msg void OnEnable(); + afx_msg void OnDisable(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP () +}; + +CMainDialog::CMainDialog (CWnd * pParent /* =NULL */ ) + : CDialog (CMainDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CMainDialog) + m_ChangeDir = -1; + m_bDevStudioEditor = FALSE; + //}}AFX_DATA_INIT +} + +void CMainDialog::DoDataExchange (CDataExchange * pDX) +{ + CDialog::DoDataExchange (pDX); + //{{AFX_DATA_MAP(CMainDialog) + DDX_Radio(pDX, IDC_CD_SOURCE_PATH, m_ChangeDir); + DDX_Check (pDX, IDC_DEVSTUDIO_EDITOR, m_bDevStudioEditor); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP (CMainDialog, CDialog) + //{{AFX_MSG_MAP(CMainDialog) + //}}AFX_MSG_MAP +END_MESSAGE_MAP () + + +///////////////////////////////////////////////////////////////////////////// +// CCommands methods + +STDMETHODIMP CCommands::VisVimDialog () +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + + // Use m_pApplication to access the Developer Studio Application + // object, + // and VERIFY_OK to see error strings in DEBUG builds of your add-in + // (see stdafx.h) + + VERIFY_OK (m_pApplication->EnableModeless (VARIANT_FALSE)); + + CMainDialog Dlg; + + Dlg.m_bDevStudioEditor = g_bDevStudioEditor; + Dlg.m_ChangeDir = g_ChangeDir; + if (Dlg.DoModal () == IDOK) + { + g_bDevStudioEditor = Dlg.m_bDevStudioEditor; + g_ChangeDir = Dlg.m_ChangeDir; + + // Save settings to registry HKEY_CURRENT_USER\Software\Vim\VisVim + HKEY hAppKey = GetAppKey ("Vim"); + if (hAppKey) + { + HKEY hSectionKey = GetSectionKey (hAppKey, "VisVim"); + if (hSectionKey) + { + WriteRegistryInt (hSectionKey, "DevStudioEditor", + g_bDevStudioEditor); + WriteRegistryInt (hSectionKey, "ChangeDir", g_ChangeDir); + RegCloseKey (hSectionKey); + } + RegCloseKey (hAppKey); + } + } + + VERIFY_OK (m_pApplication->EnableModeless (VARIANT_TRUE)); + return S_OK; +} + +STDMETHODIMP CCommands::VisVimEnable () +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + VimSetEnableState (true); + return S_OK; +} + +STDMETHODIMP CCommands::VisVimDisable () +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + VimSetEnableState (false); + return S_OK; +} + +STDMETHODIMP CCommands::VisVimToggle () +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + VimSetEnableState (! g_bEnableVim); + return S_OK; +} + +STDMETHODIMP CCommands::VisVimLoad () +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + + // Use m_pApplication to access the Developer Studio Application object, + // and VERIFY_OK to see error strings in DEBUG builds of your add-in + // (see stdafx.h) + + CComBSTR bStr; + // Define dispatch pointers for document and selection objects + CComPtr < IDispatch > pDispDoc, pDispSel; + + // Get a document object dispatch pointer + VERIFY_OK (m_pApplication->get_ActiveDocument (&pDispDoc)); + if (! pDispDoc) + return S_OK; + + BSTR FileName; + long LineNr = -1; + + // Get the document object + CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc (pDispDoc); + + if (! pDoc) + return S_OK; + + // Get the document name + if (FAILED (pDoc->get_FullName (&FileName))) + return S_OK; + + // Get a selection object dispatch pointer + if (SUCCEEDED (pDoc->get_Selection (&pDispSel))) + { + // Get the selection object + CComQIPtr < ITextSelection, &IID_ITextSelection > pSel (pDispSel); + + if (pSel) + // Get the selection line number + pSel->get_CurrentLine (&LineNr); + } + + // Open the file in Vim + VimOpenFile (FileName, LineNr); + + SysFreeString (FileName); + return S_OK; +} + + +// +// Here we do the actual processing and communication with Vim +// + +// Set the enable state and save to registry +// +static void VimSetEnableState (BOOL bEnableState) +{ + g_bEnableVim = bEnableState; + HKEY hAppKey = GetAppKey ("Vim"); + if (hAppKey) + { + HKEY hSectionKey = GetSectionKey (hAppKey, "VisVim"); + if (hSectionKey) + WriteRegistryInt (hSectionKey, "EnableVim", g_bEnableVim); + RegCloseKey (hAppKey); + } +} + +// Open the file 'FileName' in Vim and goto line 'LineNr' +// 'FileName' is expected to contain an absolute DOS path including the drive +// letter. +// 'LineNr' must contain a valid line number or 0, e. g. for a new file +// +static BOOL VimOpenFile (BSTR& FileName, long LineNr) +{ + + // OLE automation object for com. with Vim + // When the object goes out of scope, it's desctructor destroys the OLE connection; + // This is imortant to avoid blocking the object + // (in this memory corruption would be likely when terminating Vim + // while still running DevStudio). + // So keep this object local! + COleAutomationControl VimOle; + + // :cd D:/Src2/VisVim/ + // + // Get a dispatch id for the SendKeys method of Vim; + // enables connection to Vim if necessary + DISPID DispatchId; + DispatchId = VimGetDispatchId (VimOle, "SendKeys"); + if (! DispatchId) + // OLE error, can't obtain dispatch id + goto OleError; + + OLECHAR Buf[MAX_OLE_STR]; + char FileNameTmp[MAX_OLE_STR]; + char VimCmd[MAX_OLE_STR]; + char *s, *p; + + // Prepend CTRL-\ CTRL-N to exit insert mode + VimCmd[0] = 0x1c; + VimCmd[1] = 0x0e; + VimCmd[2] = 0; + +#ifdef SINGLE_WINDOW + // Update the current file in Vim if it has been modified. + // Disabled, because it could write the file when you don't want to. + sprintf (VimCmd + 2, ":up\n"); +#endif + if (! VimOle.Method (DispatchId, "s", TO_OLE_STR_BUF (VimCmd, Buf))) + goto OleError; + + // Change Vim working directory to where the file is if desired + if (g_ChangeDir != CD_NONE) + VimChangeDir (VimOle, DispatchId, FileName); + + // Make Vim open the file. + // In the filename convert all \ to /, put a \ before a space. + sprintf(VimCmd, ":drop "); + sprintf(FileNameTmp, "%S", (char *)FileName); + s = VimCmd + 6; + for (p = FileNameTmp; *p != '\0' && s < FileNameTmp + MAX_OLE_STR - 4; + ++p) + if (*p == '\\') + *s++ = '/'; + else + { + if (*p == ' ') + *s++ = '\\'; + *s++ = *p; + } + *s++ = '\n'; + *s = '\0'; + + if (! VimOle.Method (DispatchId, "s", TO_OLE_STR_BUF (VimCmd, Buf))) + goto OleError; + + if (LineNr > 0) + { + // Goto line + sprintf (VimCmd, ":%d\n", LineNr); + if (! VimOle.Method (DispatchId, "s", TO_OLE_STR_BUF (VimCmd, Buf))) + goto OleError; + } + + // Make Vim come to the foreground + if (! VimOle.Method ("SetForeground")) + VimOle.ErrDiag (); + + // We're done + return true; + + OleError: + // There was an OLE error + // Check if it's the "unknown class string" error + VimErrDiag (VimOle); + return false; +} + +// Return the dispatch id for the Vim method 'Method' +// Create the Vim OLE object if necessary +// Returns a valid dispatch id or null on error +// +static DISPID VimGetDispatchId (COleAutomationControl& VimOle, char* Method) +{ + // Initialize Vim OLE connection if not already done + if (! VimOle.IsCreated ()) + { + if (! VimOle.CreateObject ("Vim.Application")) + return NULL; + } + + // Get the dispatch id for the SendKeys method. + // By doing this, we are checking if Vim is still there... + DISPID DispatchId = VimOle.GetDispatchId ("SendKeys"); + if (! DispatchId) + { + // We can't get a dispatch id. + // This means that probably Vim has been terminated. + // Don't issue an error message here, instead + // destroy the OLE object and try to connect once more + // + // In fact, this should never happen, because the OLE aut. object + // should not be kept long enough to allow the user to terminate Vim + // to avoid memory corruption (why the heck is there no system garbage + // collection for those damned OLE memory chunks???). + VimOle.DeleteObject (); + if (! VimOle.CreateObject ("Vim.Application")) + // If this create fails, it's time for an error msg + return NULL; + + if (! (DispatchId = VimOle.GetDispatchId ("SendKeys"))) + // There is something wrong... + return NULL; + } + + return DispatchId; +} + +// Output an error message for an OLE error +// Check on the classstring error, which probably means Vim wasn't registered. +// +static void VimErrDiag (COleAutomationControl& VimOle) +{ + SCODE sc = GetScode (VimOle.GetResult ()); + if (sc == CO_E_CLASSSTRING) + { + char Buf[256]; + sprintf (Buf, "There is no registered OLE automation server named " + "\"Vim.Application\".\n" + "Use the OLE-enabled version of Vim with VisVim and " + "make sure to register Vim by running \"vim -register\"."); + MessageBox (NULL, Buf, "OLE Error", MB_OK); + } + else + VimOle.ErrDiag (); +} + +// Change directory to the directory the file 'FileName' is in or it's parent +// directory according to the setting of the global 'g_ChangeDir': +// 'FileName' is expected to contain an absolute DOS path including the drive +// letter. +// CD_NONE +// CD_SOURCE_PATH +// CD_SOURCE_PARENT +// +static void VimChangeDir (COleAutomationControl& VimOle, DISPID DispatchId, BSTR& FileName) +{ + // Do a :cd first + + // Get the path name of the file ("dir/") + CString StrFileName = FileName; + char Drive[_MAX_DRIVE]; + char Dir[_MAX_DIR]; + char DirUnix[_MAX_DIR * 2]; + char *s, *t; + + _splitpath (StrFileName, Drive, Dir, NULL, NULL); + + // Convert to Unix path name format, escape spaces. + t = DirUnix; + for (s = Dir; *s; ++s) + if (*s == '\\') + *t++ = '/'; + else + { + if (*s == ' ') + *t++ = '\\'; + *t++ = *s; + } + *t = '\0'; + + + // Construct the cd command; append /.. if cd to parent + // directory and not in root directory + OLECHAR Buf[MAX_OLE_STR]; + char VimCmd[MAX_OLE_STR]; + + sprintf (VimCmd, ":cd %s%s%s\n", Drive, DirUnix, + g_ChangeDir == CD_SOURCE_PARENT && DirUnix[1] ? ".." : ""); + VimOle.Method (DispatchId, "s", TO_OLE_STR_BUF (VimCmd, Buf)); +} + +#ifdef _DEBUG +// Print out a debug message +// +static void DebugMsg (char* Msg, char* Arg) +{ + char Buf[400]; + sprintf (Buf, Msg, Arg); + AfxMessageBox (Buf); +} +#endif + diff --git a/src/VisVim/Commands.h b/src/VisVim/Commands.h new file mode 100644 index 0000000000..e47c81a130 --- /dev/null +++ b/src/VisVim/Commands.h @@ -0,0 +1,127 @@ +// Commands.h : header file +// + +#if !defined(AFX_COMMANDS_H__AC726717_2977_11D1_B2F3_006008040780__INCLUDED_) +#define AFX_COMMANDS_H__AC726717_2977_11D1_B2F3_006008040780__INCLUDED_ + +#include "vsvtypes.h" + +class CCommands : + public CComDualImpl < ICommands, + &IID_ICommands, + &LIBID_VisVim >, + public CComObjectRoot, + public CComCoClass < CCommands, + &CLSID_Commands > +{ + protected: + IApplication * m_pApplication; + + public: + CCommands (); + ~CCommands (); + void SetApplicationObject (IApplication * m_pApplication); + IApplication *GetApplicationObject () + { + return m_pApplication; + } + void UnadviseFromEvents (); + + BEGIN_COM_MAP (CCommands) + COM_INTERFACE_ENTRY (IDispatch) + COM_INTERFACE_ENTRY (ICommands) + END_COM_MAP () + DECLARE_NOT_AGGREGATABLE (CCommands) + + protected: + // This class template is used as the base class for the Application + // event handler object and the Debugger event handler object, + // which are declared below. + template < class IEvents, + const IID * piidEvents, + const GUID * plibid, + class XEvents, + const CLSID * pClsidEvents > + class XEventHandler : + public CComDualImpl < IEvents, + piidEvents, + plibid >, + public CComObjectRoot, + public CComCoClass < XEvents, + pClsidEvents > + { + public: + BEGIN_COM_MAP (XEvents) + COM_INTERFACE_ENTRY (IDispatch) + COM_INTERFACE_ENTRY_IID (*piidEvents, IEvents) + END_COM_MAP () + DECLARE_NOT_AGGREGATABLE (XEvents) + void Connect (IUnknown * pUnk) + { + VERIFY (SUCCEEDED (AtlAdvise (pUnk, this, *piidEvents, + &m_dwAdvise))); + } + void Disconnect (IUnknown * pUnk) + { + AtlUnadvise (pUnk, *piidEvents, m_dwAdvise); + } + + CCommands *m_pCommands; + + protected: + DWORD m_dwAdvise; + }; + + // This object handles events fired by the Application object + class XApplicationEvents : public XEventHandler < IApplicationEvents, + &IID_IApplicationEvents, + &LIBID_VisVim, + XApplicationEvents, + &CLSID_ApplicationEvents > + { + public: + // IApplicationEvents methods + STDMETHOD (BeforeBuildStart) (THIS); + STDMETHOD (BuildFinish) (THIS_ long nNumErrors, long nNumWarnings); + STDMETHOD (BeforeApplicationShutDown) (THIS); + STDMETHOD (DocumentOpen) (THIS_ IDispatch * theDocument); + STDMETHOD (BeforeDocumentClose) (THIS_ IDispatch * theDocument); + STDMETHOD (DocumentSave) (THIS_ IDispatch * theDocument); + STDMETHOD (NewDocument) (THIS_ IDispatch * theDocument); + STDMETHOD (WindowActivate) (THIS_ IDispatch * theWindow); + STDMETHOD (WindowDeactivate) (THIS_ IDispatch * theWindow); + STDMETHOD (WorkspaceOpen) (THIS); + STDMETHOD (WorkspaceClose) (THIS); + STDMETHOD (NewWorkspace) (THIS); + }; + typedef CComObject < XApplicationEvents > XApplicationEventsObj; + XApplicationEventsObj *m_pApplicationEventsObj; + + // This object handles events fired by the Application object + class XDebuggerEvents : public XEventHandler < IDebuggerEvents, + &IID_IDebuggerEvents, + &LIBID_VisVim, + XDebuggerEvents, + &CLSID_DebuggerEvents > + { + public: + // IDebuggerEvents method + STDMETHOD (BreakpointHit) (THIS_ IDispatch * pBreakpoint); + }; + typedef CComObject < XDebuggerEvents > XDebuggerEventsObj; + XDebuggerEventsObj *m_pDebuggerEventsObj; + + public: + // ICommands methods + STDMETHOD (VisVimDialog) (THIS); + STDMETHOD (VisVimEnable) (THIS); + STDMETHOD (VisVimDisable) (THIS); + STDMETHOD (VisVimToggle) (THIS); + STDMETHOD (VisVimLoad) (THIS); +}; + +typedef CComObject < CCommands > CCommandsObj; + +//{{AFX_INSERT_LOCATION}} + +#endif // !defined(AFX_COMMANDS_H__AC726717_2977_11D1_B2F3_006008040780__INCLUDED) diff --git a/src/VisVim/DSAddIn.cpp b/src/VisVim/DSAddIn.cpp new file mode 100644 index 0000000000..3e72544612 --- /dev/null +++ b/src/VisVim/DSAddIn.cpp @@ -0,0 +1,160 @@ +#include "stdafx.h" +#include "VisVim.h" +#include "DSAddIn.h" +#include "Commands.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; + +#endif + +// This is called when the user first loads the add-in, and on start-up +// of each subsequent Developer Studio session +STDMETHODIMP CDSAddIn::OnConnection (IApplication * pApp, VARIANT_BOOL bFirstTime, + long dwCookie, VARIANT_BOOL * OnConnection) +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + *OnConnection = VARIANT_FALSE; + + // Store info passed to us + IApplication *pApplication = NULL; + HRESULT hr; + + hr = pApp->QueryInterface (IID_IApplication, (void **) &pApplication); + if (FAILED (hr)) + { + ReportLastError (hr); + return E_UNEXPECTED; + } + if (pApplication == NULL) + { + ReportInternalError ("IApplication::QueryInterface"); + return E_UNEXPECTED; + } + + m_dwCookie = dwCookie; + + // Create command dispatch, send info back to DevStudio + CCommandsObj::CreateInstance (&m_pCommands); + if (! m_pCommands) + { + ReportInternalError ("CCommandsObj::CreateInstance"); + return E_UNEXPECTED; + } + m_pCommands->AddRef (); + + // The QueryInterface above AddRef'd the Application object. It will + // be Release'd in CCommand's destructor. + m_pCommands->SetApplicationObject (pApplication); + + hr = pApplication->SetAddInInfo ((long) AfxGetInstanceHandle (), + (LPDISPATCH) m_pCommands, IDR_TOOLBAR_MEDIUM, IDR_TOOLBAR_LARGE, + m_dwCookie); + if (FAILED (hr)) + { + ReportLastError (hr); + return E_UNEXPECTED; + } + + // Inform DevStudio of the commands we implement + if (! AddCommand (pApplication, "VisVimDialog", "VisVimDialogCmd", + IDS_CMD_DIALOG, 0, bFirstTime)) + return E_UNEXPECTED; + if (! AddCommand (pApplication, "VisVimEnable", "VisVimEnableCmd", + IDS_CMD_ENABLE, 1, bFirstTime)) + return E_UNEXPECTED; + if (! AddCommand (pApplication, "VisVimDisable", "VisVimDisableCmd", + IDS_CMD_DISABLE, 2, bFirstTime)) + return E_UNEXPECTED; + if (! AddCommand (pApplication, "VisVimToggle", "VisVimToggleCmd", + IDS_CMD_TOGGLE, 3, bFirstTime)) + return E_UNEXPECTED; + if (! AddCommand (pApplication, "VisVimLoad", "VisVimLoadCmd", + IDS_CMD_LOAD, 4, bFirstTime)) + return E_UNEXPECTED; + + *OnConnection = VARIANT_TRUE; + return S_OK; +} + +// This is called on shut-down, and also when the user unloads the add-in +STDMETHODIMP CDSAddIn::OnDisconnection (VARIANT_BOOL bLastTime) +{ + AFX_MANAGE_STATE (AfxGetStaticModuleState ()); + + m_pCommands->UnadviseFromEvents (); + m_pCommands->Release (); + m_pCommands = NULL; + + return S_OK; +} + +// Add a command to DevStudio +// Creates a toolbar button for the command also. +// 'MethodName' is the name of the methode specified in the .odl file +// 'StrResId' the resource id of the descriptive string +// 'GlyphIndex' the image index into the command buttons bitmap +// Return true on success +// +bool CDSAddIn::AddCommand (IApplication* pApp, char* MethodName, char* CmdName, + UINT StrResId, UINT GlyphIndex, VARIANT_BOOL bFirstTime) +{ + CString CmdString; + CString CmdText; + + CmdText.LoadString (StrResId); + CmdString = CmdName; + CmdString += CmdText; + + CComBSTR bszCmdString (CmdString); + CComBSTR bszMethod (MethodName); + CComBSTR bszCmdName (CmdName); + + // (see stdafx.h for the definition of VERIFY_OK) + + VARIANT_BOOL bRet; + VERIFY_OK (pApp->AddCommand (bszCmdString, bszMethod, GlyphIndex, + m_dwCookie, &bRet)); + if (bRet == VARIANT_FALSE) + { + // AddCommand failed because a command with this name already exists. + ReportInternalError ("IApplication::AddCommand"); + return FALSE; + } + + // Add toolbar buttons only if this is the first time the add-in + // is being loaded. Toolbar buttons are automatically remembered + // by Developer Studio from session to session, so we should only + // add the toolbar buttons once. + if (bFirstTime == VARIANT_TRUE) + VERIFY_OK (pApp->AddCommandBarButton (dsGlyph, bszCmdName, m_dwCookie)); + + return TRUE; +} + +void ReportLastError (HRESULT Err) +{ + char *Buf = NULL; + char Msg[512]; + + FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, Err, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + Buf, 400, NULL); + sprintf (Msg, "Unexpected error (Error code: %lx)\n%s", Err, Buf); + + ::MessageBox (NULL, Msg, "VisVim", MB_OK | MB_ICONSTOP); + if (Buf) + LocalFree (Buf); +} + +void ReportInternalError (char* Fct) +{ + char Msg[512]; + + sprintf (Msg, "Unexpected error\n%s failed", Fct); + ::MessageBox (NULL, Msg, "VisVim", MB_OK | MB_ICONSTOP); +} + diff --git a/src/VisVim/DSAddIn.h b/src/VisVim/DSAddIn.h new file mode 100644 index 0000000000..72828722f9 --- /dev/null +++ b/src/VisVim/DSAddIn.h @@ -0,0 +1,53 @@ +// DSAddIn.h : header file +// + +#if !defined(AFX_DSADDIN_H__AC726715_2977_11D1_B2F3_006008040780__INCLUDED_) +#define AFX_DSADDIN_H__AC726715_2977_11D1_B2F3_006008040780__INCLUDED_ + +#include "commands.h" + +// {4F9E01C0-406B-11d2-8006-00001C405077} +DEFINE_GUID (CLSID_DSAddIn, + 0x4f9e01c0, 0x406b, 0x11d2, 0x80, 0x6, 0x0, 0x0, 0x1c, 0x40, 0x50, 0x77); + +///////////////////////////////////////////////////////////////////////////// +// CDSAddIn + +class CDSAddIn : + public IDSAddIn, + public CComObjectRoot, + public CComCoClass < CDSAddIn, + &CLSID_DSAddIn > +{ |