Ultimate MS Outlook Editor

At my work, I’m required to use Microsoft Outlook for exchanging email with my co-workers. At home, I use Mutt on FreeBSD, and have grown to really love the lightning-fast responsiveness, immunity to virusses, and easy scriptability of this tiny text-based mail reader.


At my work, I’m required to use Microsoft Outlook for exchanging email with my co-workers. At home, I use Mutt on FreeBSD, and have grown to really love the lightning-fast responsiveness, immunity to virusses, and easy scriptability of this tiny text-based mail reader.

I’m going to tell you one solution, just so I can tell you another one πŸ™‚

It’s possible to use Mutt with Microsoft Exchange:

  • Set up IMAP on your Exchange server. This was already done here.
  • Install a copy of Cygwin, including Python.
  • Either set up Mutt to access IMAP on Exchange directly, or do what I prefer to do: download and set up offlineimap. This IMAP-to-Maildir synchronization utility is excellent.
    1. First, you need to run the “rebaseall” utility so that Python doesn’t dump with traceback when you try to run offlineimap. You can’t rebaseall if you’re trying to do it from an rxvt window — you need to be using the cmd-based Cygwin shell for it to finish without an error.
    2. Then you need make sure your .offlineimaprc file specifies “Curses.Blinkenlights” as the first available interface — the TK interface, on Win32, just hangs.
  • You can’t use offlineimap on a non-managed Cygwin mount. The reason is that the Maildir specification uses the “:” character, which is a big no-no in Windows-land. The solution is to use this command:
     $ mount -f -s -b -o managed "d:/tmp/mail" "/home/of/mail" 

    substituting the windows-path directory you wish to use for mail for the “d:/tmp/mail” above, and the mount point you wish to put it on instead of “/home/of/mail”.

  • Once you have IMAP-to-Maildir synchronization going to your local PC, then you’re good to go with offline IMAP stuff and Mutt. Follow the usual directions for configuring Mutt to use the Maildir you’ve set up, paying particular attention to choice of outbound mailer (probably ssmtp).

Obviously, though I’m a big fan of Mutt, that seemed like a lot of work. Lucky me, I chanced across a script that, with minor modifications, gave me the primary thing I loved about using Mutt: being able to use vim as my text editor. I’m just much faster using that than any other editor, and it’s ubiquitous on UNIX systems, either in a more-primitive incarnation of “vi”, or in some version.

So I installed Python and the Win32 extensions for Python, then linked this script on my quickbar in Windows, conveniently right next to Outlook:

 #!/bin/env python ''' outlook.pyw (OutLook editor launcher) -- allows one to edit an open e-mail  mesg from Outlook using Emacs or *Vi* rather than "Notepad--". :-)  NOTE: requires Python 1.6 and newer (use of string methods)

created by John Klassa (klassa at employees.org) on 2001 May 29 updated by Wesley Chun (cyberweb at rocketmail.com) on 2002 Feb 28

$Id: outlook.pyw,v 0.2 2002/08/28 18:04:06 wesc Exp wesc $ '''

from os import spawnv, P_WAIT, unlink from tempfile import mktemp from Tkinter import Tk, Button, Frame, Label from Tkconstants import * from win32com.client import Dispatch

def launch(): '''launch() spawns your favorite editor to edit the Outlook compose   window (either new or reply), then returns that data to Outlook...  change the 'ed' variable to switch editors.'''

# Get a handle to Outlook. o = Dispatch("Outlook.Application")

# Work our way down to the reply (a "MailItem"). insp = o.ActiveInspector() if insp == None: return item = insp.CurrentItem if item == None: return

# Grab the message body in the reply. body = item.Body

# Write the body... need to "encode" the string because Outlook uses # Unicode with bunch of unprintables (ASCII chars > 128). Also, since # we are going from DOS2UNIX2DOS, we have the \r\n vs \n issue, re- # sulting in those fabulous ^M characters. A persistent, bound-to-a- # key Emacs macro takes care of that nicely, but the solution imple- # mented here is to just wipe the '\r's now, then add them back when # we reread this file back before returning the body to Outlook. tmp = mktemp() # generate a unique tmp filename fh = open(tmp, "w") fh.write(body.encode('ascii', 'ignore').replace('\r\n', '\n')) fh.close()

# Launch editor to edit the file (should make this configurable). #ed = r"d:\emacs-20.7\bin\emacs" # emacs editor binary ed = r"c:\vim\vim62\gvim.exe" # *vi* editor binary spawnv(P_WAIT, ed, [ed, tmp])

# Read edited file back into memory, restore '\r's, and kill tmp file. fh = open(tmp) body = fh.read().replace('\n', '\r\n') fh.close() unlink(tmp)

# Store it as the body of the reply. Note that we are merely # sending this data back to Outlook -- it does not prevent MS from # mucking with your message. For example, it may add your signature # again, or it may remove newlines. MS software... what can you do? item.Body = body

# Create the Tk(inter) GUI app with the appropriate label and buttons. if __name__=='__main__': tk = Tk() f = Frame(tk, relief=RIDGE, borderwidth=2).pack() Label(f, text="Outlook Edit Launcher v0.2").pack() Button(f, text="Edit", fg='blue', command=launch).pack(fill=BOTH) Button(f, text="Quit", fg='red', command=tk.quit).pack(fill=BOTH) tk.mainloop()

I now click Outlook, then click my outlook.py script. I minimize the annoying black cmd window that comes up (anybody know how to get rid of this?), and I now have a little Python/TK window with a convenient “edit” button on it. When I compose a message in LookOut, I click this “edit” button, and up pops gvim 6.2, ready for me to type the message. When I’m done typing it, I just write-quit out of gvim, and the text pops up in my Outlook compose window.

Convenient! Well, for a UNIX-geek at least.

Anyway, I’m still torn. Do I really need to use Outlook here? Realistically, I have maybe one meeting a week that I need to keep track of, and that’s easily done in my Palm. Maybe I should just use Mutt in Cygwin on a managed mount? Who knows, but both are valid choices. And in a world where MS wants you to only use MS products, and those products are funkily generic and slow, it’s nice to have choices.

67 thoughts on “Ultimate MS Outlook Editor”

  1. That’s so 1990s

    Matt, c’mon man, who isn’t using Mutt in Cygwin on a manager mount these days? Get with the times dude.

    Here’s a question: say a small firm is setting up an office for 5 employees. The set up is going to be a server-client network (no shared apps). Do you recommend going with a MS Windows or Mac OS system? Are there choices in buying out-of-the-box or configurable servers and workstations that can house popular software, don’t cost an arm and a leg and give choice?

    Wondering if you can go out and buy the computing pieces and then run a freeware OS and pick and choose your components…and if it makes compatibility and cost sense…

    BTW — I’m not trying to diminish the genius of your original post, it’s just that I don’t understand it. πŸ™‚

    1. Well, you brought up a very g

      Well, you brought up a very general topic. So I’m going to give generic advice for setting up a small office network on the cheap.

      The first thing to realize is that “freeware”, or “open source” is only free if your time is worth nothing. If you know nothing about what you’re doing, you’ll be paying a consultant to do it right regardless of what platform you choose. You can do it “on the cheap” on your own, but you’ll be learning a lot as you do so πŸ™‚

      There are several basic components to any office setup, some of which may be optional depending on your situation and type of business:

        Infrastructure:

      • Electronic Mail System
      • Shared calendaring system
      • Telephone (PBX) System
      • Fax system
      • File-Sharing
      • Web presence (lots to this, depending on what you wish to do)
      • Switch, router, and firewall
      • Documentation management
      • Customer Relationship Management
      • Web browser
      • Email reader
      • Office suite
      • Domain-specific applications (Photoshop for the artist, Lightwave for the modeler, etc.)
      • Accounting package(s)
      • Project management

      With all of these, you can pick-and-choose where you want technology to assist you, and where you wish to do things by hand. You can also choose to outsource much of it, pick a closed-source application, or pick an open-source app that you can modify to suit your needs.

      My default rule in new buildouts is to use open-source (“free” or “libre”) software wherever possible. I can make that default choice without additional justification if it’s capable of meeting the needs of the client. If I must choose a proprietary application (such as Microsoft Exchange), I then need to give justifications for that choice.

      For desktops, if it is feasible, I would choose GNU/Linux. Which distribution is probably irrelevant, but for ease of updating, and due to some idealistic concerns regarding free software, I would probably pick Debian.

      If I had to choose between MacOSX and Windows, I would pick MacOSX in a heartbeat. At its core, it is a UNIX-based operating system. It is also less popular than MS Windows, and in this age of monoculture computer virusses, that alone is an excellent justification. It has all the domain-specific apps people need in a creative workshop, runs on standardized hardware that, while expensive, has a much lower failure rate than commodity PCs, and has a definite sex appeal πŸ™‚

      On the server side, I’d buy one really fast, capable dual-processor PC with 2 GB+ RAM, a 64-bit processor (AMD or Intel), running GNU/Linux. Possibly, if you want to stay an all-Mac shop, a Mac rackable G5 server would be a good choice for this, too. Run all the critical services on this one box, and maybe set up a second one with an identical configuration so you have a backup in case the primary fails.

      I could write an essay about this, so I’ll stop now.


      Matthew P. Barnson

  2. The MS Way

    Matt,

    Try this:

    1. Copy the following into a file and name it ‘launchvim.vbs’
       Option Explicit
      
      Private Sub launch()
      
      Const TemporaryFolder = 2
      
      Dim ws, ol, insp, item, body, fso, tempfile, tfolder, tname, tfile
      
      Set ol = CreateObject("Outlook.Application")
      
      Set insp = ol.ActiveInspector If insp Is Nothing then Exit Sub End if Set item = insp.CurrentItem If item Is Nothing then Exit Sub End if
      
      body = CStr(item.Body)
      
      Set fso = CreateObject("Scripting.FileSystemObject") Set tfolder = fso.GetSpecialFolder(TemporaryFolder) tname = fso.GetTempName Set tfile = tfolder.CreateTextFile(tname) tfile.Write( Replace( body, Chr(13) & Chr(10), Chr(10) ) ) tfile.Close()
      
      Set ws = WScript.CreateObject("WScript.Shell") Wsh.Echo( "c:\vim\vim62\gvim.exe " & tfolder.Path & "\" & tname ) ws.Run "c:\vim\vim62\gvim.exe " & tfolder.Path & "\" & tname ,4, true
      
      Set tfile = fso.OpenTextFile(tfolder.Path & "\" & tname, 1 ) item.body = Replace( tfile.ReadAll, Chr(10), Chr(13) & Chr(10) ) tfile.close()
      
      fso.DeleteFile( tfolder.Path & "\" & tname )
      
      End Sub
      
      Call launch()
      
      
    2. In Outlook, Go To Tools->Macros->VB Editor (Make sure your Security settings for Outlook are set to Medium)
    3. Add a new module, and paste this into it
       Sub LaunchVIM()
      
      Dim windir As String
      
      windir = Environ("WinDir")
      
      Shell (windir & "\system32\cscript.exe " & windir & "\system32\launchvim.vbs")
      
      End Sub
      
      
    4. Open a new Outlook mail message
    5. Click View->Toolbars->Customize
    6. Under the Commands tab, Select Macros on the left, and drag the macro you just created to the Outlook toolbar in your newly opened mail dialog.

    Voila! Now you can launch vim from the Outlook toolbar!

    EDIT by matthew: cleaned up formatting for slightly easier readability.

    1. SWEET!

      Pretty sweet, dude. I now have a “Project1.LaunchVIM” button on my toolbar. Unfortunately, setting security to Medium violates our corporate security policy. So I reset it back to High after installing the button, and the button continues to work fine.

      So, for future security-conscious readers, set to Medium to install the script, then back to High and your script will continue to run without problems. How long did it take you to whip that out, Weed? I know next to nothing about Visual Basic, but it is visually much cleaner (and easier to install) than a separate Python window with an “EDIT” button πŸ™‚


      Matthew P. Barnson

      1. Uh-oh

        Matt

        The security feature of the macros takes place after the next restart, so more than likely the next time you open Outlook your button won’t work.

        I’ll look into signing the code so it works with High. You may have to install my company’s cert authority tho, ’cause I’m not paying Veri$ign to sign it.

        As for VBScript, it’s not hard. http://msdn.microsoft.com/ has a bunch of information on it, but, as with all Microsoft, you have to learn how to search for it.

        Look here: http://www.microsoft.com/technet/prodtechnol/office/office2000/maintain/security/o2ksec.mspx

        1. Roger that

          Yeah, just fired up Outlook again, and the button does nothing. Durn.

          For now, I’m continuing to use my offlineimap/Mutt/Cygwin solution. It works very well to keep the folders synchronized, but stuff like seeing other users’ folders just doesn’t work at all, so I have to keep Outlook around.


          Matthew P. Barnson

    2. Restoring the text format

      Hi Weed, this script works well for me. It is very useful and productive for Vim fans like me! I am looking for one more feature. Right now, when I return back from my Vim session the file type is set to ‘rich text’ irrespective of the state before editing in vim. Is it possible to restore the text format. If that is not possible, how to set it to ‘plain text’ which makes more sense when we edit using vim (the nice indentations will show up the same way in outlook)

      Thanks –Mahesh N

      1. Mail format

        Unfortunately, this is a change you have to make in Outlook, not in your configuration for using VIM.

        In Outlook, go to the Tools menu and select Options. Click the “Mail Format” tab, and change the “Compose in this message format” from “Rich Text” to “Plain Text”. The problem is then solved, and you have your nice indentation and mail config.

        I’m in this same boat again today, since I’m working a new job where they use Outlook exclusively. And, in this case, Outlook is extremely tied-in to their basic management systems, so using Mutt to the exclusion out Outlook is no longer an option (sigh)… So I came back to this page this morning to remember how I did it!

        Anyway, changing those options will do the trick. The one annoyance left is that with the latest patches to Outlook, every time I launch this I get a prompt saying “A program is trying to access your Address Book”, and I have to click “Yes” to allow it to run. It’s only one extra click, but I do this in part for convenience. I’ve been digging around trying to figure out how to turn this off for a signed, truested vbscript, but no luck.

        However, the tips above on signing your own code work great to make it work appropriately, with the exception of that annoying pop-up every time I compose a mail message.

        The price I pay for being a UNIX geek, I guess… maybe I’ll go back to using Mutt on Cygwin for email, and just use LookOut for calendars, contacts, etc.


        Matthew P. Barnson

  3. Change the .py to .pyw

    Getting rid of the python console is easy – change the file extension. The app will work and the console will not be spawned.

    1. .py to .pyw

      Changing the file extension to .pyw worked like a champ for getting rid of the console window; thanks for the tip!


      Matthew P. Barnson

      1. Alternatively

        Since Windows runs programs based on extension and not MIME-type, setting the first line in the script to:

        #!c:\python24\pythonw.exe 

        will do the same thing.

        Python for Windows associates *.py with python.exe and *.pyw with pythonw.exe.

  4. what if we don’t have gvim installed?

    I use non-gui version of vim under Windows XP + cygwin, and I am not willing to install another windows version gvim at the moment. Is it possible to tailor these scripts so that it works under such environment?

    I am always wanting tweaks such that whenever windows calls for a text editor, it invokes rxvt + vim, is this possible?

    Thanks,

    Jindan

    1. Yes, replacement

      Jindan,

      Yes, replacement is trivially easy in each of these scripts in order to use the cygwin version of vim instead of the native Win32 gvim. Simply everywhere it currently calls c:\some_path\bin\vim, replace it with c:\your_cygwin_path\bin\rxvt -e vim.

      For instance, in my case, my Cygwin root is in d:\cygwin. I would replace this line:

      ed = r"c:\vim\vim62\gvim.exe" # *vi* editor binary

      with this one:

      ed = r"d:\cygwin\bin\rxvt.exe -e vim" # *vi* editor binary

      Just tested it, done and done. So the Python version is figured out; you’d need to adjust it similarly if you were to use Weed’s Visual Basic version on the parent page. I’m not using either one anymore, at the moment, because I’m so sick of Outlook. I went back to using OfflineIMAP + Mutt on a Cygwin managed mount because it’s so much faster, and I can run it remotely without having to use some sort of remote desktop. If I get an appointment in my inbox that requires their synchronization tool, I note the time of the appointment in my Palm Pilot, and next time I’m in the office I might fire up Outlook to confirm the appointment (or just show up; people around here rarely seem to care if you actually RSVP for the meeting or not).

      Curiously, my new company’s Exchange server doesn’t create nearly the havoc with offlineimap that the old one did. I wonder if they improved their IMAP support in the latest version?


      Matthew P. Barnson

      1. That is so cool!

        This is what I did, first I created vim.bat in c:\program files\cygwin\bin with this line:

        start rxvt -sr -sl 2500 -geometry 90×30 -fg grey70 -bg midnightblue -fn “Lucida ConsoleP-16” -e vim %1

        Then I changed the View Source program from Notepad to vim.bat, worked out like a charm! Since many of the IE temp file doesn’t have an extension file name, I need to manually type

        set syntax=html

        to enable syntax highlighting each time. Trying to figure out a workaround now.

        Weed’s code doesn’t work out (yet), when I press the macro button, the screen flashed as if something happening, but then nothing. Is there a log that I can check in VB editor or Outlook so that I can tell what happened?

        1. syntax highlighting

          Try adding these lines to your $HOME/.vimrc file (this varies according to installation, the easiest way is to just do “vi ~/.vimrc” from a cygwin shell):

          “turn on syntax highlighting
          :syntax on

          Now it’s possible that vim may not recognize your terminal type. In order to work around this (like if syntax highlighting won’t turn on from this one addition to your .vimrc), then try adding these to your ~/.vimrc:

          “fix inability to read term type
          :set term=xterm-color


          Matthew P. Barnson

          1. I think the problem is with …

            That the IE temporary files are sometimes without an explicit extension name, i.e. .html, .htm, etc., thus vim can’t find a proper syntax highlighting scheme, even though I have “syntax on” set in my .vimrc file.

          2. Okay, the prolem is solved by …

            modifying my vim.bat as followed:

            start rxvt -sr -sl 2500 -geometry 90×30 -fg grey70 -bg midnightblue -fn “Lucida ConsoleP-16” -e vim -c “set syntax=html” %1

            Thanks, Matt!

          3. syntax=mail

            You’ll get even better results with syntax highlighting if you do a:

            vim -c “set syntax=mail” %1

            Vim’s very smart about email syntax, understanding quoting and such. Since I prefer a dark background with light text, I’d add this to my .vimrc as well:

            :colorscheme murphy

            Other light-on-dark colorschemes that work well are “torte”, “evening”, and “ron”.

            Good luck!

            :wq!


            Matthew P. Barnson

        2. Weed’s code

          It doesn’t work for me (yet). I tried debugging the script and found that the GetInspector methor returns “Nothing” – I have Microsoft Outlook 2003. I went to outlookcode.com and obtained a few test scripts – all of them exit with the same result – GetInspector returns nothing. Does anyone have any clues to offer?

          Thanks in advance, Girish

          1. Problem with VBS

            Hi,

            I successfully created the launchvim.vbs script and the acompanying VB Makro. But vim doesn’t start when clicking on the macro-button in the toolbar. Does anyone have a clue?

            I’m using Outlook 2003 and VIM 7.0

          2. Here’s the new version

            All,

            I changed the code up a bit. Here are the new steps.

            1) In Outlook, click Tools->Macro->Visual Basic Editor 2) Under Tools->References, make sure Microsoft Scripting Runtime is selected. Close out of the dialog 3) Either create a new module or use and existing one 4) Paste the following code into the module:

             Option Explicit
            
            Private Type STARTUPINFO cb As Long lpReserved As String lpDesktop As String lpTitle As String dwX As Long dwY As Long dwXSize As Long dwYSize As Long dwXCountChars As Long dwYCountChars As Long dwFillAttribute As Long dwFlags As Long wShowWindow As Integer cbReserved2 As Integer lpReserved2 As Long hStdInput As Long hStdOutput As Long hStdError As Long End Type
            
            Private Type PROCESS_INFORMATION hProcess As Long hThread As Long dwProcessID As Long dwThreadID As Long End Type
            
            Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal _ hHandle As Long, ByVal dwMilliseconds As Long) As Long
            
            Private Declare Function CreateProcessA Lib "kernel32" (ByVal _ lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _ lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _ ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _ ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _ lpStartupInfo As STARTUPINFO, lpProcessInformation As _ PROCESS_INFORMATION) As Long
            
            Private Declare Function CloseHandle Lib "kernel32" (ByVal _ hObject As Long) As Long
            
            Private Const NORMAL_PRIORITY_CLASS = &H20& Private Const INFINITE = -1&
            
            Sub LaunchVIM()
            
            'Dim windir As String
            
            'windir = Environ("WinDir")
            
            'Shell (windir & "\system32\cscript.exe " & windir & "\system32\launchvim.vbs") Const TemporaryFolder = 2 Const VIMLocation = "C:\Program Files\Vim\vim70\gvim.exe"
            
            Dim ol, insp, item, body, fso, tempfile, tfolder, tname, tfile, appRef, x
            
            Set ol = Application
            
            Set insp = ol.ActiveInspector If insp Is Nothing Then Exit Sub End If Set item = insp.CurrentItem If item Is Nothing Then Exit Sub End If
            
            body = CStr(item.body)
            
            Set fso = CreateObject("Scripting.FileSystemObject") Set tfolder = fso.GetSpecialFolder(TemporaryFolder) tname = fso.GetTempName Set tfile = tfolder.CreateTextFile(tname) tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10))) tfile.Close
            
            ExecCmd VIMLocation & " " & Chr(34) & tfolder.Path & "\" & tname & Chr(34)
            
            Set tfile = fso.OpenTextFile(tfolder.Path & "\" & tname, 1) item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10)) tfile.Close
            
            fso.DeleteFile (tfolder.Path & "\" & tname)
            
            End Sub
            
            Public Sub ExecCmd(cmdline$) Dim proc As PROCESS_INFORMATION Dim start As STARTUPINFO Dim ReturnValue As Integer
            
            ' Initialize the STARTUPINFO structure: start.cb = Len(start)
            
            ' Start the shelled application: ReturnValue = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, _ NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)
            
            ' Wait for the shelled application to finish: Do ReturnValue = WaitForSingleObject(proc.hProcess, 0) DoEvents Loop Until ReturnValue <> 258
            
            ReturnValue = CloseHandle(proc.hProcess) End Sub 

            Now follow the above intructions on creating a toolbar button that launches the Macro “LaunchVIM”

            This method keeps everything in VBA and strips out the VBScript external application as well as the WSH junk.

            This post used massive amounts of cut-and-paste programming from examples provided at the MS MSDN site. All the answers are there, however finding them is the trick. πŸ˜‰

            My $.02 Weed

          3. Colorized!

            And, of course, the preceding code… colorized!

            Yeah, I’m useless. But I like coloring books.

             Option Explicit
            
            Private Type STARTUPINFO cb As Long lpReserved As String lpDesktop As String lpTitle As String dwX As Long dwY As Long dwXSize As Long dwYSize As Long dwXCountChars As Long dwYCountChars As Long dwFillAttribute As Long dwFlags As Long wShowWindow As Integer cbReserved2 As Integer lpReserved2 As Long hStdInput As Long hStdOutput As Long hStdError As Long End Type
            
            Private Type PROCESS_INFORMATION hProcess As Long hThread As Long dwProcessID As Long dwThreadID As Long End Type
            
            Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal _ hHandle As Long, ByVal dwMilliseconds As Long) As Long
            
            Private Declare Function CreateProcessA Lib "kernel32" (ByVal _ lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _ lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _ ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _ ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _ lpStartupInfo As STARTUPINFO, lpProcessInformation As _ PROCESS_INFORMATION) As Long
            
            Private Declare Function CloseHandle Lib "kernel32" (ByVal _ hObject As Long) As Long
            
            Private Const NORMAL_PRIORITY_CLASS = &H20& Private Const INFINITE = -1&
            
            Sub LaunchVIM()
            
            'Dim windir As String
            
            'windir = Environ("WinDir")
            
            'Shell (windir & "\system32\cscript.exe " & windir & "\system32\launchvim.vbs")
            
            Const TemporaryFolder = 2 Const VIMLocation = "C:\Program Files\Vim\vim70\gvim.exe"
            
            Dim ol, insp, item, body, fso, tempfile, tfolder, tname, tfile, appRef, x
            
            Set ol = Application
            
            Set insp = ol.ActiveInspector If insp Is Nothing Then Exit Sub End If Set item = insp.CurrentItem If item Is Nothing Then Exit Sub End If
            
            body = CStr(item.body)
            
            Set fso = CreateObject("Scripting.FileSystemObject") Set tfolder = fso.GetSpecialFolder(TemporaryFolder) tname = fso.GetTempName Set tfile = tfolder.CreateTextFile(tname) tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10))) tfile.Close
            
            ExecCmd VIMLocation & " " & Chr(34) & tfolder.Path & "\" & tname & Chr(34)
            
            Set tfile = fso.OpenTextFile(tfolder.Path & "\" & tname, 1) item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10)) tfile.Close
            
            fso.DeleteFile (tfolder.Path & "\" & tname)
            
            End Sub
            
            Public Sub ExecCmd(cmdline$)
            
            Dim proc As PROCESS_INFORMATION Dim start As STARTUPINFO Dim ReturnValue As Integer
            
            ' Initialize the STARTUPINFO structure: start.cb = Len(start)
            
            ' Start the shelled application: ReturnValue = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, _ NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)
            
            ' Wait for the shelled application to finish: Do ReturnValue = WaitForSingleObject(proc.hProcess, 0) DoEvents Loop Until ReturnValue 258
            
            ReturnValue = CloseHandle(proc.hProcess)
            
            End Sub
            
            


            Matthew P. Barnson

          4. Copy/paste

            I use… what else? Vim πŸ™‚ In this case, specifically, gvim, but you can do it from any version.

            Copy and paste into vim.

            :cal SetSyn(“vb”) :syntax on :set background=light :runtime! syntax/2html.vim ggVG (to select all in this top frame) “+y (to copy to clipboard)

            Then paste using whatever method you use to paste. gvim makes this easier than console-based vim, as you can use drop-down menus instead of console commands. I just trim the header & footer information, and then post!

            I think it works fine with filtered HTML (the Drupal default), but it may not. I use full html mode to post.


            Matthew P. Barnson

          5. VIM and outlook

            You don’t use VIM w/Outlook anymore though, do you?

            I don’t use VIM at all (except for rare cases), but I can’t have my code not working. It’s a problem I have…

            My $.02 Weed

          6. Enlightened employer

            Until March 1, 2006, I used Vim/Outlook all the time with my employer. My company was acquired by a new company which is far more enlightened about their IT policies… they use Linux extensively, and almost exclusively, for server infrastructure. I normally use Thunderbird with some plugins or their web-based collaboration suite, either of which support Vim just fine.

            Firefox + mozex for Vim in a textarea via the web interface. For Vim in Thunderbird, I use the External Editor extension: http://www.appliedmiscellany.com/blog/archives/22


            Matthew P. Barnson

          7. Thanks!

            Thanks for that! It’s worthwhile to note how old the original blog entry is though…. ViewSourceWith wasn’t written at the time I wrote the original. I always expect humanity to better a good idea.


            Matthew P. Barnson

  5. The Python code strips accented letters from Outlook

    fh.write(body.encode(‘ascii’, ‘ignore’).replace(‘\r\n’, ‘\n’)) likely is the reason that accented letters like Γ© in GΓ©rard end up being dropped πŸ™ This severely limits an otherwise very good call to VIM for Outlook.

    Any fix?

    1. encoding…

      I’d think replacing “ascii” with a Unicode encoding such as “Latin-1” might do the trick, or, more likely, eliminate the body.encode call entirely and try just doing an fh.write. Unfortunately, I’ve stopped using this program for “real” work, so I don’t have a way to test it.

      You’ll also have to make sure your Vim is set up to handle Unicode, which is an area where I have to claim utter ignorance πŸ™‚

      Additionally, I don’t know that the whole stripping \r\n thing is even necessary in the Windows version of Vim today. The one I’m running now handles DOS-formatted files without a hiccup.


      Matthew P. Barnson

  6. problems when gvim installed in “Program Files” dir

    Matt,

    I’m trying to use your script with gvim, which I have installed in the “Program Files” directory. Here’s the line I changed in the script:

    ed = r”c:\Program Files\Vim\vim70\gvim.exe” # *vi* editor binary

    Only problem is that when I try to write-quit out of gvim, I get the following error:

    “Files\Vim\vim70\gvim.exe” E212: Can’t open file for writing

    I think it’s having issues with the space between “Program” and “Files” in the path to the .exe.

    Any ideas?

    Ben

    1. Progra~1

      Have you tried using “Progra~1” instead? I think that’s the DOS name.


      Matthew P. Barnson

      1. dir /x

        If you open a command prompt and go to the C: drive, then type dir /x, it’ll show you the normal name and the 8.3 dos name. But Matt’s right, 99.9999999% of the time, it’ll be Progra~1.

        My $.02 Weed

  7. Issues with customizing toolbar

    Hi,

    I tried Weed’s second post for how to set this up but when I try to customize the toolbar in the compose email window there are no macros available in the dialog window (however, the macros do appear when I customize the main mail window). I’m using Outlook 2003 on Windows XP. Please let me know if you have any ideas.

    Cheers.

    1. At least for me…

      At least for me, time moves on and so did I. My new company is very tolerant of open-source software, so I’m back to using Mutt on Linux for 99% of my mail needs. Sorry I can’t help; maybe Weed can chime in?


      Matthew P. Barnson

    2. Don’t Compose Using Word

      I bet you’re using Word to compose email messages. The script won’t work if you’re using Word as your email editor, although it might be tweaked if you want to play with it. I don’t have time now.

      To see if Outlook is using Word as your email editor, from the mail Outlook window, click Tools->Options, and look on the Mail Format tab.

      My $.02 Weed

  8. Newlines Messing Up

    FWIW, I found that using the second version of the VB macro code above was screwing up all of the newlines in my gVim-written text. I was able to fix the problem by changing these lines:

    ‘item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10)) item.body = tfile.ReadAll … ‘tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10))) tfile.Write (body)

    My problem was probably due to some combination of my Outlook composition settings (Plain Text Only) and the way gVim handles newlines.

    1. I Forget

      I forget why I put that in there in the first place. Maybe a previous version of Vim on Windows had Unix-style newlines, and I needed to convert them to Windows-style newlines.

      Your replacement is much cleaner in that there’s no text “search and replace” going on to slow things down.

      My $.02 Weed

      1. I got it to work with vim,

        I got it to work with vim, but any idea how to get it to work in emacs?

        I changed the vim references & paths to the emacs path (runemacs). When I hit the button, emacs launces & edits a file in the TEMP directory with a name of the appropriate form, but it isn’t the same file that Outlook is using.

        In vim, my signature is included, and when I save & quit, the edited text shows up in Outlook.

        In emacs, my signature isn’t there and my edits are not in Outlook when I quit.

        1. Hmm

          So if you click the button to edit in Emacs, anything already in the Outlook compose window doesn’t show up in the Emacs editor?

          Open the temp file Outlook creates with another text editor (vi, notepad, etc) and see if the text is in there. If so, maybe we need to call emacs with the temp file location differently. I can’t imagine it’s NOT there as it works for vi.

          Also, what version of emacs, Outlook, and OS are you running?

          My $.02 Weed

          1. Yes, you are correct: the

            Yes, you are correct: the vim version works, but it seems like there’s no interchange of data in *either* direction with emacs: Emacs opens ~a~ temporary file, but doesn’t seem to open the ~correct~ temp file, but I don’t have the VBA background to understand how the data is exchaged.

            I’m running Emacs 22.1.1 and Outlook 2003 under XP Pro.

            If I open a new Outlook message, type “weed” in the box, and click LaunchVIM, then vim opens C:\TEMP\radA92AD.tmp which contains “weed.” If I immediately click Project1.LaunchEmacs, then emacs edits a blank file C:\TEMP\rad54E92.tmp

            But what really causes a problem, is that Open new message in Outlook Click Project1.LaunchVIM In vim, type iweed Esc :wq! Results in a message containing the word “weed”

            But Open new message in Outlook Click Project1.LaunchEmacs In emacs, type weed ^x^s ^x^c Results in a still-blank Outlook message

            Secondly, there’s a bit of a bug in the VB: In either editor, I get a runtime error “attempt to navigate past end of file.” The offending line is: item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))

            This happens when starting VIM on a blank (no signature*) email, but, tellingly, not when launching Emacs.

            Lastly, since we’re doing this largely to work in keyboard-based editors, can we assign a hotkey to the macro, or is Alt-F8, Enter the best way to invoke these? Can Outlook be instructed to run this on every new message? If one did auto-invoke, would it break stuff like meeting replies? (sorry; I’m a little new to Outlook)

            *I’m using Autohotkey hotstrings for my various signatures: 1. I find it more flexible to insert an internal, external, or no signature explicitly rather than often having to select and delete a sig. 2. Some company systems have me sending mail from a Web form, where OL signatures don’t exist.

          2. RE: Editor War

            I’m pretty ecumenical…I almost have to be given that vi was written by a Michigan alumnus πŸ™‚

            In college (outside of Michigan), I was not properly instructed in the power features (repeating commands, etc.) of vi to justify the initial investment in learning it. A fellow student misled me into pico for a while, then, seeking more power, I got into emacs. I don’t think vim, with its language modes, was very popular then yet, either, so I tried to learn emacs. Over the years, I’ve put time into emacs in fits & starts.

            I’m technically a salesman not a programmer, so I can’t really master multiple editors.

            Somebody put together a really nice Web page showing the powerful macros that you can do with vi that almost made me want to switch, but, again, I can only invest in learning one editor really well. And that’s what’s great about this page: it’s efficient to use the same set of editing commands in as many contexts as possible.

            Along those lines, it’s probably good to implement some basic vi commands as an autohotkey script.

            I actually use sort of a hybrid vi/emacs key layout, which might be a bad idea: I use the middle button above the trackpad on as a modifier to implement the following: mbutton & h backspace mbutton & j left mbutton & k up mbutton & l down mbutton & ; right mbutton & ‘ delete mbutton & u ^left (usually back one word) mbutton & p ^right (usu forward word) mbutton & i/o page up/page down (up / down screen) mbutton & n backspace word mbutton & , ^HOME (or BACK in Firefox…) mbutton & . ^END (or FORWARD in Firefox…maybe should keep as ctrl-end in FF to scroll to the bottom of long Web pages)

            So, for what it’s worth, I get vi’s home-row navigation in a non-modal context.

            I’m waiting on a keyboard for the office…I might use the left Windows key if I don’t have a middle button.

          3. RE: Editor War

            Oh, and in my scheme, the letter m is HOME and / is END.

            I looked at Xah Lee’s “ergonomic keyboard layout for emacs,” while I was working through this.

            The IBM middle button is kind of nice, since it falls directly under my left thumb and I always used my right hand for the spacebar anyway.

            What kind of sucks (at least in autohotkey) is that I don’t think you can use any other modifier with a mouse button a modifier. So shift and ctrl don’t work in this scheme. I think I used Capslock-[ and Capslock-]to go into “shift mode,” but that was too complicated even for me.

          4. emacs & vi

            …almost made me want to switch, but, again, I can only invest in learning one editor really well.

            Truth be told, I actually use both editors frequently. emacs in psgml mode is, for me, much more intuitive when editing SGML, XML, or sometimes even HTML documents. vi is more intuitive when I’m programming in python, bash, or perl. On my workstation I run both frequently.

            I just tend to land in the vi camp most often because I administer a farm of thousands of servers. vi is the lowest-common-denominator editor everywhere. I miss vim’s extension, color, and syntax support when I’m on a remote machine, though, and often as not write the code chunk on my local workstation and paste it into the remote window.

            You’ve lost me on the problems integrating emacs into Outlook, though… I stopped using outlook the day after UltraMegaCorp announced that the new mail standard allowed “open source clients” in addition to Outlook. I sync the calendar to my Windows Mobile Device (pretty much the only place I look for calendar and task info), and have used Mutt and Thunderbird for handling mail. I used Mutt for many years until last week, and decided to try Thunderbird. I’ve been impressed with the number of keyboard shortcuts so far, which was my big complaint with most GUI mail programs.

            Next project: integrating vi into Thunderbird πŸ™‚ Thunderbird’s spell-checker stinks, it won’t format plain text correctly, it won’t let me modify text I’m replying to without munging the formatting… yuck! But it’s a decent mail reader, and with a dovecot backend rather than Maildir it’s much faster searching email than Mutt was. Of course, that’s a Dovecot feature more than a Thunderbird feature.

            I’ll have to blog my setup one day. I’m totally using the corporate mail system, yet I’m not allowing myself to be subject to their limiting “features” (Teeny, tiny quotas! Augh!) by using my own mail server and keeping regular backups. It’s pretty trivial on a Linux box, and only slightly more difficult on a Windows machine (via Cygwin).


            Matthew P. Barnson

          5. Try this

            Every time you click the button (be it the Emacs one or the Vi one), it creates a new temp file. So the fact that the tmp files have different names isn’t an issue. W

            What I would want to try is to type some text into the compose window, and hit your Emacs button. You’ll see the tmp file it wants to open. While keeping the Emacs editor open, try and open that same tmp file in vi or notepad or whatever. I want to see if the text you typed into the Outlook compose window is getting to the temp file, and it’s just emacs isn’t opening it correctly. Or, if for some reason when Emacs opens the temp file it clobbers the contents (or does some sort of silly renaming thing like notepad does, putting a .txt on the end of everything).

            With respect to the bug, try replacing this: item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))

            With this: Dim ftxt ftxt = tfile.ReadAll item.body = Replace(ftxt, Chr(10), Chr(13) & Chr(10))

            It may still error, but it’ll give me a better idea of which statement is causing the error.

            See this MS KB article about assigning hotkeys to macros. Note it’s for Outlook 2002, but it should work in your case: http://support.microsoft.com/kb/292798/en-us

            As for auto-invoke, would you want this macro to run on every message which comes in, or would you want this macro to open your compose window for you?

            My $.02 Weed

          6. New outlook message Type

            New outlook message Type “Weed” in the message box Click Project1.LaunchVIM vim shows C:\temp\rad38D7E.tmp contains “Weed” launch command line type runemacs C:\temp\rad38D7E.tmp result: emacs opens the file and it contains “Weed” in emacs: type ^e “enjoys adult panda movies” ^x^s^x^c VIM shows Warning that the file has changed; hit “Load file”, hit Esc :q! Outlook now shows “Weed enjoys adult panda movies”

            So if I manually give runemacs the right filename, it works. The question is why it is getting a different temp file.

            ———- To the VB error, now the breakpoint is ftxt = tfile.ReadAll

            I think the answer is in: http://www.microsoft.com/technet/scriptcenter/guide/sas_scr_eqco.mspx

            But when I took out the Dim and went back to your original line but wrapped in an if: If tifle.Size > 0 Then item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10)) End If

            Now I get an error ‘438’: “Object doesn’t support this property or method” when I close VIM. The breakpoint is If tfile.Size > 0 Then

          7. I was thinking of having the

            I was thinking of having the external editor launch automatically on each new message, but I need to type the addresses & subject first and I may also want to edit replies in Emacs, so autolaunch would probably be more trouble than it’s worth.

            So I’ll use the link you sent to add a hotkey.

          8. Outlook / Editor wars

            Matthew,

            Yes, knowing both would be nice, but I’m a salesman, not an IT or programmer, so the fact that I can even spell emacs is overkill for my role.

            This kind of brings up a discussion of use cases. You are “Ace Sysadmin,” Microsoft designs for “Ignorant Newbie, and I’m “Technically-Inclined Productivity-Obsessed Power User.” I’m capable of changing my path, writing autohotkey scripts & batch files, learning shortcuts, etc. But I really don’t have skills to do all that you mention in a finite amount of time without screwing stuff up.

            But I’m really surprised to say this: After hating and resisting Outlook my entire career, I realize it can become a pretty good “Integrated Productivity Environment,” so much that I’m devoting one of my monitors to it. Here’s how:

            1. Apply David Allen’s whitepaper “GTD in Outlook.” (this also kind of clarified a lot of GTD principles that weren’t clear from the book) I have some minor tweaks, but he gives a good “base install.”

            2. Install Speedfiler from Claritude. Speedfiler gives me the filing & navigation power that even Thunderbird (which I used for the last 1.5 years ago) and PINE lack. Even QuickMove didn’t really help that much with TB.

            Speedfiler can be used on both incoming & outgoing messages, and provides the interactive substring search that I have always dreamed of. Outlook has Ctrl-Shift-V to move a message and Ctrl-Y to go to a folder. Speedfiler replaces the crappy graphical browser with a substring search. So I can move a message to my _@Action-NonSales folder with: Ctrl-Shift-V nons

            And go to a folder at _Reference/Tier1/Asian/Denso with: ^y den

            SpeedFiler kicks butt.

          9. more on use cases…

            BTW, I’m not singling out computer professionals: I recently upgraded to Quicken 2007 from 2000. My main motivation was to automate as much as possible so that I would actually start keeping financial records again (and do so FASTER than my grandmother’s paper checkbook, which could not be said of my all-manual Quicken 2000). When I ask friends for help, they fall into two categories:

            1. People who don’t use Quicken.

            2. Accountants. Quicken is their *hobby* and they have never used & don’t understand the WebConnect or DirectConnect. They say “Oh, I’ve never tried any of that online stuff; I just enter all my transactions manually. I log in and check my credit cards every morning, too. Look at my calculator watch: I paid $39.47 for it in 1985.”

          10. Emacs always opens a blank file…

            New message, type “Weed enjoys Family Friendly entertainment” Click Project1.LaunchEmacs Emacs launches and edits C:\TEMP\radD281D.tmp , which is blank

            Click Project1.LaunchVIM Vim launches, edits C:\temp\rad9F783.tmp

            I don’t think it has anything to do with dueling two editors: Emacs *never* has the right file.

            My ill-informed brainstorms: 1. Emacs’ method of opening files has a race condition, where Windows starts using a different filename before it fully opens????

            2. Emacs’ method of frontslash / backslash translation screws things up?

            Here’s the full text of my emacs code: Option Explicit

            Private Type STARTUPINFO cb As Long lpReserved As String lpDesktop As String lpTitle As String dwX As Long dwY As Long dwXSize As Long dwYSize As Long dwXCountChars As Long dwYCountChars As Long dwFillAttribute As Long dwFlags As Long wShowWindow As Integer cbReserved2 As Integer lpReserved2 As Long hStdInput As Long hStdOutput As Long hStdError As Long End Type

            Private Type PROCESS_INFORMATION hProcess As Long hThread As Long dwProcessID As Long dwThreadID As Long End Type

            Private Declare Function WaitForSingleObject Lib “kernel32” (ByVal _ hHandle As Long, ByVal dwMilliseconds As Long) As Long

            Private Declare Function CreateProcessA Lib “kernel32” (ByVal _ lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _ lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _ ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _ ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _ lpStartupInfo As STARTUPINFO, lpProcessInformation As _ PROCESS_INFORMATION) As Long

            Private Declare Function CloseHandle Lib “kernel32” (ByVal _ hObject As Long) As Long

            Private Const NORMAL_PRIORITY_CLASS = &H20& Private Const INFINITE = -1&

            Sub LaunchEmacs()

            ‘Dim windir As String

            ‘windir = Environ(“WinDir”)

            ‘Shell (windir & “\system32\cscript.exe ” & windir & “\system32\launchEmacs.vbs”) Const TemporaryFolder = 2 Const EmacsLocation = “C:\apps\emacs-22.1\bin\runemacs.exe”

            Dim ol, insp, item, body, fso, tempfile, tfolder, tname, tfile, appRef, x

            Set ol = Application

            Set insp = ol.ActiveInspector If insp Is Nothing Then Exit Sub End If Set item = insp.CurrentItem If item Is Nothing Then Exit Sub End If

            body = CStr(item.body)

            Set fso = CreateObject(“Scripting.FileSystemObject”) Set tfolder = fso.GetSpecialFolder(TemporaryFolder) tname = fso.GetTempName Set tfile = tfolder.CreateTextFile(tname) tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10))) tfile.Close

            ExecCmd EmacsLocation & ” ” & Chr(34) & tfolder.Path & “\” & tname & Chr(34)

            Set tfile = fso.OpenTextFile(tfolder.Path & “\” & tname, 1) item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10)) tfile.Close

            fso.DeleteFile (tfolder.Path & “\” & tname)

            End Sub

            Public Sub ExecCmd(cmdline$) Dim proc As PROCESS_INFORMATION Dim start As STARTUPINFO Dim ReturnValue As Integer

            ‘ Initialize the STARTUPINFO structure: start.cb = Len(start)

            ‘ Start the shelled application: ReturnValue = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, _ NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)

            ‘ Wait for the shelled application to finish: Do ReturnValue = WaitForSingleObject(proc.hProcess, 0) DoEvents Loop Until ReturnValue <> 258

            ReturnValue = CloseHandle(proc.hProcess) End Sub

            ———————————————– Option Explicit

            Private Sub launch()

            Const TemporaryFolder = 2

            Dim ws, ol, insp, item, body, fso, tempfile, tfolder, tname, tfile

            Set ol = CreateObject(“Outlook.Application”)

            Set insp = ol.ActiveInspector If insp Is Nothing then Exit Sub End if Set item = insp.CurrentItem If item Is Nothing then Exit Sub End if

            body = CStr(item.Body)

            Set fso = CreateObject(“Scripting.FileSystemObject”) Set tfolder = fso.GetSpecialFolder(TemporaryFolder) tname = fso.GetTempName Set tfile = tfolder.CreateTextFile(tname) tfile.Write( Replace( body, Chr(13) & Chr(10), Chr(10) ) ) tfile.Close()

            Set ws = WScript.CreateObject(“WScript.Shell”) Wsh.Echo( “C:\apps\emacs-22.1\bin\runemacs.exe ” & tfolder.Path & “\” & tname ) ws.Run “c:\apps\emacs-22.1\bin\runemacs.exe ” & tfolder.Path & “\” & tname ,4, true

            Set tfile = fso.OpenTextFile(tfolder.Path & “\” & tname, 1 ) item.body = Replace( tfile.ReadAll, Chr(10), Chr(13) & Chr(10) ) tfile.close()

            fso.DeleteFile( tfolder.Path & “\” & tname )

            End Sub

            Call launch()

          11. Can’t use ws.run

            Try this code:

            *** BEGIN SNIP ***

            Option Explicit

            Private Type STARTUPINFO cb As Long lpReserved As String lpDesktop As String lpTitle As String dwX As Long dwY As Long dwXSize As Long dwYSize As Long dwXCountChars As Long dwYCountChars As Long dwFillAttribute As Long dwFlags As Long wShowWindow As Integer cbReserved2 As Integer lpReserved2 As Long hStdInput As Long hStdOutput As Long hStdError As Long End Type

            Private Type PROCESS_INFORMATION hProcess As Long hThread As Long dwProcessID As Long dwThreadID As Long End Type

            Private Declare Function WaitForSingleObject Lib “kernel32” (ByVal _ hHandle As Long, ByVal dwMilliseconds As Long) As Long

            Private Declare Function CreateProcessA Lib “kernel32” (ByVal _ lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _ lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _ ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _ ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _ lpStartupInfo As STARTUPINFO, lpProcessInformation As _ PROCESS_INFORMATION) As Long

            Private Declare Function CloseHandle Lib “kernel32” (ByVal _ hObject As Long) As Long

            Private Const NORMAL_PRIORITY_CLASS = &H20& Private Const INFINITE = -1&

            Sub LaunchVIM()

            Const TemporaryFolder = 2 Const VIMLocation = “C:\Program Files\Vim\vim70\gvim.exe”

            Dim ol, insp, item, body, fso, tempfile, tfolder, tname, tfile, appRef, x

            Set ol = Application

            Set insp = ol.ActiveInspector If insp Is Nothing Then Exit Sub End If Set item = insp.CurrentItem If item Is Nothing Then Exit Sub End If

            body = CStr(item.body)

            Set fso = CreateObject(“Scripting.FileSystemObject”) Set tfolder = fso.GetSpecialFolder(TemporaryFolder) tname = fso.GetTempName

            Set tfile = tfolder.CreateTextFile(tname) tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10))) tfile.Close

            ExecCmd VIMLocation & ” ” & Chr(34) & tfolder.Path & “\” & tname & Chr(34)

            Dim ffile Set ffile = fso.GetFile( tname ) If ffile.Size > 0 Then Set tfile = fso.OpenTextFile(tfolder.Path & “\” & tname, 1) item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10)) tfile.Close End if ffile.Close fso.DeleteFile (tfolder.Path & “\” & tname)

            End Sub

            Sub LaunchEmacs()

            Const TemporaryFolder = 2 Const EmacsLocation = “C:\apps\emacs-22.1\bin\runemacs.exe”

            Dim ol, insp, item, body, fso, tempfile, tfolder, tname, tfile, appRef, x

            Set ol = Application

            Set insp = ol.ActiveInspector If insp Is Nothing Then Exit Sub End If Set item = insp.CurrentItem If item Is Nothing Then Exit Sub End If

            body = CStr(item.body)

            Set fso = CreateObject(“Scripting.FileSystemObject”) Set tfolder = fso.GetSpecialFolder(TemporaryFolder) tname = fso.GetTempName

            Set tfile = tfolder.CreateTextFile(tname) tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10))) tfile.Close

            ExecCmd EmacsLocation & ” ” & Chr(34) & tfolder.Path & “\” & tname & Chr(34)

            Dim ffile Set ffile = fso.GetFile( tname ) If ffile.Size > 0 Then Set tfile = fso.OpenTextFile(tfolder.Path & “\” & tname, 1) item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10)) tfile.Close End if ffile.Close fso.DeleteFile (tfolder.Path & “\” & tname)

            End Sub

            Public Sub ExecCmd(cmdline$)

            Dim proc As PROCESS_INFORMATION Dim start As STARTUPINFO Dim ReturnValue As Integer

            ‘ Initialize the STARTUPINFO structure: start.cb = Len(start)

            ‘ Start the shelled application: ReturnValue = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, _ NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)

            ‘ Wait for the shelled application to finish: Do ReturnValue = WaitForSingleObject(proc.hProcess, 0) DoEvents Loop Until ReturnValue 258

            ReturnValue = CloseHandle(proc.hProcess)

            End Sub

            **** END SNIP *****

            That whole launch() function will never work: You can’t use ws.run because it doesn’t wait until the process ends to return to the calling function. Refer to the original post and see how I used CreateProcessA to call it synchonously. What happens when you use ws.run is that emacs is launched and then outlook just runs the rest of the code before emacs is ever opened.

            My $.02 Weed

          12. Good news:After making some

            Good news: After making some minor fixes: VIM can read text that was in Outlook & insert text. Emacs can read text that was in Outlook !!

            But in both cases, ffile.close is making a big problem: Run-time error 438 “object doesn’t support this property or method,” whether inside or outside the IF statement; deleting it completely doesn’t work either.

            Here is current code (note the <> operators on the do…until EOF check, some tabbing on the IF statements, putting the file path in the file opening statements, and (sorry) adjustments for my path:

            Option Explicit

            Private Type STARTUPINFO cb As Long lpReserved As String lpDesktop As String lpTitle As String dwX As Long dwY As Long dwXSize As Long dwYSize As Long dwXCountChars As Long dwYCountChars As Long dwFillAttribute As Long dwFlags As Long wShowWindow As Integer cbReserved2 As Integer lpReserved2 As Long hStdInput As Long hStdOutput As Long hStdError As Long End Type

            Private Type PROCESS_INFORMATION hProcess As Long hThread As Long dwProcessID As Long dwThreadID As Long End Type

            Private Declare Function WaitForSingleObject Lib “kernel32” (ByVal _ hHandle As Long, ByVal dwMilliseconds As Long) As Long

            Private Declare Function CreateProcessA Lib “kernel32” (ByVal _ lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _ lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _ ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _ ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _ lpStartupInfo As STARTUPINFO, lpProcessInformation As _ PROCESS_INFORMATION) As Long

            Private Declare Function CloseHandle Lib “kernel32” (ByVal _ hObject As Long) As Long

            Private Const NORMAL_PRIORITY_CLASS = &H20& Private Const INFINITE = -1&

            Sub LaunchVIM()

            Const TemporaryFolder = 2 Const VIMLocation = “C:\apps\Vim\vim71\gvim.exe”

            Dim ol, insp, item, body, fso, tempfile, tfolder, tname, tfile, appRef, x

            Set ol = Application

            Set insp = ol.ActiveInspector If insp Is Nothing Then Exit Sub End If Set item = insp.CurrentItem If item Is Nothing Then Exit Sub End If

            body = CStr(item.body)

            Set fso = CreateObject(“Scripting.FileSystemObject”) Set tfolder = fso.GetSpecialFolder(TemporaryFolder) tname = fso.GetTempName

            Set tfile = tfolder.CreateTextFile(tname) tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10))) tfile.Close

            ExecCmd VIMLocation & ” ” & Chr(34) & tfolder.Path & “\” & tname & Chr(34)

            Dim ffile Set ffile = fso.GetFile(tfolder.Path & “\” & tname) If ffile.Size > 0 Then Set tfile = fso.OpenTextFile(tfolder.Path & “\” & tname, 1) item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10)) tfile.Close End If

            ffile.Close

            fso.DeleteFile (tfolder.Path & “\” & tname)

            End Sub

            Sub LaunchEmacs()

            Const TemporaryFolder = 2 Const EmacsLocation = “C:\apps\emacs-22.1\bin\runemacs.exe”

            Dim ol, insp, item, body, fso, tempfile, tfolder, tname, tfile, appRef, x

            Set ol = Application

            Set insp = ol.ActiveInspector If insp Is Nothing Then Exit Sub End If Set item = insp.CurrentItem If item Is Nothing Then Exit Sub End If

            body = CStr(item.body)

            Set fso = CreateObject(“Scripting.FileSystemObject”) Set tfolder = fso.GetSpecialFolder(TemporaryFolder) tname = fso.GetTempName

            Set tfile = tfolder.CreateTextFile(tname) tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10))) tfile.Close

            ExecCmd EmacsLocation & ” ” & Chr(34) & tfolder.Path & “\” & tname & Chr(34)

            Dim ffile Set ffile = fso.GetFile(tfolder.Path & “\” & tname) If ffile.Size > 0 Then Set tfile = fso.OpenTextFile(tfolder.Path & “\” & tname, 1) item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10)) tfile.Close End If

            ffile.Close

            fso.DeleteFile (tfolder.Path & “\” & tname)

            End Sub

            Public Sub ExecCmd(cmdline$)

            Dim proc As PROCESS_INFORMATION Dim start As STARTUPINFO Dim ReturnValue As Integer

            ‘ Initialize the STARTUPINFO structure: start.cb = Len(start)

            ‘ Start the shelled application: ReturnValue = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, _ NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)

            ‘ Wait for the shelled application to finish: Do ReturnValue = WaitForSingleObject(proc.hProcess, 0) DoEvents Loop Until ReturnValue <> 258 ReturnValue = CloseHandle(proc.hProcess)

            End Sub

            end of code

          13. Duh

            The <> is because of the whole HTML tag thing, I guess that’s why they were left out.

            Replace the

            ffile.close

            with

            Set ffile = Nothing

            My $.02 Weed

          14. Now we’re back to Square 1

            So now VIM works perfectly (including handling zero-length files), but Emacs doesn’t get text from or push text to Outlook.

            * Commenting out the Set command doesn’t help * If I put the ffile.Close back in, I get the VB error, but at least emacs can read (but not write) the text.

          15. No commenting

            We’re not commenting anything.

            REPLACE the line:

            ffile.Close

            with

            Set ffile = Nothing

            My $.02 Weed

          16. Yes, I did that

            Weed, thanks for sticking with me: I did the replacement exactly as you said. VIM works, even with zero-length files, but emacs doesn’t.

            The point is that the ffile.close version at least got text into emacs, but the new current version doesn’t even do that.

            Commenting was just my own step at debugging.

          17. So Simple

            So I decided to download emacs and test it out.

            The problem is that you’re calling runemacs.exe. The way my code works is that is launches the process, waits for it to exit, then reads the temp file to see what changes have been made. However, runemacs.exe is just a launcher for emacs.exe. So runemacs.exe starts, launches emacs.exe, and then exits. So my code sees that runemacs.exe has exited, reads the contents of the tmp file, and goes along its merry way. All before the actual emacs window has time to pop up on your screen.

            The fix is to modify the Emacs_Location to run emacs.exe, not runemacs.exe. I don’t know if this breaks anything else, but it fixes the immediate problem.

            My $.02 Weed

          18. Yay!

            Wow, thanks Weed! The only change that I needed to make was to get rid of the cr/lf issue on the output, i.e., replace:

            item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))

            with:

            item.body = tfile.ReadAll

            Sorry about not knowing much about emacs invocation…runemacs is nice because it gets rid of an extra shell window that emacs leaves. I am aware of other programs/command s like gnuclient that also invoke emacs.

            There may be things that addpm does also, but I installed a previous version on another computer and still usually got the extra black box.

            And as far as hotkeys, I suspect that a refinement would be to map the desired key to an autohotkey script that would: get the position of the current message and get emacs to launch in roughly the same position. But I can probably figure that part out.

            This is really cool; thanks, Weed!

            EDIT by matthew: <pre> tags changed to <blockquote> due to threading issues.

          19. The extra box…

            If you look closely at my descriptions for running vim, you’ll see that in early versions I had a similar text-box issue hanging out in the background. In my case, I just got used to it until Weed happily provided a workaround.

            Weed is teh ubar sysadmin.

            I believe that using “emacsclient” (included in the bin directory of your emacs package) rather than “runemacs” will preserve the benefit of runemacs without forking the emacs process (it will wait for emacs to exit before it exits). Downside: if you have multiple emacs windows running, it will wait for ctrl-x# or the last window to exit before it closes.


            Matthew P. Barnson

          20. emacsclient

            emacsclient was on my list of stuff to look up about the invocation issue. But I’ll trade the black box for the ability to not clobber my other emacs window.

            Instead of going to the current insertion point, something that I’d find more useful is even simpler (and I can’t believe it’s not in Outlook): a command to go to the body/notes of a message, appointment, or task.

            The number of times to hit tab between the “subject” and body varies between the different categories of item.

            It would be nice to hit alt-. or something and go to the body, but I guess there’s not much need to do so with emacs enabled.

            And I did successfully assign this macro to alt-/ (one of the few keys that is not used by a default Outlook macro), and it works in appointments and tasks as well as email.

          21. You’re close

            Try it the other way:

            Click the emacs button: determine the temp file emacs is using. open that one in vi (don’t use the button, just open vi manually) and see if the text is in there.

            If you hit the Project1.LaunchVIM button and then hit the Project1.LaunchEmacs button on the same message, it should open 2 different tmp files. Otherwise VIM and Emacs would fight over the one tmp file. However, there might be some issues with opening both editors at the same time I don’t see right now…

            Post the modified code you’re using to launch emacs and let me look it over

            As for the bug, you need to do this:

            Dim ffile Set ffile = fso.GetFile(tfolder.Path & “\” & tname) If ffile.Size > 0 Set tfile = fso.OpenTextFile(tfolder.Path & “\” & tname, 1) item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10)) tfile.Close End if ffile.Close

            And ixnay on the andapay oviemays, kayoay? πŸ˜‰

            My $.02 Weed

  9. Good contens, its works

    Good content, it works Great Thanks for all of your work on it.

    Best Regards, Bangkok Travel

Comments are closed.