1*32b1fd08SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*32b1fd08SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*32b1fd08SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*32b1fd08SAndrew Rist  * distributed with this work for additional information
6*32b1fd08SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*32b1fd08SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*32b1fd08SAndrew Rist  * "License"); you may not use this file except in compliance
9*32b1fd08SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*32b1fd08SAndrew Rist  *
11*32b1fd08SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*32b1fd08SAndrew Rist  *
13*32b1fd08SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*32b1fd08SAndrew Rist  * software distributed under the License is distributed on an
15*32b1fd08SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*32b1fd08SAndrew Rist  * KIND, either express or implied.  See the License for the
17*32b1fd08SAndrew Rist  * specific language governing permissions and limitations
18*32b1fd08SAndrew Rist  * under the License.
19*32b1fd08SAndrew Rist  *
20*32b1fd08SAndrew Rist  *************************************************************/
21*32b1fd08SAndrew Rist 
22*32b1fd08SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir #undef UNICODE
25cdf0e10cSrcweir #undef _UNICODE
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #define _WIN32_WINDOWS 0x0410
28cdf0e10cSrcweir 
29cdf0e10cSrcweir #ifdef _MSC_VER
30cdf0e10cSrcweir #pragma warning(push, 1) /* disable warnings within system headers */
31cdf0e10cSrcweir #endif
32cdf0e10cSrcweir #define WIN32_LEAN_AND_MEAN
33cdf0e10cSrcweir #include <windows.h>
34cdf0e10cSrcweir #include <msiquery.h>
35cdf0e10cSrcweir #ifdef _MSC_VER
36cdf0e10cSrcweir #pragma warning(pop)
37cdf0e10cSrcweir #endif
38cdf0e10cSrcweir 
39cdf0e10cSrcweir #include <malloc.h>
40cdf0e10cSrcweir #include <assert.h>
41cdf0e10cSrcweir 
42cdf0e10cSrcweir #include <tchar.h>
43cdf0e10cSrcweir #include <string>
44cdf0e10cSrcweir 
45cdf0e10cSrcweir using namespace std;
46cdf0e10cSrcweir 
47cdf0e10cSrcweir namespace
48cdf0e10cSrcweir {
49cdf0e10cSrcweir     // The provided GUID must be without surounding '{}'
GetGuidPart(const string & guid,int index)50cdf0e10cSrcweir     string GetGuidPart(const string& guid, int index)
51cdf0e10cSrcweir     {
52cdf0e10cSrcweir         assert((guid.length() == 36) && "No GUID or wrong format!");
53cdf0e10cSrcweir         assert(((index > -1) && (index < 5)) && "Out of range!");
54cdf0e10cSrcweir 
55cdf0e10cSrcweir         if (index == 0) return string(guid.c_str(), 8);
56cdf0e10cSrcweir         if (index == 1) return string(guid.c_str() + 9, 4);
57cdf0e10cSrcweir         if (index == 2) return string(guid.c_str() + 14, 4);
58cdf0e10cSrcweir         if (index == 3) return string(guid.c_str() + 19, 4);
59cdf0e10cSrcweir         if (index == 4) return string(guid.c_str() + 24, 12);
60cdf0e10cSrcweir 
61cdf0e10cSrcweir         return string();
62cdf0e10cSrcweir     }
63cdf0e10cSrcweir 
Swap(char * p1,char * p2)64cdf0e10cSrcweir     void Swap(char* p1, char* p2)
65cdf0e10cSrcweir     {
66cdf0e10cSrcweir         char tmp = *p1;
67cdf0e10cSrcweir         *p1 = *p2;
68cdf0e10cSrcweir         *p2 = tmp;
69cdf0e10cSrcweir     }
70cdf0e10cSrcweir 
Invert(const string & str)71cdf0e10cSrcweir     string Invert(const string& str)
72cdf0e10cSrcweir     {
73cdf0e10cSrcweir         char* buff = reinterpret_cast<char*>(_alloca(str.length()));
74cdf0e10cSrcweir         strncpy(buff, str.c_str(), str.length());
75cdf0e10cSrcweir 
76cdf0e10cSrcweir         char* front = buff;
77cdf0e10cSrcweir         char* back = buff + str.length() - 1;
78cdf0e10cSrcweir 
79cdf0e10cSrcweir         while (front < back)
80cdf0e10cSrcweir             Swap(front++, back--);
81cdf0e10cSrcweir 
82cdf0e10cSrcweir         return string(buff, str.length());
83cdf0e10cSrcweir     }
84cdf0e10cSrcweir 
85cdf0e10cSrcweir     // Convert the upgrade code (which is a GUID) according
86cdf0e10cSrcweir     // to the way the windows installer does when writing it
87cdf0e10cSrcweir     // to the registry
88cdf0e10cSrcweir     // The first 8 bytes will be inverted, from the the last
89cdf0e10cSrcweir     // 8 bytes always the nibbles will be inverted for further
90cdf0e10cSrcweir     // details look in the MSDN under compressed registry keys
ConvertGuid(const string & guid)91cdf0e10cSrcweir     string ConvertGuid(const string& guid)
92cdf0e10cSrcweir     {
93cdf0e10cSrcweir         string convertedGuid;
94cdf0e10cSrcweir 
95cdf0e10cSrcweir         string part = GetGuidPart(guid, 0);
96cdf0e10cSrcweir         convertedGuid = Invert(part);
97cdf0e10cSrcweir 
98cdf0e10cSrcweir         part = GetGuidPart(guid, 1);
99cdf0e10cSrcweir         convertedGuid += Invert(part);
100cdf0e10cSrcweir 
101cdf0e10cSrcweir         part = GetGuidPart(guid, 2);
102cdf0e10cSrcweir         convertedGuid += Invert(part);
103cdf0e10cSrcweir 
104cdf0e10cSrcweir         part = GetGuidPart(guid, 3);
105cdf0e10cSrcweir         convertedGuid += Invert(string(part.c_str(), 2));
106cdf0e10cSrcweir         convertedGuid += Invert(string(part.c_str() + 2, 2));
107cdf0e10cSrcweir 
108cdf0e10cSrcweir         part = GetGuidPart(guid, 4);
109cdf0e10cSrcweir         int pos = 0;
110cdf0e10cSrcweir         for (int i = 0; i < 6; i++)
111cdf0e10cSrcweir         {
112cdf0e10cSrcweir             convertedGuid += Invert(string(part.c_str() + pos, 2));
113cdf0e10cSrcweir             pos += 2;
114cdf0e10cSrcweir         }
115cdf0e10cSrcweir         return convertedGuid;
116cdf0e10cSrcweir     }
117cdf0e10cSrcweir 
GetMsiProperty(MSIHANDLE handle,const string & sProperty)118cdf0e10cSrcweir     string GetMsiProperty(MSIHANDLE handle, const string& sProperty)
119cdf0e10cSrcweir     {
120cdf0e10cSrcweir 	    string	result;
121cdf0e10cSrcweir 	    TCHAR	szDummy[1] = TEXT("");
122cdf0e10cSrcweir 	    DWORD	nChars = 0;
123cdf0e10cSrcweir 
124cdf0e10cSrcweir 	    if (MsiGetProperty(handle, sProperty.c_str(), szDummy, &nChars) == ERROR_MORE_DATA)
125cdf0e10cSrcweir 	    {
126cdf0e10cSrcweir             DWORD nBytes = ++nChars * sizeof(TCHAR);
127cdf0e10cSrcweir             LPTSTR buffer = reinterpret_cast<LPTSTR>(_alloca(nBytes));
128cdf0e10cSrcweir             ZeroMemory( buffer, nBytes );
129cdf0e10cSrcweir             MsiGetProperty(handle, sProperty.c_str(), buffer, &nChars);
130cdf0e10cSrcweir             result = buffer;
131cdf0e10cSrcweir 	    }
132cdf0e10cSrcweir 	    return	result;
133cdf0e10cSrcweir     }
134cdf0e10cSrcweir 
IsSetMsiProperty(MSIHANDLE handle,const string & sProperty)135cdf0e10cSrcweir     inline bool IsSetMsiProperty(MSIHANDLE handle, const string& sProperty)
136cdf0e10cSrcweir     {
137cdf0e10cSrcweir         return (GetMsiProperty(handle, sProperty).length() > 0);
138cdf0e10cSrcweir     }
139cdf0e10cSrcweir 
UnsetMsiProperty(MSIHANDLE handle,const string & sProperty)140cdf0e10cSrcweir     inline void UnsetMsiProperty(MSIHANDLE handle, const string& sProperty)
141cdf0e10cSrcweir     {
142cdf0e10cSrcweir         MsiSetProperty(handle, sProperty.c_str(), NULL);
143cdf0e10cSrcweir     }
144cdf0e10cSrcweir 
SetMsiProperty(MSIHANDLE handle,const string & sProperty)145cdf0e10cSrcweir     inline void SetMsiProperty(MSIHANDLE handle, const string& sProperty)
146cdf0e10cSrcweir     {
147cdf0e10cSrcweir         MsiSetProperty(handle, sProperty.c_str(), TEXT("1"));
148cdf0e10cSrcweir     }
149cdf0e10cSrcweir 
RegistryKeyHasUpgradeSubKey(HKEY hRootKey,const string & regKey,const string & upgradeKey)150cdf0e10cSrcweir     bool RegistryKeyHasUpgradeSubKey(
151cdf0e10cSrcweir         HKEY hRootKey, const string& regKey, const string& upgradeKey)
152cdf0e10cSrcweir     {
153cdf0e10cSrcweir         HKEY hKey;
154cdf0e10cSrcweir         if (RegOpenKey(hRootKey, regKey.c_str(), &hKey) == ERROR_SUCCESS)
155cdf0e10cSrcweir         {
156cdf0e10cSrcweir             DWORD nSubKeys;
157cdf0e10cSrcweir             DWORD lLongestSubKey;
158cdf0e10cSrcweir 
159cdf0e10cSrcweir             if (RegQueryInfoKey(
160cdf0e10cSrcweir                 hKey, NULL, NULL, NULL, &nSubKeys, &lLongestSubKey, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
161cdf0e10cSrcweir             {
162cdf0e10cSrcweir                 LPTSTR buffer = reinterpret_cast<LPTSTR>(_alloca(lLongestSubKey + 1));
163cdf0e10cSrcweir 
164cdf0e10cSrcweir                 for (DWORD i = 0; i < nSubKeys; i++)
165cdf0e10cSrcweir                 {
166cdf0e10cSrcweir                     LONG ret = RegEnumKey(hKey, i, buffer, lLongestSubKey + 1);
167cdf0e10cSrcweir                     if ((ret == ERROR_SUCCESS) && (buffer == upgradeKey))
168cdf0e10cSrcweir                         return true;
169cdf0e10cSrcweir                 }
170cdf0e10cSrcweir             }
171cdf0e10cSrcweir         }
172cdf0e10cSrcweir         return false;
173cdf0e10cSrcweir     }
174cdf0e10cSrcweir } // namespace
175cdf0e10cSrcweir 
SetProductInstallMode(MSIHANDLE handle)176cdf0e10cSrcweir extern "C" UINT __stdcall SetProductInstallMode(MSIHANDLE handle)
177cdf0e10cSrcweir {
178cdf0e10cSrcweir     string upgradeCode = GetMsiProperty(handle, TEXT("UpgradeCode"));
179cdf0e10cSrcweir     upgradeCode = ConvertGuid(string(upgradeCode.c_str() + 1, upgradeCode.length() - 2));
180cdf0e10cSrcweir 
181cdf0e10cSrcweir     //MessageBox(NULL, upgradeCode.c_str(), TEXT("Debug"), MB_OK);
182cdf0e10cSrcweir 
183cdf0e10cSrcweir     if (RegistryKeyHasUpgradeSubKey(
184cdf0e10cSrcweir         HKEY_CURRENT_USER,
185cdf0e10cSrcweir         TEXT("Software\\Microsoft\\Installer\\UpgradeCodes"),
186cdf0e10cSrcweir         upgradeCode) && IsSetMsiProperty(handle, TEXT("ALLUSERS")))
187cdf0e10cSrcweir     {
188cdf0e10cSrcweir         UnsetMsiProperty(handle, TEXT("ALLUSERS"));
189cdf0e10cSrcweir         //MessageBox(NULL, "ALLUSERS removed", "DEBUG", MB_OK);
190cdf0e10cSrcweir     }
191cdf0e10cSrcweir     else if (RegistryKeyHasUpgradeSubKey(
192cdf0e10cSrcweir              HKEY_LOCAL_MACHINE,
193cdf0e10cSrcweir              TEXT("Software\\Classes\\Installer\\UpgradeCodes"),
194cdf0e10cSrcweir              upgradeCode) && !IsSetMsiProperty(handle, TEXT("ALLUSERS")))
195cdf0e10cSrcweir     {
196cdf0e10cSrcweir         SetMsiProperty(handle, TEXT("ALLUSERS"));
197cdf0e10cSrcweir         //MessageBox(NULL, "ALLUSERS set", "DEBUG", MB_OK);
198cdf0e10cSrcweir     }
199cdf0e10cSrcweir     return ERROR_SUCCESS;
200cdf0e10cSrcweir }
201