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