7
|
1 #include "stdafx.h"
|
|
2 #include <comdef.h> // For _bstr_t
|
|
3 #include "VisVim.h"
|
|
4 #include "Commands.h"
|
|
5 #include "OleAut.h"
|
|
6
|
|
7 #ifdef _DEBUG
|
|
8 #define new DEBUG_NEW
|
|
9 #undef THIS_FILE
|
|
10 static char THIS_FILE[] = __FILE__;
|
|
11
|
|
12 #endif
|
|
13
|
|
14
|
|
15 // Change directory before opening file?
|
|
16 #define CD_SOURCE 0 // Cd to source path
|
|
17 #define CD_SOURCE_PARENT 1 // Cd to parent directory of source path
|
|
18 #define CD_NONE 2 // No cd
|
|
19
|
|
20
|
|
21 static BOOL g_bEnableVim = TRUE; // Vim enabled
|
|
22 static BOOL g_bDevStudioEditor = FALSE; // Open file in Dev Studio editor simultaneously
|
|
23 static int g_ChangeDir = CD_NONE; // CD after file open?
|
|
24
|
|
25 static void VimSetEnableState (BOOL bEnableState);
|
|
26 static BOOL VimOpenFile (BSTR& FileName, long LineNr);
|
|
27 static DISPID VimGetDispatchId (COleAutomationControl& VimOle, char* Method);
|
|
28 static void VimErrDiag (COleAutomationControl& VimOle);
|
|
29 static void VimChangeDir (COleAutomationControl& VimOle, DISPID DispatchId, BSTR& FileName);
|
|
30 static void DebugMsg (char* Msg, char* Arg = NULL);
|
|
31
|
|
32
|
|
33 /////////////////////////////////////////////////////////////////////////////
|
|
34 // CCommands
|
|
35
|
|
36 CCommands::CCommands ()
|
|
37 {
|
|
38 // m_pApplication == NULL; M$ Code generation bug!!!
|
|
39 m_pApplication = NULL;
|
|
40 m_pApplicationEventsObj = NULL;
|
|
41 m_pDebuggerEventsObj = NULL;
|
|
42 }
|
|
43
|
|
44 CCommands::~CCommands ()
|
|
45 {
|
|
46 ASSERT (m_pApplication != NULL);
|
|
47 if (m_pApplication)
|
|
48 {
|
|
49 m_pApplication->Release ();
|
|
50 m_pApplication = NULL;
|
|
51 }
|
|
52 }
|
|
53
|
|
54 void CCommands::SetApplicationObject (IApplication * pApplication)
|
|
55 {
|
|
56 // This function assumes pApplication has already been AddRef'd
|
|
57 // for us, which CDSAddIn did in its QueryInterface call
|
|
58 // just before it called us.
|
|
59 m_pApplication = pApplication;
|
|
60 if (! m_pApplication)
|
|
61 return;
|
|
62
|
|
63 // Create Application event handlers
|
|
64 XApplicationEventsObj::CreateInstance (&m_pApplicationEventsObj);
|
|
65 if (! m_pApplicationEventsObj)
|
|
66 {
|
|
67 ReportInternalError ("XApplicationEventsObj::CreateInstance");
|
|
68 return;
|
|
69 }
|
|
70 m_pApplicationEventsObj->AddRef ();
|
|
71 m_pApplicationEventsObj->Connect (m_pApplication);
|
|
72 m_pApplicationEventsObj->m_pCommands = this;
|
|
73
|
|
74 #ifdef NEVER
|
|
75 // Create Debugger event handler
|
|
76 CComPtr < IDispatch > pDebugger;
|
|
77 if (SUCCEEDED (m_pApplication->get_Debugger (&pDebugger))
|
|
78 && pDebugger != NULL)
|
|
79 {
|
|
80 XDebuggerEventsObj::CreateInstance (&m_pDebuggerEventsObj);
|
|
81 m_pDebuggerEventsObj->AddRef ();
|
|
82 m_pDebuggerEventsObj->Connect (pDebugger);
|
|
83 m_pDebuggerEventsObj->m_pCommands = this;
|
|
84 }
|
|
85 #endif
|
|
86
|
|
87 // Get settings from registry HKEY_CURRENT_USER\Software\Vim\VisVim
|
|
88 HKEY hAppKey = GetAppKey ("Vim");
|
|
89 if (hAppKey)
|
|
90 {
|
|
91 HKEY hSectionKey = GetSectionKey (hAppKey, "VisVim");
|
|
92 if (hSectionKey)
|
|
93 {
|
|
94 g_bEnableVim = GetRegistryInt (hSectionKey, "EnableVim",
|
|
95 g_bEnableVim);
|
|
96 g_bDevStudioEditor = GetRegistryInt(hSectionKey,"DevStudioEditor",
|
|
97 g_bDevStudioEditor);
|
|
98 g_ChangeDir = GetRegistryInt (hSectionKey, "ChangeDir",
|
|
99 g_ChangeDir);
|
|
100 RegCloseKey (hSectionKey);
|
|
101 }
|
|
102 RegCloseKey (hAppKey);
|
|
103 }
|
|
104 }
|
|
105
|
|
106 void CCommands::UnadviseFromEvents ()
|
|
107 {
|
|
108 ASSERT (m_pApplicationEventsObj != NULL);
|
|
109 if (m_pApplicationEventsObj)
|
|
110 {
|
|
111 m_pApplicationEventsObj->Disconnect (m_pApplication);
|
|
112 m_pApplicationEventsObj->Release ();
|
|
113 m_pApplicationEventsObj = NULL;
|
|
114 }
|
|
115
|
|
116 #ifdef NEVER
|
|
117 if (m_pDebuggerEventsObj)
|
|
118 {
|
|
119 // Since we were able to connect to the Debugger events, we
|
|
120 // should be able to access the Debugger object again to
|
|
121 // unadvise from its events (thus the VERIFY_OK below--see
|
|
122 // stdafx.h).
|
|
123 CComPtr < IDispatch > pDebugger;
|
|
124 VERIFY_OK (m_pApplication->get_Debugger (&pDebugger));
|
|
125 ASSERT (pDebugger != NULL);
|
|
126 m_pDebuggerEventsObj->Disconnect (pDebugger);
|
|
127 m_pDebuggerEventsObj->Release ();
|
|
128 m_pDebuggerEventsObj = NULL;
|
|
129 }
|
|
130 #endif
|
|
131 }
|
|
132
|
|
133
|
|
134 /////////////////////////////////////////////////////////////////////////////
|
|
135 // Event handlers
|
|
136
|
|
137 // Application events
|
|
138
|
|
139 HRESULT CCommands::XApplicationEvents::BeforeBuildStart ()
|
|
140 {
|
|
141 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
142 return S_OK;
|
|
143 }
|
|
144
|
|
145 HRESULT CCommands::XApplicationEvents::BuildFinish (long nNumErrors, long nNumWarnings)
|
|
146 {
|
|
147 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
148 return S_OK;
|
|
149 }
|
|
150
|
|
151 HRESULT CCommands::XApplicationEvents::BeforeApplicationShutDown ()
|
|
152 {
|
|
153 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
154 return S_OK;
|
|
155 }
|
|
156
|
|
157 // The open document event handle is the place where the real interface work
|
|
158 // is done.
|
|
159 // Vim gets called from here.
|
|
160 //
|
|
161 HRESULT CCommands::XApplicationEvents::DocumentOpen (IDispatch * theDocument)
|
|
162 {
|
|
163 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
164
|
|
165 if (! g_bEnableVim)
|
|
166 // Vim not enabled or empty command line entered
|
|
167 return S_OK;
|
|
168
|
|
169 // First get the current file name and line number
|
|
170
|
|
171 // Get the document object
|
|
172 CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc (theDocument);
|
|
173 if (! pDoc)
|
|
174 return S_OK;
|
|
175
|
|
176 BSTR FileName;
|
|
177 long LineNr = -1;
|
|
178
|
|
179 // Get the document name
|
|
180 if (FAILED (pDoc->get_FullName (&FileName)))
|
|
181 return S_OK;
|
|
182
|
|
183 LPDISPATCH pDispSel;
|
|
184
|
|
185 // Get a selection object dispatch pointer
|
|
186 if (SUCCEEDED (pDoc->get_Selection (&pDispSel)))
|
|
187 {
|
|
188 // Get the selection object
|
|
189 CComQIPtr < ITextSelection, &IID_ITextSelection > pSel (pDispSel);
|
|
190
|
|
191 if (pSel)
|
|
192 // Get the selection line number
|
|
193 pSel->get_CurrentLine (&LineNr);
|
|
194
|
|
195 pDispSel->Release ();
|
|
196 }
|
|
197
|
|
198 // Open the file in Vim and position to the current line
|
|
199 if (VimOpenFile (FileName, LineNr))
|
|
200 {
|
|
201 if (! g_bDevStudioEditor)
|
|
202 {
|
|
203 // Close the document in developer studio
|
|
204 CComVariant vSaveChanges = dsSaveChangesPrompt;
|
|
205 DsSaveStatus Saved;
|
|
206
|
|
207 pDoc->Close (vSaveChanges, &Saved);
|
|
208 }
|
|
209 }
|
|
210
|
|
211 // We're done here
|
|
212 SysFreeString (FileName);
|
|
213 return S_OK;
|
|
214 }
|
|
215
|
|
216 HRESULT CCommands::XApplicationEvents::BeforeDocumentClose (IDispatch * theDocument)
|
|
217 {
|
|
218 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
219 return S_OK;
|
|
220 }
|
|
221
|
|
222 HRESULT CCommands::XApplicationEvents::DocumentSave (IDispatch * theDocument)
|
|
223 {
|
|
224 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
225 return S_OK;
|
|
226 }
|
|
227
|
|
228 HRESULT CCommands::XApplicationEvents::NewDocument (IDispatch * theDocument)
|
|
229 {
|
|
230 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
231
|
|
232 if (! g_bEnableVim)
|
|
233 // Vim not enabled or empty command line entered
|
|
234 return S_OK;
|
|
235
|
|
236 // First get the current file name and line number
|
|
237
|
|
238 CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc (theDocument);
|
|
239 if (! pDoc)
|
|
240 return S_OK;
|
|
241
|
|
242 BSTR FileName;
|
|
243 HRESULT hr;
|
|
244
|
|
245 hr = pDoc->get_FullName (&FileName);
|
|
246 if (FAILED (hr))
|
|
247 return S_OK;
|
|
248
|
|
249 // Open the file in Vim and position to the current line
|
|
250 if (VimOpenFile (FileName, 0))
|
|
251 {
|
|
252 if (! g_bDevStudioEditor)
|
|
253 {
|
|
254 // Close the document in developer studio
|
|
255 CComVariant vSaveChanges = dsSaveChangesPrompt;
|
|
256 DsSaveStatus Saved;
|
|
257
|
|
258 pDoc->Close (vSaveChanges, &Saved);
|
|
259 }
|
|
260 }
|
|
261
|
|
262 SysFreeString (FileName);
|
|
263 return S_OK;
|
|
264 }
|
|
265
|
|
266 HRESULT CCommands::XApplicationEvents::WindowActivate (IDispatch * theWindow)
|
|
267 {
|
|
268 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
269 return S_OK;
|
|
270 }
|
|
271
|
|
272 HRESULT CCommands::XApplicationEvents::WindowDeactivate (IDispatch * theWindow)
|
|
273 {
|
|
274 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
275 return S_OK;
|
|
276 }
|
|
277
|
|
278 HRESULT CCommands::XApplicationEvents::WorkspaceOpen ()
|
|
279 {
|
|
280 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
281 return S_OK;
|
|
282 }
|
|
283
|
|
284 HRESULT CCommands::XApplicationEvents::WorkspaceClose ()
|
|
285 {
|
|
286 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
287 return S_OK;
|
|
288 }
|
|
289
|
|
290 HRESULT CCommands::XApplicationEvents::NewWorkspace ()
|
|
291 {
|
|
292 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
293 return S_OK;
|
|
294 }
|
|
295
|
|
296 // Debugger event
|
|
297
|
|
298 HRESULT CCommands::XDebuggerEvents::BreakpointHit (IDispatch * pBreakpoint)
|
|
299 {
|
|
300 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
301 return S_OK;
|
|
302 }
|
|
303
|
|
304
|
|
305 /////////////////////////////////////////////////////////////////////////////
|
|
306 // VisVim dialog
|
|
307
|
|
308 class CMainDialog : public CDialog
|
|
309 {
|
|
310 public:
|
|
311 CMainDialog (CWnd * pParent = NULL); // Standard constructor
|
|
312
|
|
313 //{{AFX_DATA(CMainDialog)
|
|
314 enum { IDD = IDD_ADDINMAIN };
|
|
315 int m_ChangeDir;
|
|
316 BOOL m_bDevStudioEditor;
|
|
317 //}}AFX_DATA
|
|
318
|
|
319 //{{AFX_VIRTUAL(CMainDialog)
|
|
320 protected:
|
|
321 virtual void DoDataExchange (CDataExchange * pDX); // DDX/DDV support
|
|
322 //}}AFX_VIRTUAL
|
|
323
|
|
324 protected:
|
|
325 //{{AFX_MSG(CMainDialog)
|
|
326 afx_msg void OnEnable();
|
|
327 afx_msg void OnDisable();
|
|
328 //}}AFX_MSG
|
|
329 DECLARE_MESSAGE_MAP ()
|
|
330 };
|
|
331
|
|
332 CMainDialog::CMainDialog (CWnd * pParent /* =NULL */ )
|
|
333 : CDialog (CMainDialog::IDD, pParent)
|
|
334 {
|
|
335 //{{AFX_DATA_INIT(CMainDialog)
|
|
336 m_ChangeDir = -1;
|
|
337 m_bDevStudioEditor = FALSE;
|
|
338 //}}AFX_DATA_INIT
|
|
339 }
|
|
340
|
|
341 void CMainDialog::DoDataExchange (CDataExchange * pDX)
|
|
342 {
|
|
343 CDialog::DoDataExchange (pDX);
|
|
344 //{{AFX_DATA_MAP(CMainDialog)
|
|
345 DDX_Radio(pDX, IDC_CD_SOURCE_PATH, m_ChangeDir);
|
|
346 DDX_Check (pDX, IDC_DEVSTUDIO_EDITOR, m_bDevStudioEditor);
|
|
347 //}}AFX_DATA_MAP
|
|
348 }
|
|
349
|
|
350 BEGIN_MESSAGE_MAP (CMainDialog, CDialog)
|
|
351 //{{AFX_MSG_MAP(CMainDialog)
|
|
352 //}}AFX_MSG_MAP
|
|
353 END_MESSAGE_MAP ()
|
|
354
|
|
355
|
|
356 /////////////////////////////////////////////////////////////////////////////
|
|
357 // CCommands methods
|
|
358
|
|
359 STDMETHODIMP CCommands::VisVimDialog ()
|
|
360 {
|
|
361 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
362
|
|
363 // Use m_pApplication to access the Developer Studio Application
|
|
364 // object,
|
|
365 // and VERIFY_OK to see error strings in DEBUG builds of your add-in
|
|
366 // (see stdafx.h)
|
|
367
|
|
368 VERIFY_OK (m_pApplication->EnableModeless (VARIANT_FALSE));
|
|
369
|
|
370 CMainDialog Dlg;
|
|
371
|
|
372 Dlg.m_bDevStudioEditor = g_bDevStudioEditor;
|
|
373 Dlg.m_ChangeDir = g_ChangeDir;
|
|
374 if (Dlg.DoModal () == IDOK)
|
|
375 {
|
|
376 g_bDevStudioEditor = Dlg.m_bDevStudioEditor;
|
|
377 g_ChangeDir = Dlg.m_ChangeDir;
|
|
378
|
|
379 // Save settings to registry HKEY_CURRENT_USER\Software\Vim\VisVim
|
|
380 HKEY hAppKey = GetAppKey ("Vim");
|
|
381 if (hAppKey)
|
|
382 {
|
|
383 HKEY hSectionKey = GetSectionKey (hAppKey, "VisVim");
|
|
384 if (hSectionKey)
|
|
385 {
|
|
386 WriteRegistryInt (hSectionKey, "DevStudioEditor",
|
|
387 g_bDevStudioEditor);
|
|
388 WriteRegistryInt (hSectionKey, "ChangeDir", g_ChangeDir);
|
|
389 RegCloseKey (hSectionKey);
|
|
390 }
|
|
391 RegCloseKey (hAppKey);
|
|
392 }
|
|
393 }
|
|
394
|
|
395 VERIFY_OK (m_pApplication->EnableModeless (VARIANT_TRUE));
|
|
396 return S_OK;
|
|
397 }
|
|
398
|
|
399 STDMETHODIMP CCommands::VisVimEnable ()
|
|
400 {
|
|
401 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
402 VimSetEnableState (true);
|
|
403 return S_OK;
|
|
404 }
|
|
405
|
|
406 STDMETHODIMP CCommands::VisVimDisable ()
|
|
407 {
|
|
408 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
409 VimSetEnableState (false);
|
|
410 return S_OK;
|
|
411 }
|
|
412
|
|
413 STDMETHODIMP CCommands::VisVimToggle ()
|
|
414 {
|
|
415 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
416 VimSetEnableState (! g_bEnableVim);
|
|
417 return S_OK;
|
|
418 }
|
|
419
|
|
420 STDMETHODIMP CCommands::VisVimLoad ()
|
|
421 {
|
|
422 AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
423
|
|
424 // Use m_pApplication to access the Developer Studio Application object,
|
|
425 // and VERIFY_OK to see error strings in DEBUG builds of your add-in
|
|
426 // (see stdafx.h)
|
|
427
|
|
428 CComBSTR bStr;
|
|
429 // Define dispatch pointers for document and selection objects
|
|
430 CComPtr < IDispatch > pDispDoc, pDispSel;
|
|
431
|
|
432 // Get a document object dispatch pointer
|
|
433 VERIFY_OK (m_pApplication->get_ActiveDocument (&pDispDoc));
|
|
434 if (! pDispDoc)
|
|
435 return S_OK;
|
|
436
|
|
437 BSTR FileName;
|
|
438 long LineNr = -1;
|
|
439
|
|
440 // Get the document object
|
|
441 CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc (pDispDoc);
|
|
442
|
|
443 if (! pDoc)
|
|
444 return S_OK;
|
|
445
|
|
446 // Get the document name
|
|
447 if (FAILED (pDoc->get_FullName (&FileName)))
|
|
448 return S_OK;
|
|
449
|
|
450 // Get a selection object dispatch pointer
|
|
451 if (SUCCEEDED (pDoc->get_Selection (&pDispSel)))
|
|
452 {
|
|
453 // Get the selection object
|
|
454 CComQIPtr < ITextSelection, &IID_ITextSelection > pSel (pDispSel);
|
|
455
|
|
456 if (pSel)
|
|
457 // Get the selection line number
|
|
458 pSel->get_CurrentLine (&LineNr);
|
|
459 }
|
|
460
|
|
461 // Open the file in Vim
|
|
462 VimOpenFile (FileName, LineNr);
|
|
463
|
|
464 SysFreeString (FileName);
|
|
465 return S_OK;
|
|
466 }
|
|
467
|
|
468
|
|
469 //
|
|
470 // Here we do the actual processing and communication with Vim
|
|
471 //
|
|
472
|
|
473 // Set the enable state and save to registry
|
|
474 //
|
|
475 static void VimSetEnableState (BOOL bEnableState)
|
|
476 {
|
|
477 g_bEnableVim = bEnableState;
|
|
478 HKEY hAppKey = GetAppKey ("Vim");
|
|
479 if (hAppKey)
|
|
480 {
|
|
481 HKEY hSectionKey = GetSectionKey (hAppKey, "VisVim");
|
|
482 if (hSectionKey)
|
|
483 WriteRegistryInt (hSectionKey, "EnableVim", g_bEnableVim);
|
|
484 RegCloseKey (hAppKey);
|
|
485 }
|
|
486 }
|
|
487
|
|
488 // Open the file 'FileName' in Vim and goto line 'LineNr'
|
|
489 // 'FileName' is expected to contain an absolute DOS path including the drive
|
|
490 // letter.
|
|
491 // 'LineNr' must contain a valid line number or 0, e. g. for a new file
|
|
492 //
|
|
493 static BOOL VimOpenFile (BSTR& FileName, long LineNr)
|
|
494 {
|
|
495
|
|
496 // OLE automation object for com. with Vim
|
|
497 // When the object goes out of scope, it's desctructor destroys the OLE connection;
|
|
498 // This is imortant to avoid blocking the object
|
|
499 // (in this memory corruption would be likely when terminating Vim
|
|
500 // while still running DevStudio).
|
|
501 // So keep this object local!
|
|
502 COleAutomationControl VimOle;
|
|
503
|
|
504 // :cd D:/Src2/VisVim/
|
|
505 //
|
|
506 // Get a dispatch id for the SendKeys method of Vim;
|
|
507 // enables connection to Vim if necessary
|
|
508 DISPID DispatchId;
|
|
509 DispatchId = VimGetDispatchId (VimOle, "SendKeys");
|
|
510 if (! DispatchId)
|
|
511 // OLE error, can't obtain dispatch id
|
|
512 goto OleError;
|
|
513
|
|
514 OLECHAR Buf[MAX_OLE_STR];
|
|
515 char FileNameTmp[MAX_OLE_STR];
|
|
516 char VimCmd[MAX_OLE_STR];
|
|
517 char *s, *p;
|
|
518
|
|
519 // Prepend CTRL-\ CTRL-N to exit insert mode
|
|
520 VimCmd[0] = 0x1c;
|
|
521 VimCmd[1] = 0x0e;
|
|
522 VimCmd[2] = 0;
|
|
523
|
|
524 #ifdef SINGLE_WINDOW
|
|
525 // Update the current file in Vim if it has been modified.
|
|
526 // Disabled, because it could write the file when you don't want to.
|
|
527 sprintf (VimCmd + 2, ":up\n");
|
|
528 #endif
|
|
529 if (! VimOle.Method (DispatchId, "s", TO_OLE_STR_BUF (VimCmd, Buf)))
|
|
530 goto OleError;
|
|
531
|
|
532 // Change Vim working directory to where the file is if desired
|
|
533 if (g_ChangeDir != CD_NONE)
|
|
534 VimChangeDir (VimOle, DispatchId, FileName);
|
|
535
|
|
536 // Make Vim open the file.
|
|
537 // In the filename convert all \ to /, put a \ before a space.
|
|
538 sprintf(VimCmd, ":drop ");
|
|
539 sprintf(FileNameTmp, "%S", (char *)FileName);
|
|
540 s = VimCmd + 6;
|
|
541 for (p = FileNameTmp; *p != '\0' && s < FileNameTmp + MAX_OLE_STR - 4;
|
|
542 ++p)
|
|
543 if (*p == '\\')
|
|
544 *s++ = '/';
|
|
545 else
|
|
546 {
|
|
547 if (*p == ' ')
|
|
548 *s++ = '\\';
|
|
549 *s++ = *p;
|
|
550 }
|
|
551 *s++ = '\n';
|
|
552 *s = '\0';
|
|
553
|
|
554 if (! VimOle.Method (DispatchId, "s", TO_OLE_STR_BUF (VimCmd, Buf)))
|
|
555 goto OleError;
|
|
556
|
|
557 if (LineNr > 0)
|
|
558 {
|
|
559 // Goto line
|
|
560 sprintf (VimCmd, ":%d\n", LineNr);
|
|
561 if (! VimOle.Method (DispatchId, "s", TO_OLE_STR_BUF (VimCmd, Buf)))
|
|
562 goto OleError;
|
|
563 }
|
|
564
|
|
565 // Make Vim come to the foreground
|
|
566 if (! VimOle.Method ("SetForeground"))
|
|
567 VimOle.ErrDiag ();
|
|
568
|
|
569 // We're done
|
|
570 return true;
|
|
571
|
|
572 OleError:
|
|
573 // There was an OLE error
|
|
574 // Check if it's the "unknown class string" error
|
|
575 VimErrDiag (VimOle);
|
|
576 return false;
|
|
577 }
|
|
578
|
|
579 // Return the dispatch id for the Vim method 'Method'
|
|
580 // Create the Vim OLE object if necessary
|
|
581 // Returns a valid dispatch id or null on error
|
|
582 //
|
|
583 static DISPID VimGetDispatchId (COleAutomationControl& VimOle, char* Method)
|
|
584 {
|
|
585 // Initialize Vim OLE connection if not already done
|
|
586 if (! VimOle.IsCreated ())
|
|
587 {
|
|
588 if (! VimOle.CreateObject ("Vim.Application"))
|
|
589 return NULL;
|
|
590 }
|
|
591
|
|
592 // Get the dispatch id for the SendKeys method.
|
|
593 // By doing this, we are checking if Vim is still there...
|
|
594 DISPID DispatchId = VimOle.GetDispatchId ("SendKeys");
|
|
595 if (! DispatchId)
|
|
596 {
|
|
597 // We can't get a dispatch id.
|
|
598 // This means that probably Vim has been terminated.
|
|
599 // Don't issue an error message here, instead
|
|
600 // destroy the OLE object and try to connect once more
|
|
601 //
|
|
602 // In fact, this should never happen, because the OLE aut. object
|
|
603 // should not be kept long enough to allow the user to terminate Vim
|
|
604 // to avoid memory corruption (why the heck is there no system garbage
|
|
605 // collection for those damned OLE memory chunks???).
|
|
606 VimOle.DeleteObject ();
|
|
607 if (! VimOle.CreateObject ("Vim.Application"))
|
|
608 // If this create fails, it's time for an error msg
|
|
609 return NULL;
|
|
610
|
|
611 if (! (DispatchId = VimOle.GetDispatchId ("SendKeys")))
|
|
612 // There is something wrong...
|
|
613 return NULL;
|
|
614 }
|
|
615
|
|
616 return DispatchId;
|
|
617 }
|
|
618
|
|
619 // Output an error message for an OLE error
|
|
620 // Check on the classstring error, which probably means Vim wasn't registered.
|
|
621 //
|
|
622 static void VimErrDiag (COleAutomationControl& VimOle)
|
|
623 {
|
|
624 SCODE sc = GetScode (VimOle.GetResult ());
|
|
625 if (sc == CO_E_CLASSSTRING)
|
|
626 {
|
|
627 char Buf[256];
|
|
628 sprintf (Buf, "There is no registered OLE automation server named "
|
|
629 "\"Vim.Application\".\n"
|
|
630 "Use the OLE-enabled version of Vim with VisVim and "
|
|
631 "make sure to register Vim by running \"vim -register\".");
|
|
632 MessageBox (NULL, Buf, "OLE Error", MB_OK);
|
|
633 }
|
|
634 else
|
|
635 VimOle.ErrDiag ();
|
|
636 }
|
|
637
|
|
638 // Change directory to the directory the file 'FileName' is in or it's parent
|
|
639 // directory according to the setting of the global 'g_ChangeDir':
|
|
640 // 'FileName' is expected to contain an absolute DOS path including the drive
|
|
641 // letter.
|
|
642 // CD_NONE
|
|
643 // CD_SOURCE_PATH
|
|
644 // CD_SOURCE_PARENT
|
|
645 //
|
|
646 static void VimChangeDir (COleAutomationControl& VimOle, DISPID DispatchId, BSTR& FileName)
|
|
647 {
|
|
648 // Do a :cd first
|
|
649
|
|
650 // Get the path name of the file ("dir/")
|
|
651 CString StrFileName = FileName;
|
|
652 char Drive[_MAX_DRIVE];
|
|
653 char Dir[_MAX_DIR];
|
|
654 char DirUnix[_MAX_DIR * 2];
|
|
655 char *s, *t;
|
|
656
|
|
657 _splitpath (StrFileName, Drive, Dir, NULL, NULL);
|
|
658
|
|
659 // Convert to Unix path name format, escape spaces.
|
|
660 t = DirUnix;
|
|
661 for (s = Dir; *s; ++s)
|
|
662 if (*s == '\\')
|
|
663 *t++ = '/';
|
|
664 else
|
|
665 {
|
|
666 if (*s == ' ')
|
|
667 *t++ = '\\';
|
|
668 *t++ = *s;
|
|
669 }
|
|
670 *t = '\0';
|
|
671
|
|
672
|
|
673 // Construct the cd command; append /.. if cd to parent
|
|
674 // directory and not in root directory
|
|
675 OLECHAR Buf[MAX_OLE_STR];
|
|
676 char VimCmd[MAX_OLE_STR];
|
|
677
|
|
678 sprintf (VimCmd, ":cd %s%s%s\n", Drive, DirUnix,
|
|
679 g_ChangeDir == CD_SOURCE_PARENT && DirUnix[1] ? ".." : "");
|
|
680 VimOle.Method (DispatchId, "s", TO_OLE_STR_BUF (VimCmd, Buf));
|
|
681 }
|
|
682
|
|
683 #ifdef _DEBUG
|
|
684 // Print out a debug message
|
|
685 //
|
|
686 static void DebugMsg (char* Msg, char* Arg)
|
|
687 {
|
|
688 char Buf[400];
|
|
689 sprintf (Buf, Msg, Arg);
|
|
690 AfxMessageBox (Buf);
|
|
691 }
|
|
692 #endif
|
|
693
|