I've been using Linux almost exclusively on my laptops since 1999. I've now (September 2004) bought a new laptop and decided to give Windows another try. On this page I'll assemble some information I've gathered which helped me to make Windows more usable for me. The main reason for its existence is that I can refer to it should I ever have to reinstall the OS. But if someone else thinks the stuff here is useful, he/she is invited to use it... :)
And of course, as is you didn't know that already, if you apply any of this information to your own system, you may end up causing damage to your software, your hardware, or your mental health. I take no responsibility for anything that you may do as a result of reading this page. The contents of this page are provided 'as is' with no warranty. Yada, yada, yada...
If you want to know when or if this page has been updated check the
CVS header at the bottom.
A very nice SSH client which I think is superior to other commercial or free offers. Make sure to enable "Copy on select" and "Paste on middle button" in your Global Options.
I couldn't live without it. What I don't like about it is its default
shell (cygwin.bat) so I've installed
sshd as a service and use SecureCRT to connect to
localhost instead. Much better IMHO.
A nice little freeware app to create folder "hard links" on NTFS file
systems. These will play nicely with every application including
Cygwin and Emacs while Explorer shortcuts (.lnk)
won't. Note that Cygwin can create file "hard links" for you but you
can also use a specialized tool like Hardlink
ShellExtension instead.
A shareware replacement for Windows' built-in "Quick Launch" facility. It has popup menus and keyboard shortcuts which really work.
Another shareware tool. You can use it to minimize applications into the tray instead of the task bar. These apps are also removed from the Alt-Tab rotation. Very handy.
A free replacement for the Windows Task Manager. Very informative and helpful.
I use it to catalogue all my backups. Has saved my life a couple of times.
You can handle most formats with Cygwin already but sometimes it's convenient to have a graphical tool if you just want to look into some archive or extract one or two files from it. FilZip does a good job and it's free.
I have a batch file startwin.bat in my Windows Startup folder that looks like this:
@echo off SET DISPLAY=127.0.0.1:0.0 SET CYGWIN_ROOT=\cygwin SET PATH=.;%CYGWIN_ROOT%\bin;%CYGWIN_ROOT%\usr\X11R6\bin;%PATH% SET XAPPLRESDIR=/usr/X11R6/lib/X11/app-defaults SET XCMSDB=/usr/X11R6/lib/X11/Xcms.txt SET XKEYSYMDB=/usr/X11R6/lib/X11/XKeysymDB SET XNLSPATH=/usr/X11R6/lib/X11/locale if not exist %CYGWIN_ROOT%\tmp\.X11-unix\X0 goto CLEANUP-FINISH attrib -s %CYGWIN_ROOT%\tmp\.X11-unix\X0 del %CYGWIN_ROOT%\tmp\.X11-unix\X0 :CLEANUP-FINISH if exist %CYGWIN_ROOT%\tmp\.X11-unix rmdir %CYGWIN_ROOT%\tmp\.X11-unix run XWin -nounixkill -multiwindow -clipboard -silent-dup-error -xkblayout de -xkbrules xfree86 -xkbmodel pc105 -xkbvariant nodeadkeysThis also takes care of my German keyboard.
I had one problem with Cygwin/X: If I connect to another machine (or
even to localhost) via Cygwin's ssh and with X11 forwarding then
remote Emacsen will mysteriously crash under certain
circumstances. Turns out that this doesn't occur with SecureCRT. So I
now have a tiny VB script Emacs.vbs like this one
# $language = "VBScript" # $interface = "1.0" Sub Main crt.Screen.Send "emacs && exit" & VbCr crt.window.Show(0) End Suband use it as a "logon script" for SecureCRT. (Note that the two comment lines are necessary!) This enables me to have entries in True Launch Bar which directly open remote Emacsen with one mouse click or a keyboard shortcut.
Unfortunately they don't support Debian as a guest OS so you have to
invest some time if you want to use the VMWare Tools (and you
should use them): I installed a minimal Debian testing system
from a Sarge business card ISO from cdimage.debian.org
and used a 2.4 kernel - from my experiences VMWare doesn't seem to be
ready for 2.6 yet. Then I grabbed a matching kernel source, copied the
.config file from the /boot directory and
built the kernel with make-kpkg. This will give you the
same kernel you already have installed but now you have the kernel
headers the VMWare Tools installer wants to know about. Once you have
VMWare Tools installed you'll have DMA access to your hard drive and a
clock which is synchronized with your host OS.
I usually minimize VMWare into the tray via ToggleMinimize and then use it through SecureCRT. I generally don't use the X Server of the virtual machine.
Note that VMWare will not cleanly survive if you hibernate your system
or put it into standby mode. I hope they'll fix this in the future.
browse-url)
opens a link I don't want it to use a new window but a new tab
instead. It turns out that this can be easily accomplished with
Tabbrowser Extensions.
In my user.js I have
these lines:
user_pref("browser.block.target_new_window", true);
user_pref("nglayout.initialpaint.delay", 0);
[HKEY_CLASSES_ROOT\AllFilesystemObjects\shellex\ContextMenuHandlers\Copy To]
@="{C2FBB630-2971-11d1-A18C-00C04FD75D13}"
[HKEY_CLASSES_ROOT\AllFilesystemObjects\shellex\ContextMenuHandlers\Move To]
@="{C2FBB631-2971-11d1-A18C-00C04FD75D13}"
Update: I don't use these anymore - they don't seem to always work properly.
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\commandprompt] @="Command &Prompt" [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\commandprompt\command] @="cmd.exe /k pushd %L"
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced] "EnableBalloonTips"=dword:00000000
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Messenger\Client] "PreventRun"=dword:00000001
.REG file (which should start with a
line like "REGEDIT4").
To start Emacs maximized put this line at the end of your ~/.emacs file:
(w32-send-sys-command 61488)If you don't want the Emacs tool bar you can add the line
(tool-bar-mode 0) to your ~/.emacs file
but Emacs won't fully maximize in this case - the real estate occupied
by the tool bar is lost. You have to disable the tool bar in the
registry to get it back:
[HKEY_LOCAL_MACHINE\SOFTWARE\GNU\Emacs\Emacs.Toolbar] @="0"
Some key bindings I use:
(defun my-delete-frame ()
"Deletes the current frame. If this is the last frame, quit Emacs."
(interactive)
(if (cdr (frame-list))
(delete-frame)
(save-buffers-kill-emacs)))
(global-set-key [\M-f4] 'my-delete-frame)
(defun my-make-frame ()
"Make a new frame and maximize it."
(interactive)
(w32-send-sys-command 61488 (make-frame)))
(global-set-key "\M-n" 'my-make-frame)
Unfortunately, Gnuserv is not very well documented and there doesn't seem to be an active maintainer. I got my copy from http://www.wyrdrune.com/Files/gnuserv.zip.
Update: In the meantime, Guy Gascoigne-Piggford has released a new (beta) version of Gnuserv which is available from http://www.wyrdrune.com/Files/.
To install Gnuserv unzip the archive and copy gnuserv.exe
and gnuclientw.exe to your Emacs bin directory. Copy
gnuserv.el to a folder which is in your load path and
optionally byte-compile it. Finally, add the lines
(require 'gnuserv) (setq gnuserv-frame (car (frame-list))) (gnuserv-start)to your
~/.emacs file. The second line will prevent Emacs
from creating a new frame each time it is invoked via gnuclientw - leave it out if
you like this behaviour.
There's one little problem: If Emacs was minimized and is afterwards
invoked via gnuclientw it won't return to its maximized
state. This is actually a shortcoming of NT Emacs which doesn't behave
like a good Windows citizen and not a problem of
gnuclientw. However, it is easy to get rid of this. Patch
gnuclient.c like so
--- gnuclient.c~ 1999-09-11 22:37:24.000000000 +0200
+++ gnuclient.c 2004-10-11 20:31:22.433531000 +0200
@@ -85,16 +85,19 @@
return (TRUE);
}
-void showEmacs( int unIconify )
+void showEmacs( int unIconify, int maximize )
{
HWND hWnd = FindWindow ("Emacs", NULL);
if ( hWnd ) {
/* Is the Emacs window iconified ? */
if (IsIconic (hWnd)) {
if (unIconify) {
- ShowWindow (hWnd, SW_SHOWNORMAL);
+ ShowWindow (hWnd, SW_SHOW);
/* Need this since Emacs thinks it is still iconified otherwise! */
SendMessage (hWnd, WM_SYSCOMMAND, SC_RESTORE, 0);
+ if (maximize) {
+ SendMessage (hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
+ }
}
}
else {
@@ -181,6 +184,7 @@
#if defined( WIN32 )
int wintofront = 0; /* wintofront flag */
int uniconify = 0; /* uniconify flag */
+ int maximize = 0; /* maximize flag */
int runEmacs = 0;
#endif
#ifdef INTERNET_DOMAIN_SOCKETS
@@ -208,7 +212,7 @@
#ifdef INTERNET_DOMAIN_SOCKETS
#if defined( WIN32 )
- "h:p:r:qfFxe"
+ "h:p:r:qfFMxe"
#else
"h:p:r:qe"
#endif
@@ -243,6 +247,11 @@
case 'F':
wintofront = 1;
uniconify = 1;
+ break;
+ case 'M':
+ wintofront = 1;
+ uniconify = 1;
+ maximize = 1;
break;
case 'x': /* Just run and or show emacs */
runEmacs = 1;
@@ -276,7 +285,7 @@
#if defined( WIN32 )
if ( runEmacs ) { /* just run and or show Emacs and then exit */
- showEmacs( 1 );
+ showEmacs( 1, maximize );
exit(0);
}
#endif
@@ -373,7 +382,7 @@
#if defined( WIN32 )
if (wintofront)
- showEmacs( uniconify );
+ showEmacs( uniconify, maximize );
#endif
#ifdef SYSV_IPC
and re-build gnuclientw.exe. If you don't want to do this
you can download the whole archive including the patch and binary
executables from http://weitz.de/files/gnuserv.zip. The
patch adds a new command-line option "-M" which, if present, makes
sure Emacs is maximized after it has been uniconified. It also
automatically adds the options "-f" (bring Emacs window to front) and
"-F" (uniconify if necessary). Note that in all of the following
recipes you can replace "-M" with "-F" or "-f" or leave it out
completely. If you do this you don't have to use the patched version
of gnuclientw.
Now that you have Gnuserv installed you can create a Windows shortcut for Emacs with the following target:
c:\emacs\bin\gnuclientw.exe -M "%1"You can drag any file on this shortcut and it will open in Emacs. If Emacs is already running the file will just be opened in a new buffer, otherwise Emacs will be started. You can also double-click this shortcut to start Emacs or bring a running Emacs to the front. However, Emacs will try to open a file named "%1" in this case (which most likely doesn't exist). You can prevent this from happening by adding the following form to your
~/.emacs file:
(defadvice server-find-file (around ignore-percent-one (file) activate)
(if (or (not (string= "%1" (file-name-nondirectory file)))
(file-exists-p file))
ad-do-it))
I've added the shortcut described above to True Launch Bar and
assigned it a hot key.
But it gets even better: You can add an entry to the Explorer context menu such that if you right-click on any file you'll get an option to edit this file with Emacs:
[HKEY_CLASSES_ROOT\*\shell\Emacs] @="Edit with &Emacs" [HKEY_CLASSES_ROOT\*\shell\Emacs\command] @="c:\\emacs\\bin\\gnuclientw.exe -M \"%1\""Cool, isn't it?
If you want to open specific file types directly in Emacs by
double-clicking them you can do that, too. Here's an example for text
(.TXT) files:
[HKEY_CLASSES_ROOT\txtfile\shell\open\command] @="c:\\emacs\\bin\\gnuclientw.exe -M \"%1\""If you plan to do this with a lot of file types then maybe you can save some time with this Emacs Lisp code:
;; w32-reg-int is available from <http://www.gnusoftware.com/Emacs/Registry/>
;; you must also install registry.exe, available from the same location
(require 'w32-reg-int)
(require 'cl)
(defvar reg-open-suffixes
'("txt" "el" "php" "xml" "xsl" "system" "asd" "lisp" "cl")
"If you want a file type to be opened by Emacs if you double-click
its icon, add its suffix here.")
(defvar reg-edit-suffixes
'("asm" "cc" "cs" "cpp" "pl" "c" "htm" "csv" "h" "bat" "java" "js" "py" "pm" "sql")
"If you want a file type to be edited by Emacs if you right-click
its icon and choose \"Edit\", add its suffix here.")
(defvar gnuclientw "c:\\emacs\\bin\\gnuclientw.exe"
"Where gnuclientw is located")
(defun convert-gnuclientw ()
(let (pos
(gnuclientw-temp gnuclientw))
(while (setq pos (string-match "\\\\" gnuclientw-temp pos))
(setq gnuclientw-temp (replace-match "\\\\" t t gnuclientw-temp))
(incf pos)
(incf pos))
gnuclientw-temp))
(defun create-registry-entries* (suffix-list &optional edit)
(dolist (suffix suffix-list)
(lexical-let ((class (cdr (w32-reg-interface-read-value (format "HKEY_CLASSES_ROOT\\.%s\\" suffix)))))
(when class
(insert (format "[HKEY_CLASSES_ROOT\\%s\\shell\\%s\\command]
@=\"%s\"
"
class (if edit "edit" "open")
gnuclientw-for-regedit))))))
(defun create-registry-entries ()
(interactive)
(let ((gnuclientw-for-regedit (format "%s -M \\\"%%1\\\""
(convert-gnuclientw))))
(insert "REGEDIT4
")
(create-registry-entries* reg-open-suffixes)
(create-registry-entries* reg-edit-suffixes t)))
Change the variables to your liking, load the code with
load-file, open a new buffer and then M-x create-registry-entries. Now
save this buffer as a .REG file.
You can do more cool stuff with Gnuserv: With the following registry entry you can right-click any folder and open it with Dired:
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\Dired] @="Emacs &Dired" [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\Dired\command] @="c:\emacs\bin\gnuclientw.exe -M \"%L\""And with this one you can click on "mailto" links in your web browser and compose the email in Gnus:
[HKEY_CLASSES_ROOT\mailto\shell\open\command] @="c:\\emacs\\bin\\gnuclientw.exe -M -e \"(gnus-msg-mail (substring \\\"%1\\\" 7))\""
I want to send my email with Emacs and Gnus but I couldn't get starttls.exe
to play nicely with NT Emacs although it compiles cleanly on
Cygwin. Using a
local SMTP server on my laptop is not an option either because
many email servers nowadays reject email coming from dynamic IP
addresses. Therefore I use the following scheme: I try to guess from
certain heuristics whether I'm online and where I am. I use this
result to either select a specific SMTP server within the same LAN or
to connect to a shell account via ssh and use its local sendmail
daemon or to queue the mail if I'm offline. To achieve this I have
these lines in my ~/.emacs file:
(setq user-full-name "Edi Weitz")
(setq user-mail-address "edi@agharta.de")
(defadvice feedmail-buffer-to-binmail (around change-shell () activate)
"Make sure feedmail uses Cygwin's bash shell."
(let ((shell-file-name "sh"))
ad-do-it))
(defvar my-net-location nil
"Holds a symbol which describes my current location based on the
network settings. NIL means that I'm offline.")
(defun get-my-net-location ()
"Update the value of `my-net-location' based on certain heuristics."
(interactive)
(setq my-net-location
(let ((ipconfig (shell-command-to-string "ipconfig")))
(cond ((and (string-match "Default Gateway.*: 10\\.0\\.1\\.1" ipconfig)
(zerop (call-process "ping" nil nil nil "-n" "1" "miles")))
'home)
((and (string-match "Default Gateway.*: 192\\.168\\.0\\.1" ipconfig)
(zerop (call-process "ping" nil nil nil "-n" "1" "luna")))
'work)
((string-match "Default Gateway" ipconfig)
'other)
(t nil)))))
(defun my-send-mail ()
"Send email depending on the value of `my-net-location'."
(case my-net-location
(home
;; use SMTP server at home
(let ((smtpmail-smtp-service 25)
(smtpmail-smtp-server "my.mailserver.de"))
(smtpmail-send-it)))
(work
;; use customer's SMTP server
(let ((smtpmail-smtp-service 25)
(smtpmail-smtp-server "customer.mail.com"))
(smtpmail-send-it)))
(other
;; login via SSH to one of my servers and then send via local
;; sendmail
(let ((feedmail-enable-queue nil)
(feedmail-binmail-template "ssh shell.account.de -e none /usr/sbin/sendmail %s"))
(feedmail-send-it)))
(otherwise
;; offline - queue it
(let ((feedmail-enable-queue t))
(feedmail-send-it)))))
(setq message-send-mail-function 'my-send-mail
send-mail-function 'my-send-mail)
(setq feedmail-enable-queue t)
(setq auto-mode-alist
(cons '("\\.fqm$" . mail-mode) auto-mode-alist))
(defun maybe-feedmail-queue-reminder ()
"Run feedmail queue if online."
(interactive)
(when (get-my-net-location)
(feedmail-run-the-queue-global-prompt)))
(add-hook 'gnus-after-exiting-gnus-hook 'maybe-feedmail-queue-reminder)
(get-my-net-location)
Note that you need to patch feedmail.el to make this work because it
has /bin/sh hardcoded as the shell to use for feedmail-binmail-template:
--- feedmail.el~ 2004-10-08 22:41:10.022078400 +0200
+++ feedmail.el 2004-10-08 22:43:26.958984000 +0200
@@ -1302,17 +1302,18 @@
(defcustom feedmail-binmail-template (if mail-interactive "/bin/mail %s" "/bin/rmail %s")
- "*Command template for the subprocess which will get rid of the mail.
-It can result in any command understandable by /bin/sh. Might not
-work at all in non-Unix environments. The single '%s', if present,
-gets replaced by the space-separated, simplified list of addressees.
-Used in feedmail-buffer-to-binmail to form the shell command which
-will receive the contents of the prepped buffer as stdin. If you'd
-like your errors to come back as mail instead of immediately in a
-buffer, try /bin/rmail instead of /bin/mail (this can be accomplished
-by keeping the default nil setting of `mail-interactive'). You might
-also like to consult local mail experts for any other interesting
-command line possibilities."
+ "*Command template for the subprocess which will get rid of the
+mail. It can result in any command understandable by the shell named
+by `shell-file-name'. Might not work at all in non-Unix
+environments. \(Note that on Cygwin you can use the value \"sh\".) The
+single '%s', if present, gets replaced by the space-separated,
+simplified list of addressees. Used in feedmail-buffer-to-binmail to
+form the shell command which will receive the contents of the prepped
+buffer as stdin. If you'd like your errors to come back as mail
+instead of immediately in a buffer, try /bin/rmail instead of
+/bin/mail (this can be accomplished by keeping the default nil setting
+of `mail-interactive'). You might also like to consult local mail
+experts for any other interesting command line possibilities."
:group 'feedmail-misc
:type 'string
)
@@ -1328,7 +1329,8 @@
(set-buffer prepped)
(apply
'call-process-region
- (append (list (point-min) (point-max) "/bin/sh" nil errors-to nil "-c"
+ (append (list (point-min) (point-max) shell-file-name
+ nil errors-to nil shell-command-switch
(format feedmail-binmail-template
(mapconcat 'identity addr-listoid " "))))))
openssl and NT Emacs. I now use SSH port forwarding
instead. This requires that you also have a shell account on the mail
server to which you can connect via ssh without entering
your password. My IMAP server is configured to listen for SSL
connections on 993. It also listens for unencrypted connections on
143, but only on 127.0.0.1.
This is in my ~/.gnus:
(setq gnus-secondary-select-methods '((nnimap "mail-imap"
(nnimap-address "localhost")
(nnimap-server-port 7777))))
And this is in my ~/.emacs:
(defadvice imap-starttls-p (around always-nil (buffer) activate)
;; we don't want to use starttls even if it's offered by the server
nil)
(defvar imap-tunnel-process nil
"The process which creates the ssh connection for tunneling.")
(defvar imap-tunnel-buffer (generate-new-buffer " *imap-tunnel*")
"The buffer for imap-tunnel-process.")
(defvar real-imap-server "my.imap.server.de"
"The real address of the imap server. Set nnimap-server to
\"localhost\".")
(defvar real-imap-server-port 143
"The real port of the imap server. Set nnimap-server-port to the
local port you want to use for forwarding.")
(defun maybe-destroy-imap-tunnel ()
(when (processp imap-tunnel-process)
(message "Destroying imap tunnel")
(unwind-protect
(delete-process imap-tunnel-process)
(setq imap-tunnel-process nil))))
(defun maybe-create-imap-tunnel ()
(cond ((and (processp imap-tunnel-process)
(memq (process-status imap-tunnel-process) '(open run))))
(t
(maybe-destroy-imap-tunnel)
(message "Creating imap tunnel through %s:%s via port %s"
real-imap-server real-imap-server-port nnimap-server-port)
(let (done)
(with-current-buffer imap-tunnel-buffer
(erase-buffer)
(when (progn
(setq imap-tunnel-process
(start-process "imap-tunnel" imap-tunnel-buffer
shell-file-name shell-command-switch
;; Cygwin ssh doesn't really work here, so we use PuTTY instead
(format "c:\\PROGRA~1\\PuTTY\\plink.exe -l edi -i c:\\home\\.ssh\\edi.ppk -L %s:localhost:%s %s"
nnimap-server-port real-imap-server-port real-imap-server)))
(process-kill-without-query imap-tunnel-process)
imap-tunnel-process)
(while (and (memq (process-status imap-tunnel-process) '(open run))
(goto-char (point-min))
(not (looking-at ".")))
(accept-process-output imap-tunnel-process 1)
(sit-for 1))
(setq done t)))
(message "Creating imap tunnel through %s:%s via port %s...%s"
real-imap-server real-imap-server-port nnimap-server-port
(if done "done" "failed"))))))
(defadvice imap-open (before imap-tunnel () activate)
(maybe-create-imap-tunnel))
(add-hook 'gnus-after-exiting-gnus-hook 'maybe-destroy-imap-tunnel)
In my ~/.authinfo I had to add this line:
machine localhost login edi password frob port 7777And finally, make sure all messags I've read (IMAP or NNTP) are cached locally so I have them available when I'm offline:
(setq gnus-agent-cache t
gnus-agent-consider-all-articles t
gnus-agent-enable-expiration 'DISABLE
gnus-select-article-hook 'gnus-agent-fetch-selected-article)
load-path
is set to pick up this version of ERC.
PATH environment variable so that the GnuTLS
binary can be found. (If you're also using Cygwin, make sure that
you're not using the Cygwin version of GnuTLS by accident.)
~/.emacs file:
(require 'erc) (erc-autojoin-mode 1) (require 'erc-track) (erc-track-mode 1) (setq erc-nick "donald" erc-user-full-name "Donald Duck" erc-auto-query 'buffer erc-track-shorten-function nil erc-track-exclude-types '("JOIN" "NICK" "PART" "QUIT" "324" "329" "332" "333" "353" "477") erc-track-exclude-server-buffer t erc-anonymous-login nil erc-keywords '("\\bDonald\\b" "\\bDuck\\b" "\\bDuckburg\\b")) (defun erc-lisp () (interactive) (erc-select :server "irc.freenode.net" :port 6667)) (defun erc-customer-1 () (interactive) (erc-select :server "irc.customer1.com" :port 6667 :password "camarillo")) (defun erc-customer-2 () (interactive) (erc-select-ssl :server "irc.customer2.com" :port 7000 :password "brillo")) (setq erc-autojoin-channels-alist '(("customer1" "#blah" "#blech") ("customer2" "#business") ("freenode" "#lisp")))
(erc-lisp).
$Header: /usr/local/cvsrep/weitz.de/win/index.html,v 1.10 2008/02/10 12:39:22 edi Exp $