Replace VB with VC.
diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py
index eb17ad5..6ef5335 100644
--- a/Tools/msi/msi.py
+++ b/Tools/msi/msi.py
@@ -295,47 +295,15 @@
     # UpdateEditIDLE sets the REGISTRY.tcl component into
     # the installed/uninstalled state according to both the
     # Extensions and TclTk features.
-    open("inst.vbs","w").write("""
-    Function CheckDir()
-      Set FSO = CreateObject("Scripting.FileSystemObject")
-      if FSO.FolderExists(Session.Property("TARGETDIR")) then
-        Session.Property("TargetExists") = "1"
-      else
-        Session.Property("TargetExists") = "0"
-      end if
-    End Function
-    Function UpdateEditIDLE()
-      Dim ext_new, tcl_new, regtcl_old
-      ext_new = Session.FeatureRequestState("Extensions")
-      tcl_new = Session.FeatureRequestState("TclTk")
-      if ext_new=-1 then
-         ext_new = Session.FeatureCurrentState("Extensions")
-      end if
-      if tcl_new=-1 then
-         tcl_new = Session.FeatureCurrentState("TclTk")
-      end if
-      regtcl_old = Session.ComponentCurrentState("REGISTRY.tcl")
-      if ext_new=3 and (tcl_new=3 or tcl_new=4) and regtcl_old<>3 then
-         Session.ComponentRequestState("REGISTRY.tcl")=3
-      end if
-      if (ext_new=2 or tcl_new=2) and regtcl_old<>2 then
-         Session.ComponentRequestState("REGISTRY.tcl")=2
-      end if
-    End Function
-    """)
-    # To add debug messages into scripts, the following fragment can be used
-    #     set objRec = Session.Installer.CreateRecord(1)
-    #     objRec.StringData(1) = "Debug message"
-    #     Session.message &H04000000, objRec
-    add_data(db, "Binary", [("Script", msilib.Binary("inst.vbs"))])
-    # See "Custom Action Type 6"
+    if os.system("nmake /nologo /c /f msisupport.mak") != 0:
+        raise "'nmake /f msisupport.mak' failed"
+    add_data(db, "Binary", [("Script", msilib.Binary("msisupport.dll"))])
+    # See "Custom Action Type 1"
     add_data(db, "CustomAction",
-        [("CheckDir", 6, "Script", "CheckDir")])
+        [("CheckDir", 1, "Script", "_CheckDir@4")])
     if have_tcl:
         add_data(db, "CustomAction",
-        [("UpdateEditIDLE", 6, "Script", "UpdateEditIDLE")])
-    os.unlink("inst.vbs")
-
+        [("UpdateEditIDLE", 1, "Script", "_UpdateEditIDLE@4")])
 
     # UI customization properties
     add_data(db, "Property",
diff --git a/Tools/msi/msisupport.c b/Tools/msi/msisupport.c
new file mode 100644
index 0000000..a6feadf
--- /dev/null
+++ b/Tools/msi/msisupport.c
@@ -0,0 +1,89 @@
+#include "windows.h"
+#include "msiquery.h"
+
+/* Print a debug message to the installer log file.
+ * To see the debug messages, install with
+ * msiexec /i pythonxy.msi /l*v python.log
+ */
+static UINT debug(MSIHANDLE hInstall, LPCWSTR msg)
+{
+	MSIHANDLE hRec = MsiCreateRecord(1);
+	if (!hRec || MsiRecordSetStringW(hRec, 1, msg) != ERROR_SUCCESS) {
+		return ERROR_INSTALL_FAILURE;
+	}
+	MsiProcessMessage(hInstall, INSTALLMESSAGE_INFO, hRec);
+	MsiCloseHandle(hRec);
+	return ERROR_SUCCESS;
+}
+
+/* Check whether the TARGETDIR exists and is a directory.
+ * Set TargetExists appropriately.
+ */
+UINT __declspec(dllexport) __stdcall CheckDir(MSIHANDLE hInstall)
+{
+	WCHAR path[1024];
+	UINT result;
+	DWORD size = sizeof(path)/sizeof(WCHAR);
+	DWORD attributes;
+	
+	result = MsiGetPropertyW(hInstall, L"TARGETDIR", path, &size);
+	if (result != ERROR_SUCCESS)
+		return result;
+	path[size] = L'\0';
+
+	attributes = GetFileAttributesW(path);
+	if (attributes == INVALID_FILE_ATTRIBUTES ||
+		!(attributes & FILE_ATTRIBUTE_DIRECTORY)) 
+	{
+		return MsiSetPropertyW(hInstall, L"TargetExists", L"0");
+	} else {
+		return MsiSetPropertyW(hInstall, L"TargetExists", L"1");
+	}
+}
+
+/* Update the state of the REGISTRY.tcl component according to the
+ * Extension and TclTk features. REGISTRY.tcl must be installed
+ * if both features are installed, and must be absent otherwise.
+ */
+UINT __declspec(dllexport) __stdcall UpdateEditIDLE(MSIHANDLE hInstall)
+{
+	INSTALLSTATE ext_old, ext_new, tcl_old, tcl_new, reg_new;
+	UINT result;
+
+	result = MsiGetFeatureStateW(hInstall, L"Extensions", &ext_old, &ext_new);
+	if (result != ERROR_SUCCESS)
+		return result;
+	result = MsiGetFeatureStateW(hInstall, L"TclTk", &tcl_old, &tcl_new);
+	if (result != ERROR_SUCCESS)
+		return result;
+
+	/* If the current state is Absent, and the user did not select
+	   the feature in the UI, Installer apparently sets the "selected"
+	   state to unknown. Update it to the current value, then. */
+	if (ext_new == INSTALLSTATE_UNKNOWN)
+		ext_new = ext_old;
+	if (tcl_new == INSTALLSTATE_UNKNOWN)
+		tcl_new = tcl_old;
+
+	// XXX consider current state of REGISTRY.tcl?
+	if (((tcl_new == INSTALLSTATE_LOCAL) ||
+		 (tcl_new == INSTALLSTATE_SOURCE) ||
+		 (tcl_new == INSTALLSTATE_DEFAULT)) &&
+		((ext_new == INSTALLSTATE_LOCAL) ||
+		 (ext_new == INSTALLSTATE_SOURCE) ||
+		 (ext_new == INSTALLSTATE_DEFAULT))) {
+		reg_new = INSTALLSTATE_SOURCE;
+	} else { 
+		reg_new = INSTALLSTATE_ABSENT;
+	}
+	result = MsiSetComponentStateW(hInstall, L"REGISTRY.tcl", reg_new);
+	return result;
+}
+
+BOOL APIENTRY DllMain(HANDLE hModule, 
+                      DWORD  ul_reason_for_call, 
+                      LPVOID lpReserved)
+{
+    return TRUE;
+}
+
diff --git a/Tools/msi/msisupport.mak b/Tools/msi/msisupport.mak
new file mode 100644
index 0000000..1047510
--- /dev/null
+++ b/Tools/msi/msisupport.mak
@@ -0,0 +1,12 @@
+# /OPT: REF and ICF are added by VS.NET by default
+# NOWIN98 saves 7k of executable size, at the expense of some
+# slowdown on Win98
+msisupport.dll:	msisupport.obj
+	link.exe /OUT:msisupport.dll /INCREMENTAL:NO /NOLOGO /DLL /MACHINE:X86 /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /OPT:NOWIN98 msisupport.obj msi.lib kernel32.lib
+
+# We request a static CRT, so that there will be no CRT dependencies
+# for the target system. We cannot do without a CRT, since it provides
+# the DLL entry point.
+msisupport.obj:	msisupport.c
+	cl /O2 /D WIN32 /D NDEBUG /D _WINDOWS /MT /W3 /c msisupport.c
+