summaryrefslogtreecommitdiffstats
path: root/setup_native/source/win32/customactions/shellextensions
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--setup_native/source/win32/customactions/shellextensions/checkdirectory.cxx66
-rw-r--r--setup_native/source/win32/customactions/shellextensions/checkpatches.cxx62
-rw-r--r--setup_native/source/win32/customactions/shellextensions/completeinstallpath.cxx116
-rw-r--r--setup_native/source/win32/customactions/shellextensions/migrateinstallpath.cxx96
-rw-r--r--setup_native/source/win32/customactions/shellextensions/shlxtmsi.def9
-rw-r--r--setup_native/source/win32/customactions/shellextensions/shlxtmsi.hxx59
-rw-r--r--setup_native/source/win32/customactions/shellextensions/startmenuicon.cxx63
-rw-r--r--setup_native/source/win32/customactions/shellextensions/upgrade.cxx158
8 files changed, 629 insertions, 0 deletions
diff --git a/setup_native/source/win32/customactions/shellextensions/checkdirectory.cxx b/setup_native/source/win32/customactions/shellextensions/checkdirectory.cxx
new file mode 100644
index 000000000..8e4166b0d
--- /dev/null
+++ b/setup_native/source/win32/customactions/shellextensions/checkdirectory.cxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "shlxtmsi.hxx"
+
+#include <malloc.h>
+#include <assert.h>
+
+#include <queue>
+#include <stdio.h>
+
+#include <systools/win32/uwinapi.h>
+#include "../tools/seterror.hxx"
+
+extern "C" __declspec(dllexport) UINT __stdcall CheckInstallDirectory(MSIHANDLE handle)
+{
+ std::wstring sInstallPath = GetMsiPropertyW(handle, L"INSTALLLOCATION");
+ std::wstring sOfficeHostnamePath = GetMsiPropertyW(handle, L"OFFICEDIRHOSTNAME");
+
+ // MessageBoxW(NULL, sInstallPath.c_str(), L"DEBUG", MB_OK);
+
+ // unsetting all properties
+
+ UnsetMsiPropertyW(handle, L"DIRECTORY_NOT_EMPTY");
+
+ // 1. Searching for file setup.ini
+
+ std::wstring sSetupIniPath = sInstallPath + sOfficeHostnamePath + L"\\program\\setup.ini";
+
+ WIN32_FIND_DATAW data;
+ HANDLE hdl = FindFirstFileW(sSetupIniPath.c_str(), &data);
+
+ // std::wstring mystr = L"Searching for " + sSetupIniPath;
+ // MessageBoxW(NULL, mystr.c_str(), L"DEBUG", MB_OK);
+
+ if (IsValidHandle(hdl))
+ {
+ // setup.ini found -> directory cannot be used for installation.
+ SetMsiPropertyW(handle, L"DIRECTORY_NOT_EMPTY", L"1");
+ SetMsiErrorCode(MSI_ERROR_DIRECTORY_NOT_EMPTY);
+ // std::wstring notEmptyStr = L"Directory is not empty. Please choose another installation directory.";
+ // std::wstring notEmptyTitle = L"Directory not empty";
+ // MessageBoxW(NULL, notEmptyStr.c_str(), notEmptyTitle.c_str(), MB_OK);
+ FindClose(hdl);
+ }
+
+ return ERROR_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/setup_native/source/win32/customactions/shellextensions/checkpatches.cxx b/setup_native/source/win32/customactions/shellextensions/checkpatches.cxx
new file mode 100644
index 000000000..9bad21377
--- /dev/null
+++ b/setup_native/source/win32/customactions/shellextensions/checkpatches.cxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "shlxtmsi.hxx"
+#include <strsafe.h>
+#include <systools/win32/uwinapi.h>
+#ifdef DEBUG
+#include <sal/macros.h>
+#endif
+
+#ifdef DEBUG
+inline void OutputDebugStringFormatW( PCWSTR pFormat, ... )
+{
+ WCHAR buffer[1024];
+ va_list args;
+
+ va_start( args, pFormat );
+ StringCchVPrintfW( buffer, SAL_N_ELEMENTS(buffer), pFormat, args );
+ OutputDebugStringW( buffer );
+ va_end(args);
+}
+#else
+static void OutputDebugStringFormatW( PCWSTR, ... )
+{
+}
+#endif
+
+extern "C" __declspec(dllexport) UINT __stdcall CheckPatchList( MSIHANDLE handle )
+{
+ std::wstring sPatchList = GetMsiPropertyW( handle, L"PATCH" );
+ std::wstring sRequiredPatch = GetMsiPropertyW( handle, L"PREREQUIREDPATCH" );
+
+ OutputDebugStringFormatW( L"CheckPatchList called with PATCH=%s and PRQ=%s\n", sPatchList.c_str(), sRequiredPatch.c_str() );
+
+ if ( ( sPatchList.length() != 0 ) && ( sRequiredPatch.length() != 0 ) )
+ {
+ if ( wcsstr( sPatchList.c_str(), sRequiredPatch.c_str() ) )
+ {
+ SetMsiPropertyW( handle, L"IGNOREPREREQUIREDPATCH", L"1" );
+ OutputDebugStringFormatW( L"Set Property IgnorePrerequiredPatch!\n" );
+ }
+ }
+ return ERROR_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/setup_native/source/win32/customactions/shellextensions/completeinstallpath.cxx b/setup_native/source/win32/customactions/shellextensions/completeinstallpath.cxx
new file mode 100644
index 000000000..787041ed8
--- /dev/null
+++ b/setup_native/source/win32/customactions/shellextensions/completeinstallpath.cxx
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "shlxtmsi.hxx"
+
+#include <malloc.h>
+
+extern "C" __declspec(dllexport) UINT __stdcall CompleteInstallPath( MSIHANDLE handle )
+{
+ // This CustomAction is necessary for updates from OOo 3.0, OOo 3.1 and OOo 3.2 to versions
+ // OOo 3.3 or later. This is caused by a change of INSTALLLOCATION, that starting with OOo 3.3
+ // contains the name of the product again (instead of only "c:\program files"). Unfortunately
+ // this causes in an update installation, that INSTALLLOCATION is set to "c:\program files",
+ // so that in an OOo 3.3 or later, the directory "program" or "share" are directly created
+ // below "c:\program files".
+
+ HKEY hKey;
+
+ // Reading property OFFICEDIRHOSTNAME_, that contains the part of the path behind
+ // the program files folder.
+
+ std::wstring sInstallLocation = GetMsiPropertyW( handle, L"INSTALLLOCATION" );
+ std::wstring sOfficeDirHostname = GetMsiPropertyW( handle, L"OFFICEDIRHOSTNAME_" );
+
+ // If sInstallLocation ends with (contains) the string sOfficeDirHostname,
+ // INSTALLLOCATION is good and nothing has to be done here.
+
+ bool pathCompletionRequired = true;
+
+ if ( wcsstr( sInstallLocation.c_str(), sOfficeDirHostname.c_str() ) )
+ {
+ pathCompletionRequired = false; // nothing to do
+ }
+
+ // If the path INSTALLLOCATION does not end with this string, INSTALLLOCATION is maybe
+ // transferred from an OOo 3.0, OOo 3.1 and OOo 3.2 and need to be changed therefore.
+
+ if ( pathCompletionRequired )
+ {
+ std::wstring sManufacturer = GetMsiPropertyW( handle, L"Manufacturer" );
+ std::wstring sDefinedName = GetMsiPropertyW( handle, L"DEFINEDPRODUCT" );
+ std::wstring sUpgradeCode = GetMsiPropertyW( handle, L"UpgradeCode" );
+
+ // sUpdateVersion can be "3.0", "3.1" or "3.2"
+
+ std::wstring sProductKey30 = L"Software\\" + sManufacturer + L"\\" + sDefinedName +
+ L"\\" L"3.0" L"\\" + sUpgradeCode;
+
+ std::wstring sProductKey31 = L"Software\\" + sManufacturer + L"\\" + sDefinedName +
+ L"\\" L"3.1" L"\\" + sUpgradeCode;
+
+ std::wstring sProductKey32 = L"Software\\" + sManufacturer + L"\\" + sDefinedName +
+ L"\\" L"3.2" L"\\" + sUpgradeCode;
+
+ bool oldVersionExists = false;
+
+ if ( ERROR_SUCCESS == RegOpenKeyW( HKEY_CURRENT_USER, sProductKey30.c_str(), &hKey ) )
+ {
+ oldVersionExists = true;
+ RegCloseKey( hKey );
+ }
+ else if ( ERROR_SUCCESS == RegOpenKeyW( HKEY_CURRENT_USER, sProductKey31.c_str(), &hKey ) )
+ {
+ oldVersionExists = true;
+ RegCloseKey( hKey );
+ }
+ else if ( ERROR_SUCCESS == RegOpenKeyW( HKEY_CURRENT_USER, sProductKey32.c_str(), &hKey ) )
+ {
+ oldVersionExists = true;
+ RegCloseKey( hKey );
+ }
+ else if ( ERROR_SUCCESS == RegOpenKeyW( HKEY_LOCAL_MACHINE, sProductKey30.c_str(), &hKey ) )
+ {
+ oldVersionExists = true;
+ RegCloseKey( hKey );
+ }
+ else if ( ERROR_SUCCESS == RegOpenKeyW( HKEY_LOCAL_MACHINE, sProductKey31.c_str(), &hKey ) )
+ {
+ oldVersionExists = true;
+ RegCloseKey( hKey );
+ }
+ else if ( ERROR_SUCCESS == RegOpenKeyW( HKEY_LOCAL_MACHINE, sProductKey32.c_str(), &hKey ) )
+ {
+ oldVersionExists = true;
+ RegCloseKey( hKey );
+ }
+
+ if ( oldVersionExists )
+ {
+ // Adding the new path content sOfficeDirHostname
+ sInstallLocation += sOfficeDirHostname;
+ // Setting the new property value
+ MsiSetPropertyW(handle, L"INSTALLLOCATION", sInstallLocation.c_str());
+ }
+ }
+
+ return ERROR_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/setup_native/source/win32/customactions/shellextensions/migrateinstallpath.cxx b/setup_native/source/win32/customactions/shellextensions/migrateinstallpath.cxx
new file mode 100644
index 000000000..10c817169
--- /dev/null
+++ b/setup_native/source/win32/customactions/shellextensions/migrateinstallpath.cxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "shlxtmsi.hxx"
+#include <algorithm>
+#include <sstream>
+#include <systools/win32/uwinapi.h>
+
+extern "C" __declspec(dllexport) UINT __stdcall MigrateInstallPath(MSIHANDLE handle)
+{
+ std::wstring sInstDir = GetMsiPropertyW(handle, L"INSTALLLOCATION");
+ if (!sInstDir.empty())
+ return ERROR_SUCCESS; // Don't overwrite explicitly set value
+
+ auto RegValue = [](HKEY hRoot, const WCHAR* sKey, const WCHAR* sVal) {
+ std::wstring sResult;
+ WCHAR buf[32767]; // max longpath
+ DWORD bufsize = sizeof(buf); // yes, it is the number of bytes
+ if (RegGetValueW(hRoot, sKey, sVal, RRF_RT_REG_SZ, nullptr, buf, &bufsize) == ERROR_SUCCESS)
+ sResult = buf; // RegGetValueW null-terminates strings
+
+ return sResult;
+ };
+
+ const std::wstring sManufacturer = GetMsiPropertyW( handle, L"Manufacturer" );
+ const std::wstring sDefinedName = GetMsiPropertyW( handle, L"DEFINEDPRODUCT" );
+ const std::wstring sUpdateVersion = GetMsiPropertyW( handle, L"DEFINEDVERSION" );
+ const std::wstring sUpgradeCode = GetMsiPropertyW( handle, L"UpgradeCode" );
+ const std::wstring sBrandPackageVersion = GetMsiPropertyW(handle, L"BRANDPACKAGEVERSION");
+
+ std::wstring sKey = L"Software\\" + sManufacturer + L"\\" + sDefinedName +
+ L"\\" + sUpdateVersion + L"\\" + sUpgradeCode;
+
+ sInstDir = RegValue(HKEY_CURRENT_USER, sKey.c_str(), L"INSTALLLOCATION");
+ if (sInstDir.empty())
+ sInstDir = RegValue(HKEY_LOCAL_MACHINE, sKey.c_str(), L"INSTALLLOCATION");
+ // See #i93032# for layers description
+ if (sInstDir.empty())
+ {
+ sKey = L"Software\\LibreOffice\\Layers\\" + sDefinedName + L"\\" + sBrandPackageVersion;
+ sInstDir = RegValue(HKEY_CURRENT_USER, sKey.c_str(), L"INSTALLLOCATION");
+ }
+ if (sInstDir.empty())
+ {
+ sKey = L"Software\\LibreOffice\\Layers_\\" + sDefinedName + L"\\" + sBrandPackageVersion;
+ sInstDir = RegValue(HKEY_CURRENT_USER, sKey.c_str(), L"INSTALLLOCATION");
+ }
+ if (sInstDir.empty())
+ {
+ sKey = L"Software\\LibreOffice\\Layers\\" + sDefinedName + L"\\" + sBrandPackageVersion;
+ sInstDir = RegValue(HKEY_LOCAL_MACHINE, sKey.c_str(), L"INSTALLLOCATION");
+ }
+ if (sInstDir.empty())
+ {
+ sKey = L"Software\\LibreOffice\\Layers_\\" + sDefinedName + L"\\" + sBrandPackageVersion;
+ sInstDir = RegValue(HKEY_LOCAL_MACHINE, sKey.c_str(), L"INSTALLLOCATION");
+ }
+ if (sInstDir.empty())
+ {
+ std::wistringstream sOlds{ GetMsiPropertyW(handle, L"OLDPRODUCTS") };
+ std::wstring sOld;
+ while (std::getline(sOlds, sOld, L';'))
+ {
+ if (sOld.empty())
+ continue;
+ sKey = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + sOld;
+ sInstDir = RegValue(HKEY_LOCAL_MACHINE, sKey.c_str(), L"InstallLocation");
+ if (!sInstDir.empty())
+ break;
+ }
+ }
+
+ if (!sInstDir.empty())
+ MsiSetPropertyW(handle, L"INSTALLLOCATION", sInstDir.c_str());
+
+ return ERROR_SUCCESS;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/setup_native/source/win32/customactions/shellextensions/shlxtmsi.def b/setup_native/source/win32/customactions/shellextensions/shlxtmsi.def
new file mode 100644
index 000000000..57b6aa154
--- /dev/null
+++ b/setup_native/source/win32/customactions/shellextensions/shlxtmsi.def
@@ -0,0 +1,9 @@
+LIBRARY "shlxtmsi.dll"
+EXPORTS
+ CheckInstallDirectory
+ CheckPatchList
+ CompleteInstallPath
+ MigrateInstallPath
+ InstallStartmenuFolderIcon
+ DeinstallStartmenuFolderIcon
+ SetProductInstallMode
diff --git a/setup_native/source/win32/customactions/shellextensions/shlxtmsi.hxx b/setup_native/source/win32/customactions/shellextensions/shlxtmsi.hxx
new file mode 100644
index 000000000..3a08060be
--- /dev/null
+++ b/setup_native/source/win32/customactions/shellextensions/shlxtmsi.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SETUP_NATIVE_SOURCE_WIN32_CUSTOMACTIONS_SHELLEXTENSIONS_SHLXTMSI_HXX
+#define INCLUDED_SETUP_NATIVE_SOURCE_WIN32_CUSTOMACTIONS_SHELLEXTENSIONS_SHLXTMSI_HXX
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <msiquery.h>
+
+#include <string>
+
+static inline std::wstring GetMsiPropertyW( MSIHANDLE handle, const std::wstring& sProperty )
+{
+ std::wstring result;
+ WCHAR szDummy[1] = L"";
+ DWORD nChars = 0;
+
+ if ( MsiGetPropertyW( handle, sProperty.c_str(), szDummy, &nChars ) == ERROR_MORE_DATA )
+ {
+ DWORD nBytes = ++nChars * sizeof(WCHAR);
+ PWSTR buffer = static_cast<PWSTR>(_alloca(nBytes));
+ ZeroMemory( buffer, nBytes );
+ MsiGetPropertyW( handle, sProperty.c_str(), buffer, &nChars );
+ result = buffer;
+ }
+
+ return result;
+}
+
+static inline void SetMsiPropertyW( MSIHANDLE handle, const std::wstring& sProperty, const std::wstring& sValue )
+{
+ MsiSetPropertyW( handle, sProperty.c_str(), sValue.c_str() );
+}
+
+static inline void UnsetMsiPropertyW( MSIHANDLE handle, const std::wstring& sProperty )
+{
+ MsiSetPropertyW( handle, sProperty.c_str(), nullptr );
+}
+
+#endif // INCLUDED_SETUP_NATIVE_SOURCE_WIN32_CUSTOMACTIONS_SHELLEXTENSIONS_SHLXTMSI_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/setup_native/source/win32/customactions/shellextensions/startmenuicon.cxx b/setup_native/source/win32/customactions/shellextensions/startmenuicon.cxx
new file mode 100644
index 000000000..6e95c6e1e
--- /dev/null
+++ b/setup_native/source/win32/customactions/shellextensions/startmenuicon.cxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "shlxtmsi.hxx"
+
+#include <malloc.h>
+
+/*
+ Called during installation to customize the start menu folder icon.
+ See: http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
+*/
+extern "C" __declspec(dllexport) UINT __stdcall InstallStartmenuFolderIcon( MSIHANDLE handle )
+{
+ std::wstring sOfficeMenuFolder = GetMsiPropertyW( handle, L"OfficeMenuFolder" );
+ std::wstring sDesktopFile = sOfficeMenuFolder + L"Desktop.ini";
+
+ // at the moment there exists no Vista Icon, so we use the default folder icon.
+ // add the icon into desktop/util/verinfo.rc
+
+ // The value '0' is to avoid a message like "You Are Deleting a System Folder" warning when deleting or moving the folder.
+ WritePrivateProfileStringW(
+ L".ShellClassInfo",
+ L"ConfirmFileOp",
+ L"0",
+ sDesktopFile.c_str() );
+
+ SetFileAttributesW( sDesktopFile.c_str(), FILE_ATTRIBUTE_HIDDEN );
+ SetFileAttributesW( sOfficeMenuFolder.c_str(), FILE_ATTRIBUTE_SYSTEM );
+
+
+ return ERROR_SUCCESS;
+}
+
+extern "C" __declspec(dllexport) UINT __stdcall DeinstallStartmenuFolderIcon(MSIHANDLE handle)
+{
+ std::wstring sOfficeMenuFolder = GetMsiPropertyW( handle, L"OfficeMenuFolder" );
+ std::wstring sDesktopFile = sOfficeMenuFolder + L"Desktop.ini";
+
+ SetFileAttributesW( sDesktopFile.c_str(), FILE_ATTRIBUTE_NORMAL );
+ DeleteFileW( sDesktopFile.c_str() );
+
+ SetFileAttributesW( sOfficeMenuFolder.c_str(), FILE_ATTRIBUTE_NORMAL );
+
+ return ERROR_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/setup_native/source/win32/customactions/shellextensions/upgrade.cxx b/setup_native/source/win32/customactions/shellextensions/upgrade.cxx
new file mode 100644
index 000000000..494cfaeda
--- /dev/null
+++ b/setup_native/source/win32/customactions/shellextensions/upgrade.cxx
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "shlxtmsi.hxx"
+
+#include <malloc.h>
+#include <assert.h>
+
+namespace
+{
+ // The provided GUID must be without surrounding '{}'
+ std::wstring GetGuidPart(const std::wstring& guid, int index)
+ {
+ assert((guid.length() == 36) && "No GUID or wrong format!");
+ assert(((index > -1) && (index < 5)) && "Out of range!");
+
+ if (index == 0) return std::wstring(guid.c_str(), 8);
+ if (index == 1) return std::wstring(guid.c_str() + 9, 4);
+ if (index == 2) return std::wstring(guid.c_str() + 14, 4);
+ if (index == 3) return std::wstring(guid.c_str() + 19, 4);
+ if (index == 4) return std::wstring(guid.c_str() + 24, 12);
+
+ return std::wstring();
+ }
+
+ void Swap(wchar_t* p1, wchar_t* p2)
+ {
+ wchar_t tmp = *p1;
+ *p1 = *p2;
+ *p2 = tmp;
+ }
+
+ std::wstring Invert(const std::wstring& str)
+ {
+ wchar_t* buff = static_cast<wchar_t*>(_alloca(str.length()*sizeof(wchar_t)));
+ wcsncpy(buff, str.c_str(), str.length());
+
+ wchar_t* front = buff;
+ wchar_t* back = buff + str.length() - 1;
+
+ while (front < back)
+ Swap(front++, back--);
+
+ return std::wstring(buff, str.length());
+ }
+
+ // Convert the upgrade code (which is a GUID) according
+ // to the way the windows installer does when writing it
+ // to the registry
+ // The first 8 bytes will be inverted, from the last
+ // 8 bytes always the nibbles will be inverted for further
+ // details look in the MSDN under compressed registry keys
+ std::wstring ConvertGuid(const std::wstring& guid)
+ {
+ std::wstring convertedGuid;
+
+ std::wstring part = GetGuidPart(guid, 0);
+ convertedGuid = Invert(part);
+
+ part = GetGuidPart(guid, 1);
+ convertedGuid += Invert(part);
+
+ part = GetGuidPart(guid, 2);
+ convertedGuid += Invert(part);
+
+ part = GetGuidPart(guid, 3);
+ convertedGuid += Invert(std::wstring(part.c_str(), 2));
+ convertedGuid += Invert(std::wstring(part.c_str() + 2, 2));
+
+ part = GetGuidPart(guid, 4);
+ int pos = 0;
+ for (int i = 0; i < 6; i++)
+ {
+ convertedGuid += Invert(std::wstring(part.c_str() + pos, 2));
+ pos += 2;
+ }
+ return convertedGuid;
+ }
+
+ bool IsSetMsiPropertyW(MSIHANDLE handle, const std::wstring& sProperty)
+ {
+ return (GetMsiPropertyW(handle, sProperty).length() > 0);
+ }
+
+ void SetMsiPropertyW(MSIHANDLE handle, const std::wstring& sProperty)
+ {
+ MsiSetPropertyW(handle, sProperty.c_str(), L"1");
+ }
+
+ bool RegistryKeyHasUpgradeSubKey(
+ HKEY hRootKey, const std::wstring& regKey, const std::wstring& upgradeKey)
+ {
+ HKEY hKey;
+ if (RegOpenKeyW(hRootKey, regKey.c_str(), &hKey) == ERROR_SUCCESS)
+ {
+ DWORD nSubKeys;
+ DWORD lLongestSubKey;
+
+ if (RegQueryInfoKeyW(
+ hKey, nullptr, nullptr, nullptr, &nSubKeys, &lLongestSubKey, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS)
+ {
+ LPWSTR buffer = static_cast<LPWSTR>(_alloca((lLongestSubKey + 1)*sizeof(WCHAR)));
+
+ for (DWORD i = 0; i < nSubKeys; i++)
+ {
+ LONG ret = RegEnumKeyW(hKey, i, buffer, lLongestSubKey + 1);
+ if ((ret == ERROR_SUCCESS) && (buffer == upgradeKey))
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+} // namespace
+
+extern "C" __declspec(dllexport) UINT __stdcall SetProductInstallMode(MSIHANDLE handle)
+{
+ std::wstring upgradeCode = GetMsiPropertyW(handle, L"UpgradeCode");
+ upgradeCode = ConvertGuid(std::wstring(upgradeCode.c_str() + 1, upgradeCode.length() - 2));
+
+ // MessageBoxW(NULL, upgradeCode.c_str(), "Debug", MB_OK);
+
+ if (RegistryKeyHasUpgradeSubKey(
+ HKEY_CURRENT_USER,
+ L"Software\\Microsoft\\Installer\\UpgradeCodes",
+ upgradeCode) && IsSetMsiPropertyW(handle, L"ALLUSERS"))
+ {
+ UnsetMsiPropertyW(handle, L"ALLUSERS");
+ // MessageBoxW(NULL, L"ALLUSERS removed", L"DEBUG", MB_OK);
+ }
+ else if (RegistryKeyHasUpgradeSubKey(
+ HKEY_LOCAL_MACHINE,
+ L"Software\\Classes\\Installer\\UpgradeCodes",
+ upgradeCode) && !IsSetMsiPropertyW(handle, L"ALLUSERS"))
+ {
+ SetMsiPropertyW(handle, L"ALLUSERS");
+ // MessageBoxW(NULL, L"ALLUSERS set", L"DEBUG", MB_OK);
+ }
+ return ERROR_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */