diff options
Diffstat (limited to 'Tools/msi')
-rw-r--r-- | Tools/msi/msi.py | 44 | ||||
-rw-r--r-- | Tools/msi/msisupport.c | 89 | ||||
-rw-r--r-- | Tools/msi/msisupport.mak | 12 |
3 files changed, 107 insertions, 38 deletions
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 @@ def add_ui(db): # 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 + |