summaryrefslogtreecommitdiffstats
path: root/src/VisVim
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2004-06-13 20:20:40 +0000
committerBram Moolenaar <Bram@vim.org>2004-06-13 20:20:40 +0000
commit071d4279d6ab81b7187b48f3a0fc61e587b6db6c (patch)
tree221cbe3c40e043163c06f61c52a7ba2eb41e12ce /src/VisVim
parentb4210b3bc14e2918f153a7307530fbe6eba659e1 (diff)
updated for version 7.0001v7.0001
Diffstat (limited to 'src/VisVim')
-rw-r--r--src/VisVim/Commands.cpp693
-rw-r--r--src/VisVim/Commands.h127
-rw-r--r--src/VisVim/DSAddIn.cpp160
-rw-r--r--src/VisVim/DSAddIn.h53
-rw-r--r--src/VisVim/OleAut.cpp781
-rw-r--r--src/VisVim/OleAut.h73
-rw-r--r--src/VisVim/README_VisVim.txt322
-rw-r--r--src/VisVim/Reg.cpp56
-rw-r--r--src/VisVim/Register.bat1
-rw-r--r--src/VisVim/Resource.h29
-rw-r--r--src/VisVim/StdAfx.cpp6
-rw-r--r--src/VisVim/StdAfx.h73
-rw-r--r--src/VisVim/UnRegist.bat1
-rw-r--r--src/VisVim/VisVim.cpp152
-rw-r--r--src/VisVim/VisVim.def11
-rw-r--r--src/VisVim/VisVim.dllbin0 -> 49664 bytes
-rw-r--r--src/VisVim/VisVim.h33
-rw-r--r--src/VisVim/VisVim.mak205
-rw-r--r--src/VisVim/VisVim.odl61
-rw-r--r--src/VisVim/VisVim.rc199
-rw-r--r--src/VisVim/VsReadMe.txt91
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 >
+{