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