Commands.cpp
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:16k
源码类别:

编辑器/阅读器

开发平台:

DOS

  1. #include "stdafx.h"
  2. #include <comdef.h> // For _bstr_t
  3. #include "VisVim.h"
  4. #include "Commands.h"
  5. #include "OleAut.h"
  6. #ifdef _DEBUG
  7. #define new DEBUG_NEW
  8. #undef THIS_FILE
  9. static char THIS_FILE[] = __FILE__;
  10. #endif
  11. // Change directory before opening file?
  12. #define CD_SOURCE 0 // Cd to source path
  13. #define CD_SOURCE_PARENT 1 // Cd to parent directory of source path
  14. #define CD_NONE 2 // No cd
  15. static BOOL g_bEnableVim = TRUE; // Vim enabled
  16. static BOOL g_bDevStudioEditor = FALSE; // Open file in Dev Studio editor simultaneously
  17. static int g_ChangeDir = CD_NONE; // CD after file open?
  18. static COleAutomationControl VimOle; // OLE automation object for com. with Vim
  19. static void VimSetEnableState (BOOL bEnableState);
  20. static BOOL VimOpenFile (BSTR& FileName, long LineNr);
  21. static DISPID VimGetDispatchId (char* Method);
  22. static void VimErrDiag ();
  23. static void VimChangeDir (BSTR& FileName, DISPID DispatchId);
  24. static void DebugMsg (char* Msg, char* Arg = NULL);
  25. /////////////////////////////////////////////////////////////////////////////
  26. // CCommands
  27. CCommands::CCommands ()
  28. {
  29. m_pApplication == NULL;
  30. m_pApplicationEventsObj = NULL;
  31. m_pDebuggerEventsObj = NULL;
  32. }
  33. CCommands::~CCommands ()
  34. {
  35. ASSERT (m_pApplication != NULL);
  36. m_pApplication->Release ();
  37. }
  38. void CCommands::SetApplicationObject (IApplication * pApplication)
  39. {
  40. // This function assumes pApplication has already been AddRef'd
  41. // for us, which CDSAddIn did in its QueryInterface call
  42. // just before it called us.
  43. m_pApplication = pApplication;
  44. // Create Application event handlers
  45. XApplicationEventsObj::CreateInstance (&m_pApplicationEventsObj);
  46. m_pApplicationEventsObj->AddRef ();
  47. m_pApplicationEventsObj->Connect (m_pApplication);
  48. m_pApplicationEventsObj->m_pCommands = this;
  49. #ifdef NEVER
  50. // Create Debugger event handler
  51. CComPtr < IDispatch > pDebugger;
  52. if (SUCCEEDED (m_pApplication->get_Debugger (&pDebugger))
  53.     && pDebugger != NULL)
  54. {
  55. XDebuggerEventsObj::CreateInstance (&m_pDebuggerEventsObj);
  56. m_pDebuggerEventsObj->AddRef ();
  57. m_pDebuggerEventsObj->Connect (pDebugger);
  58. m_pDebuggerEventsObj->m_pCommands = this;
  59. }
  60. #endif
  61. // Get settings from registry HKEY_CURRENT_USERSoftwareVimVisVim
  62. HKEY hAppKey = GetAppKey ("Vim");
  63. if (hAppKey)
  64. {
  65. HKEY hSectionKey = GetSectionKey (hAppKey, "VisVim");
  66. if (hSectionKey)
  67. {
  68. g_bEnableVim = GetRegistryInt (hSectionKey, "EnableVim",
  69.        g_bEnableVim);
  70. g_bDevStudioEditor = GetRegistryInt(hSectionKey,"DevStudioEditor",
  71.     g_bDevStudioEditor);
  72. g_ChangeDir = GetRegistryInt (hSectionKey, "ChangeDir",
  73.       g_ChangeDir);
  74. RegCloseKey (hSectionKey);
  75. }
  76. RegCloseKey (hAppKey);
  77. }
  78. }
  79. void CCommands::UnadviseFromEvents ()
  80. {
  81. // Destroy OLE connection
  82. VimOle.DeleteObject ();
  83. ASSERT (m_pApplicationEventsObj != NULL);
  84. m_pApplicationEventsObj->Disconnect (m_pApplication);
  85. m_pApplicationEventsObj->Release ();
  86. m_pApplicationEventsObj = NULL;
  87. #ifdef NEVER
  88. if (m_pDebuggerEventsObj)
  89. {
  90. // Since we were able to connect to the Debugger events, we
  91. // should be able to access the Debugger object again to
  92. // unadvise from its events (thus the VERIFY_OK below--see
  93. // stdafx.h).
  94. CComPtr < IDispatch > pDebugger;
  95. VERIFY_OK (m_pApplication->get_Debugger (&pDebugger));
  96. ASSERT (pDebugger != NULL);
  97. m_pDebuggerEventsObj->Disconnect (pDebugger);
  98. m_pDebuggerEventsObj->Release ();
  99. m_pDebuggerEventsObj = NULL;
  100. }
  101. #endif
  102. }
  103. /////////////////////////////////////////////////////////////////////////////
  104. // Event handlers
  105. // Application events
  106. HRESULT CCommands::XApplicationEvents::BeforeBuildStart ()
  107. {
  108. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  109. return S_OK;
  110. }
  111. HRESULT CCommands::XApplicationEvents::BuildFinish (long nNumErrors, long nNumWarnings)
  112. {
  113. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  114. return S_OK;
  115. }
  116. HRESULT CCommands::XApplicationEvents::BeforeApplicationShutDown ()
  117. {
  118. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  119. return S_OK;
  120. }
  121. // The open document event handle is the place where the real interface work
  122. // is done.
  123. // Vim gets called from here.
  124. //
  125. HRESULT CCommands::XApplicationEvents::DocumentOpen (IDispatch * theDocument)
  126. {
  127. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  128. if (! g_bEnableVim)
  129. // Vim not enabled or empty command line entered
  130. return S_OK;
  131. // First get the current file name and line number
  132. // Get the document object
  133. CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc (theDocument);
  134. if (! pDoc)
  135. return S_OK;
  136. BSTR FileName;
  137. long LineNr = -1;
  138. // Get the document name
  139. if (FAILED (pDoc->get_FullName (&FileName)))
  140. return S_OK;
  141. LPDISPATCH pDispSel;
  142. // Get a selection object dispatch pointer
  143. if (SUCCEEDED (pDoc->get_Selection (&pDispSel)))
  144. {
  145. // Get the selection object
  146. CComQIPtr < ITextSelection, &IID_ITextSelection > pSel (pDispSel);
  147. if (pSel)
  148. // Get the selection line number
  149. pSel->get_CurrentLine (&LineNr);
  150. pDispSel->Release ();
  151. }
  152. // Open the file in Vim and position to the current line
  153. if (VimOpenFile (FileName, LineNr))
  154. {
  155. if (! g_bDevStudioEditor)
  156. {
  157. // Close the document in developer studio
  158. CComVariant vSaveChanges = dsSaveChangesPrompt;
  159. DsSaveStatus Saved;
  160. pDoc->Close (vSaveChanges, &Saved);
  161. }
  162. }
  163. // We're done here
  164. return S_OK;
  165. }
  166. HRESULT CCommands::XApplicationEvents::BeforeDocumentClose (IDispatch * theDocument)
  167. {
  168. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  169. return S_OK;
  170. }
  171. HRESULT CCommands::XApplicationEvents::DocumentSave (IDispatch * theDocument)
  172. {
  173. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  174. return S_OK;
  175. }
  176. HRESULT CCommands::XApplicationEvents::NewDocument (IDispatch * theDocument)
  177. {
  178. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  179. if (! g_bEnableVim)
  180. // Vim not enabled or empty command line entered
  181. return S_OK;
  182. // First get the current file name and line number
  183. CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc (theDocument);
  184. if (! pDoc)
  185. return S_OK;
  186. BSTR FileName;
  187. HRESULT hr;
  188. hr = pDoc->get_FullName (&FileName);
  189. if (FAILED (hr))
  190. return S_OK;
  191. // Open the file in Vim and position to the current line
  192. if (VimOpenFile (FileName, 0))
  193. {
  194. if (! g_bDevStudioEditor)
  195. {
  196. // Close the document in developer studio
  197. CComVariant vSaveChanges = dsSaveChangesPrompt;
  198. DsSaveStatus Saved;
  199. pDoc->Close (vSaveChanges, &Saved);
  200. }
  201. }
  202. return S_OK;
  203. }
  204. HRESULT CCommands::XApplicationEvents::WindowActivate (IDispatch * theWindow)
  205. {
  206. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  207. return S_OK;
  208. }
  209. HRESULT CCommands::XApplicationEvents::WindowDeactivate (IDispatch * theWindow)
  210. {
  211. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  212. return S_OK;
  213. }
  214. HRESULT CCommands::XApplicationEvents::WorkspaceOpen ()
  215. {
  216. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  217. return S_OK;
  218. }
  219. HRESULT CCommands::XApplicationEvents::WorkspaceClose ()
  220. {
  221. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  222. return S_OK;
  223. }
  224. HRESULT CCommands::XApplicationEvents::NewWorkspace ()
  225. {
  226. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  227. return S_OK;
  228. }
  229. // Debugger event
  230. HRESULT CCommands::XDebuggerEvents::BreakpointHit (IDispatch * pBreakpoint)
  231. {
  232. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  233. return S_OK;
  234. }
  235. /////////////////////////////////////////////////////////////////////////////
  236. // VisVim dialog
  237. class CMainDialog : public CDialog
  238. {
  239.     public:
  240. CMainDialog (CWnd * pParent = NULL); // Standard constructor
  241. //{{AFX_DATA(CMainDialog)
  242. enum { IDD = IDD_ADDINMAIN };
  243. BOOL m_bDevStudioEditor;
  244. int m_ChangeDir;
  245. //}}AFX_DATA
  246. //{{AFX_VIRTUAL(CMainDialog)
  247.     protected:
  248. virtual void DoDataExchange (CDataExchange * pDX); // DDX/DDV support
  249. //}}AFX_VIRTUAL
  250.     protected:
  251. //{{AFX_MSG(CMainDialog)
  252. afx_msg void OnEnable();
  253. afx_msg void OnDisable();
  254. //}}AFX_MSG
  255. DECLARE_MESSAGE_MAP ()
  256. };
  257. CMainDialog::CMainDialog (CWnd * pParent /* =NULL */ )
  258. : CDialog (CMainDialog::IDD, pParent)
  259. {
  260. //{{AFX_DATA_INIT(CMainDialog)
  261. m_bDevStudioEditor = FALSE;
  262. m_ChangeDir = -1;
  263. //}}AFX_DATA_INIT
  264. }
  265. void CMainDialog::DoDataExchange (CDataExchange * pDX)
  266. {
  267. CDialog::DoDataExchange (pDX);
  268. //{{AFX_DATA_MAP(CMainDialog)
  269. DDX_Check (pDX, IDC_DEVSTUDIO_EDITOR, m_bDevStudioEditor);
  270. DDX_Radio(pDX, IDC_CD_SOURCE_PATH, m_ChangeDir);
  271. //}}AFX_DATA_MAP
  272. }
  273. BEGIN_MESSAGE_MAP (CMainDialog, CDialog)
  274. //{{AFX_MSG_MAP(CMainDialog)
  275. //}}AFX_MSG_MAP
  276. END_MESSAGE_MAP ()
  277. /////////////////////////////////////////////////////////////////////////////
  278. // CCommands methods
  279. STDMETHODIMP CCommands::VisVimDialog ()
  280. {
  281. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  282. // Use m_pApplication to access the Developer Studio Application
  283. // object,
  284. // and VERIFY_OK to see error strings in DEBUG builds of your add-in
  285. // (see stdafx.h)
  286. VERIFY_OK (m_pApplication->EnableModeless (VARIANT_FALSE));
  287. CMainDialog Dlg;
  288. Dlg.m_bDevStudioEditor = g_bDevStudioEditor;
  289. Dlg.m_ChangeDir = g_ChangeDir;
  290. if (Dlg.DoModal () == IDOK)
  291. {
  292. g_bDevStudioEditor = Dlg.m_bDevStudioEditor;
  293. g_ChangeDir = Dlg.m_ChangeDir;
  294. // Save settings to registry HKEY_CURRENT_USERSoftwareVimVisVim
  295. HKEY hAppKey = GetAppKey ("Vim");
  296. if (hAppKey)
  297. {
  298. HKEY hSectionKey = GetSectionKey (hAppKey, "VisVim");
  299. if (hSectionKey)
  300. {
  301. WriteRegistryInt (hSectionKey, "DevStudioEditor",
  302.   g_bDevStudioEditor);
  303. WriteRegistryInt (hSectionKey, "ChangeDir", g_ChangeDir);
  304. RegCloseKey (hSectionKey);
  305. }
  306. RegCloseKey (hAppKey);
  307. }
  308. }
  309. VERIFY_OK (m_pApplication->EnableModeless (VARIANT_TRUE));
  310. return S_OK;
  311. }
  312. STDMETHODIMP CCommands::VisVimEnable ()
  313. {
  314. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  315. VimSetEnableState (true);
  316. return S_OK;
  317. }
  318. STDMETHODIMP CCommands::VisVimDisable ()
  319. {
  320. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  321. VimSetEnableState (false);
  322. return S_OK;
  323. }
  324. STDMETHODIMP CCommands::VisVimToggle ()
  325. {
  326. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  327. VimSetEnableState (! g_bEnableVim);
  328. return S_OK;
  329. }
  330. STDMETHODIMP CCommands::VisVimLoad ()
  331. {
  332. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  333. // Use m_pApplication to access the Developer Studio Application object,
  334. // and VERIFY_OK to see error strings in DEBUG builds of your add-in
  335. // (see stdafx.h)
  336. //
  337. VERIFY_OK (m_pApplication->EnableModeless (VARIANT_FALSE));
  338. CComBSTR bStr;
  339. // Define dispatch pointers for document and selection objects
  340. CComPtr < IDispatch > pDispDoc, pDispSel;
  341. // Get a document object dispatch pointer
  342. VERIFY_OK (m_pApplication->get_ActiveDocument (&pDispDoc));
  343. if (! pDispDoc)
  344. return S_OK;
  345. BSTR FileName;
  346. long LineNr = -1;
  347. // Get the document object
  348. CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc (pDispDoc);
  349. if (! pDoc)
  350. return S_OK;
  351. // Get the document name
  352. if (FAILED (pDoc->get_FullName (&FileName)))
  353. return S_OK;
  354. // Get a selection object dispatch pointer
  355. if (SUCCEEDED (pDoc->get_Selection (&pDispSel)))
  356. {
  357. // Get the selection object
  358. CComQIPtr < ITextSelection, &IID_ITextSelection > pSel (pDispSel);
  359. if (pSel)
  360. // Get the selection line number
  361. pSel->get_CurrentLine (&LineNr);
  362. }
  363. // Open the file in Vim
  364. VimOpenFile (FileName, LineNr);
  365. return S_OK;
  366. }
  367. //
  368. // Here we do the actual processing and communication with Vim
  369. //
  370. // Set the enable state and save to registry
  371. //
  372. static void VimSetEnableState (BOOL bEnableState)
  373. {
  374. g_bEnableVim = bEnableState;
  375. HKEY hAppKey = GetAppKey ("Vim");
  376. if (hAppKey)
  377. {
  378. HKEY hSectionKey = GetSectionKey (hAppKey, "VisVim");
  379. if (hSectionKey)
  380. WriteRegistryInt (hSectionKey, "EnableVim", g_bEnableVim);
  381. RegCloseKey (hAppKey);
  382. }
  383. }
  384. // Open the file 'FileName' in Vim and goto line 'LineNr'
  385. // 'FileName' is expected to contain an absolute DOS path including the drive
  386. // letter.
  387. // 'LineNr' must contain a valid line number or 0, e. g. for a new file
  388. //
  389. static BOOL VimOpenFile (BSTR& FileName, long LineNr)
  390. {
  391. // Get a dispatch id for the SendKeys method of Vim;
  392. // enables connection to Vim if necessary
  393. DISPID DispatchId;
  394. DispatchId = VimGetDispatchId ("SendKeys");
  395. if (! DispatchId)
  396. // OLE error, can't obtain dispatch id
  397. goto OleError;
  398. // Change Vim working directory to where the file is if desired
  399. VimChangeDir (FileName, DispatchId);
  400. // Make Vim open the file
  401. OLECHAR Buf[MAX_OLE_STR];
  402. char VimCmd[MAX_OLE_STR];
  403. char* s;
  404. // Open file
  405. sprintf (VimCmd, ":e %Sn", (char*) FileName);
  406. // Convert all  to / 
  407. for (s = VimCmd; *s; ++s)
  408. if (*s == '\')
  409. *s = '/';
  410. if (! VimOle.Method (DispatchId, "s", TO_OLE_STR_BUF (VimCmd, Buf)))
  411. goto OleError;
  412. if (LineNr > 0)
  413. {
  414. // Goto line
  415. sprintf (VimCmd, ":%dn", LineNr);
  416. if (! VimOle.Method (DispatchId, "s", TO_OLE_STR_BUF (VimCmd, Buf)))
  417. goto OleError;
  418. }
  419. // Make Vim come to the foreground
  420. if (! VimOle.Method ("SetForeground"))
  421. VimOle.ErrDiag ();
  422. // We're done
  423. return true;
  424.     OleError:
  425. // There was an OLE error
  426. // Check if it's the "unknown class string" error
  427. VimErrDiag ();
  428. return false;
  429. }
  430. // Return the dispatch id for the Vim method 'Method'
  431. // Create the Vim OLE object if necessary
  432. // Returns a valid dispatch id or null on error
  433. //
  434. static DISPID VimGetDispatchId (char* Method)
  435. {
  436. // Initialize Vim OLE connection if not already done
  437. if (! VimOle.IsCreated ())
  438. {
  439. if (! VimOle.CreateObject ("Vim.Application"))
  440. return NULL;
  441. }
  442. // Get the dispatch id for the SendKeys method.
  443. // By doing this, we are checking if Vim is still there...
  444. DISPID DispatchId = VimOle.GetDispatchId ("SendKeys");
  445. if (! DispatchId)
  446. {
  447. // We can't get a dispatch id.
  448. // This means that probably Vim has been terminated.
  449. // Don't issue an error message here, instead
  450. // destroy the OLE object and try to connect once more
  451. VimOle.DeleteObject ();
  452. if (! VimOle.CreateObject ("Vim.Application"))
  453. // If this create fails, it's time for an error msg
  454. return NULL;
  455. if (! (DispatchId = VimOle.GetDispatchId ("SendKeys")))
  456. // There is something wrong...
  457. return NULL;
  458. }
  459. return DispatchId;
  460. }
  461. // Output an error message for an OLE error
  462. // Check on the classstring error, which probably means Vim wasn't registered.
  463. //
  464. static void VimErrDiag ()
  465. {
  466. SCODE sc = GetScode (VimOle.GetResult ());
  467. if (sc == CO_E_CLASSSTRING)
  468. {
  469. char Buf[256];
  470. sprintf (Buf, "There is no registered OLE automation server named "
  471.  ""Vim.Application".n"
  472.  "Use the OLE-enabled version of Vim with VisVim and "
  473.  "make sure to register Vim by running "vim -register".");
  474. MessageBox (NULL, Buf, "OLE Error", MB_OK);
  475. }
  476. else
  477. VimOle.ErrDiag ();
  478. }
  479. // Change directory to the directory the file 'FileName' is in or it's parent
  480. // directory according to the setting of the global 'g_ChangeDir':
  481. // 'FileName' is expected to contain an absolute DOS path including the drive
  482. // letter.
  483. // CD_NONE
  484. // CD_SOURCE_PATH
  485. // CD_SOURCE_PARENT
  486. //
  487. static void VimChangeDir (BSTR& FileName, DISPID DispatchId)
  488. {
  489. if (g_ChangeDir != CD_NONE)
  490. {
  491. // Do a :cd first
  492. // Get the path name of the file ("dir/")
  493. CString StrFileName = FileName;
  494. char Drive[_MAX_DRIVE];
  495. char Dir[_MAX_DIR];
  496. _splitpath (StrFileName, Drive, Dir, NULL, NULL);
  497. // Convert to unix path name format
  498. for (char* s = Dir; *s; ++s)
  499. if (*s == '\')
  500. *s = '/';
  501. // Construct the cd command; append /.. if cd to parent
  502. // directory and not in root directory
  503. OLECHAR Buf[MAX_OLE_STR];
  504. char VimCmd[MAX_OLE_STR];
  505. sprintf (VimCmd, ":cd %s%s%sn", Drive, Dir,
  506.  g_ChangeDir == CD_SOURCE_PARENT && Dir[1] ? ".." : "");
  507. VimOle.Method (DispatchId, "s", TO_OLE_STR_BUF (VimCmd, Buf));
  508. }
  509. }
  510. #ifdef _DEBUG
  511. // Print out a debug message
  512. //
  513. static void DebugMsg (char* Msg, char* Arg)
  514. {
  515. char Buf[400];
  516. sprintf (Buf, Msg, Arg);
  517. AfxMessageBox (Buf);
  518. }
  519. #endif