diff options
author | kuchhal@chromium.org <kuchhal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-16 00:42:48 +0000 |
---|---|---|
committer | kuchhal@chromium.org <kuchhal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-16 00:42:48 +0000 |
commit | 66a4ff2f884413f935ae72a8e505c1f756381fc4 (patch) | |
tree | 7a470d6d204420f1e67221100e93da8539d256b3 /chrome | |
parent | 8d2335f413f55bd140a3dad2286620a44df84ba9 (diff) | |
download | chromium_src-66a4ff2f884413f935ae72a8e505c1f756381fc4.zip chromium_src-66a4ff2f884413f935ae72a8e505c1f756381fc4.tar.gz chromium_src-66a4ff2f884413f935ae72a8e505c1f756381fc4.tar.bz2 |
* Launch Chrome in non-elevated mode.
Currently Google Update LaunchCmdLine launches command with the callers token. To launch non-elevated we try to get the token of explorer.exe and impersonate it (same as what Google Update does in another place).
Also fix a bug in Compatibility check function. We should exit if we fail to load advapi32.dll and not if we succeed.
I am still doing testing with various builds of Google Update.
Review URL: http://codereview.chromium.org/12970
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@7023 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rwxr-xr-x | chrome/chrome.sln | 6 | ||||
-rwxr-xr-x | chrome/installer/gcapi/gcapi.cc | 257 | ||||
-rwxr-xr-x | chrome/installer/gcapi/gcapi.h | 8 | ||||
-rw-r--r-- | chrome/installer/gcapi/gcapi.vsprops | 8 | ||||
-rwxr-xr-x | chrome/installer/gcapi/gcapi_dll.vcproj | 4 | ||||
-rwxr-xr-x | chrome/installer/gcapi/gcapi_lib.vcproj | 4 | ||||
-rwxr-xr-x | chrome/installer/gcapi/gcapi_test.cc | 1 |
7 files changed, 202 insertions, 86 deletions
diff --git a/chrome/chrome.sln b/chrome/chrome.sln index 300d84d..7e3a63a 100755 --- a/chrome/chrome.sln +++ b/chrome/chrome.sln @@ -1925,12 +1925,18 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gcapi_lib", "installer\gcap Debug.AspNetCompiler.Debug = "True"
Release.AspNetCompiler.Debug = "False"
EndProjectSection
+ ProjectSection(ProjectDependencies) = postProject
+ {4052059A-D72B-4183-B5C2-9D1B099E9E35} = {4052059A-D72B-4183-B5C2-9D1B099E9E35}
+ EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gcapi_dll", "installer\gcapi\gcapi_dll.vcproj", "{B802A2FE-E4E2-4F5A-905A-D5128875C954}"
ProjectSection(WebsiteProperties) = preProject
Debug.AspNetCompiler.Debug = "True"
Release.AspNetCompiler.Debug = "False"
EndProjectSection
+ ProjectSection(ProjectDependencies) = postProject
+ {4052059A-D72B-4183-B5C2-9D1B099E9E35} = {4052059A-D72B-4183-B5C2-9D1B099E9E35}
+ EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gcapi_test", "installer\gcapi\gcapi_test.vcproj", "{B64B396B-8EF1-4B6B-A07E-48D40EB961AB}"
ProjectSection(WebsiteProperties) = preProject
diff --git a/chrome/installer/gcapi/gcapi.cc b/chrome/installer/gcapi/gcapi.cc index 41e5d11..6f6c600 100755 --- a/chrome/installer/gcapi/gcapi.cc +++ b/chrome/installer/gcapi/gcapi.cc @@ -4,13 +4,20 @@ #include "chrome/installer/gcapi/gcapi.h" +#include <atlbase.h> +#include <atlcom.h> #include <windows.h> +#include <sddl.h> #include <stdlib.h> #include <strsafe.h> +#include <tlhelp32.h> + +#include "google_update_idl.h" namespace { -const wchar_t kChromeRegKey[] = L"Software\\Google\\Update\\Clients\\{8A69D345-D564-463c-AFF1-A69D9E530F96}"; +const wchar_t kChromeRegClientsKey[] = L"Software\\Google\\Update\\Clients\\{8A69D345-D564-463c-AFF1-A69D9E530F96}"; +const wchar_t kChromeRegClientStateKey[] = L"Software\\Google\\Update\\ClientState\\{8A69D345-D564-463c-AFF1-A69D9E530F96}"; const wchar_t kChromeRegLaunchCmd[] = L"InstallerSuccessLaunchCmdLine"; const wchar_t kChromeRegLastLaunchCmd[] = L"LastInstallerSuccessLaunchCmdLine"; const wchar_t kChromeRegVersion[] = L"pv"; @@ -20,7 +27,7 @@ const wchar_t kNoChromeOfferUntil[] = L"SOFTWARE\\Google\\No Chrome Offer Until" // equal or less than today's date represented in YYYYMMDD form. void CleanUpRegistryValues() { HKEY key = NULL; - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, kNoChromeOfferUntil, + if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, kNoChromeOfferUntil, 0, KEY_ALL_ACCESS, &key) != ERROR_SUCCESS) return; @@ -34,12 +41,12 @@ void CleanUpRegistryValues() { // First, remove any value whose type is not DWORD index = 0; value_len = 0; - while (RegEnumValue(key, index, value_name, &value_name_len, + while (::RegEnumValue(key, index, value_name, &value_name_len, NULL, &value_type, NULL, &value_len) == ERROR_SUCCESS) { if (value_type == REG_DWORD) index++; else - RegDeleteValue(key, value_name); + ::RegDeleteValue(key, value_name); value_name_len = _countof(value_name); value_type = REG_DWORD; @@ -48,18 +55,18 @@ void CleanUpRegistryValues() { // Get today's date, and format it as YYYYMMDD numeric value SYSTEMTIME now; - GetLocalTime(&now); + ::GetLocalTime(&now); DWORD expiration_date = now.wYear * 10000 + now.wMonth * 100 + now.wDay; // Remove any DWORD value smaller than the number represent the // expiration date (YYYYMMDD) index = 0; - while (RegEnumValue(key, index, value_name, &value_name_len, + while (::RegEnumValue(key, index, value_name, &value_name_len, NULL, &value_type, (LPBYTE) &value_data, &value_len) == ERROR_SUCCESS) { if (value_type == REG_DWORD && value_data > expiration_date) index++; // move on to next value else - RegDeleteValue(key, value_name); // delete this value + ::RegDeleteValue(key, value_name); // delete this value value_name_len = _countof(value_name); value_type = REG_DWORD; @@ -67,7 +74,7 @@ void CleanUpRegistryValues() { value_len = sizeof(DWORD); } - RegCloseKey(key); + ::RegCloseKey(key); } // Return the company name specified in the file version info resource. @@ -76,21 +83,21 @@ bool GetCompanyName(const wchar_t* filename, wchar_t* buffer, DWORD out_len) { DWORD handle = 0; DWORD buffer_size = 0; - buffer_size = GetFileVersionInfoSize(filename, &handle); + buffer_size = ::GetFileVersionInfoSize(filename, &handle); // Cannot stats the file or our buffer size is too small (very unlikely) if (buffer_size == 0 || buffer_size > _countof(file_version_info)) return false; buffer_size = _countof(file_version_info); memset(file_version_info, 0, buffer_size); - if (!GetFileVersionInfo(filename, handle, buffer_size, file_version_info)) + if (!::GetFileVersionInfo(filename, handle, buffer_size, file_version_info)) return false; DWORD data_len = 0; LPVOID data = NULL; // Retrieve the language and codepage code if exists. buffer_size = 0; - if (!VerQueryValue(file_version_info, TEXT("\\VarFileInfo\\Translation"), + if (!::VerQueryValue(file_version_info, TEXT("\\VarFileInfo\\Translation"), reinterpret_cast<LPVOID *>(&data), reinterpret_cast<UINT *>(&data_len))) return false; if (data_len != 4) @@ -107,7 +114,7 @@ bool GetCompanyName(const wchar_t* filename, wchar_t* buffer, DWORD out_len) { (lang & 0xff0000)>>16); data_len = 0; - if (!VerQueryValue(file_version_info, info_name, + if (!::VerQueryValue(file_version_info, info_name, reinterpret_cast<LPVOID *>(&data), reinterpret_cast<UINT *>(&data_len))) return false; if (data_len <= 0 || data_len >= out_len) @@ -127,7 +134,7 @@ bool CanReOfferChrome() { // If we cannot retrieve the version info of the executable or company // name, we allow the Chrome to be offered because there is no past // history to be found. - if (GetModuleFileName(NULL, filename, MAX_PATH) == 0) + if (::GetModuleFileName(NULL, filename, MAX_PATH) == 0) return true; if (!GetCompanyName(filename, company, sizeof(company))) return true; @@ -135,11 +142,11 @@ bool CanReOfferChrome() { bool can_re_offer = true; DWORD disposition = 0; HKEY key = NULL; - if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, kNoChromeOfferUntil, + if (::RegCreateKeyEx(HKEY_LOCAL_MACHINE, kNoChromeOfferUntil, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &key, &disposition) == ERROR_SUCCESS) { // Cannot re-offer, if the timer already exists and is not expired yet - if (RegQueryValueEx(key, company, 0, 0, 0, 0) == ERROR_SUCCESS) { + if (::RegQueryValueEx(key, company, 0, 0, 0, 0) == ERROR_SUCCESS) { // The expired timers were already removed in CleanUpRegistryValues. // So if the key is not found, we can offer the Chrome. can_re_offer = false; @@ -147,17 +154,17 @@ bool CanReOfferChrome() { // Set expiration date for offer as six months from today, // represented as a YYYYMMDD numeric value SYSTEMTIME timer; - GetLocalTime(&timer); + ::GetLocalTime(&timer); timer.wMonth = timer.wMonth + 6; if (timer.wMonth > 12) { timer.wMonth = timer.wMonth - 12; timer.wYear = timer.wYear + 1; } DWORD value = timer.wYear * 10000 + timer.wMonth * 100 + timer.wDay; - RegSetValueEx(key, company, 0, REG_DWORD, (LPBYTE)&value, sizeof(DWORD)); + ::RegSetValueEx(key, company, 0, REG_DWORD, (LPBYTE)&value, sizeof(DWORD)); } - RegCloseKey(key); + ::RegCloseKey(key); } return can_re_offer; @@ -183,7 +190,7 @@ bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, bool IsChromeInstalled(HKEY root_key) { wchar_t version[64]; size_t size = _countof(version); - if (ReadValueFromRegistry(root_key, kChromeRegKey, kChromeRegVersion, + if (ReadValueFromRegistry(root_key, kChromeRegClientsKey, kChromeRegVersion, version, &size)) return true; return false; @@ -210,45 +217,23 @@ bool IsWinXPSp1OrLater(bool* is_vista_or_later) { return false; // Windows 2000, WinXP no Service Pack } +// Note this function should not be called on old Windows versions where these +// Windows API are not available. We always invoke this function after checking +// that current OS is Vista or later. bool VerifyAdminGroup() { - typedef BOOL (WINAPI *ALLOCATEANDINITIALIZESIDPROC)( - PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount, - DWORD nSubAuthority0, DWORD nSubAuthority1, DWORD nSubAuthority2, - DWORD nSubAuthority3, DWORD nSubAuthority4, DWORD nSubAuthority5, - DWORD nSubAuthority6, DWORD nSubAuthority7, PSID *pSid); - typedef BOOL (WINAPI *CHECKTOKENMEMBERSHIPPROC)(HANDLE TokenHandle, - PSID SidToCheck, - PBOOL IsMember); - typedef PVOID (WINAPI *FREESIDPROC)(PSID pSid); - // Load our admin-checking functions dynamically. - HMODULE advapi_library = LoadLibrary(L"advapi32.dll"); - if (advapi_library != NULL) - return false; - - ALLOCATEANDINITIALIZESIDPROC allocSid = - reinterpret_cast<ALLOCATEANDINITIALIZESIDPROC>(GetProcAddress( - advapi_library, "AllocateAndInitializeSid")); - CHECKTOKENMEMBERSHIPPROC checkToken = - reinterpret_cast<CHECKTOKENMEMBERSHIPPROC>(GetProcAddress( - advapi_library, "CheckTokenMembership")); - FREESIDPROC freeSid = - reinterpret_cast<FREESIDPROC>(GetProcAddress( - advapi_library, "FreeSid")); - bool result = false; - if (allocSid != NULL && checkToken != NULL && freeSid != NULL) { - SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; - PSID Group; - BOOL check = allocSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, - DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &Group); - if (check) { - if (!checkToken(NULL, Group, &check)) - check = FALSE; - freeSid(Group); - } - result = !!check; + SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; + PSID Group; + BOOL check = ::AllocateAndInitializeSid(&NtAuthority, 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, + 0, 0, 0, + &Group); + if (check) { + if (!::CheckTokenMembership(NULL, Group, &check)) + check = FALSE; } - FreeLibrary(advapi_library); - return result; + ::FreeSid(Group); + return (check == TRUE); } bool VerifyHKLMAccess(const wchar_t* sub_key) { @@ -258,10 +243,10 @@ bool VerifyHKLMAccess(const wchar_t* sub_key) { DWORD disposition = 0; HKEY key = NULL; - if (RegCreateKeyEx(root, sub_key, 0, NULL, - REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, - &key, &disposition) == ERROR_SUCCESS) { - if (RegSetValueEx(key, str, 0, REG_SZ, (LPBYTE)str, + if (::RegCreateKeyEx(root, sub_key, 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, + &key, &disposition) == ERROR_SUCCESS) { + if (::RegSetValueEx(key, str, 0, REG_SZ, (LPBYTE)str, (DWORD)lstrlen(str)) == ERROR_SUCCESS) { result = true; RegDeleteValue(key, str); @@ -276,6 +261,59 @@ bool VerifyHKLMAccess(const wchar_t* sub_key) { return result; } + +bool IsRunningElevated() { + // This method should be called only for Vista or later. + bool is_vista_or_later = false; + IsWinXPSp1OrLater(&is_vista_or_later); + if (!is_vista_or_later || !VerifyAdminGroup()) + return false; + + HANDLE process_token; + if (!::OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &process_token)) + return false; + + TOKEN_ELEVATION_TYPE elevation_type = TokenElevationTypeDefault; + DWORD size_returned = 0; + if (!::GetTokenInformation(process_token, TokenElevationType, + &elevation_type, sizeof(elevation_type), + &size_returned)) { + ::CloseHandle(process_token); + return false; + } + + ::CloseHandle(process_token); + return (elevation_type == TokenElevationTypeFull); +} + +bool GetUserIdForProcess(size_t pid, wchar_t** user_sid) { + HANDLE process_handle = ::OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, pid); + if (process_handle == NULL) + return false; + + HANDLE process_token; + bool result = false; + if (::OpenProcessToken(process_handle, TOKEN_QUERY, &process_token)) { + DWORD size = 0; + ::GetTokenInformation(process_token, TokenUser, NULL, 0, &size); + if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER || + ::GetLastError() == ERROR_SUCCESS) { + DWORD actual_size = 0; + BYTE* token_user = new BYTE[size]; + if ((::GetTokenInformation(process_token, TokenUser, token_user, size, + &actual_size)) && + (actual_size <= size)) { + PSID sid = reinterpret_cast<TOKEN_USER*>(token_user)->User.Sid; + if (::ConvertSidToStringSid(sid, user_sid)) + result = true; + } + delete[] token_user; + } + ::CloseHandle(process_token); + } + ::CloseHandle(process_handle); + return result; +} } // namespace #pragma comment(linker, "/EXPORT:GoogleChromeCompatibilityCheck=_GoogleChromeCompatibilityCheck@4,PRIVATE") @@ -293,9 +331,11 @@ DLLEXPORT BOOL __stdcall GoogleChromeCompatibilityCheck(DWORD *reasons) { if (IsChromeInstalled(HKEY_CURRENT_USER)) local_reasons |= GCCC_ERROR_USERLEVELALREADYPRESENT; - if (!VerifyHKLMAccess(kChromeRegKey)) { + if (!VerifyHKLMAccess(kChromeRegClientsKey)) { local_reasons |= GCCC_ERROR_ACCESSDENIED; } else if (is_vista_or_later && !VerifyAdminGroup()) { + // For Vista or later check for elevation since even for admin user we could + // be running in non-elevated mode. We require integrity level High. local_reasons |= GCCC_ERROR_INTEGRITYLEVEL; } @@ -312,33 +352,94 @@ DLLEXPORT BOOL __stdcall GoogleChromeCompatibilityCheck(DWORD *reasons) { return (*reasons == 0); } -#pragma comment(linker, "/EXPORT:LaunchGoogleChrome=_LaunchGoogleChrome@4,PRIVATE") -DLLEXPORT BOOL __stdcall LaunchGoogleChrome(HANDLE *proc_handle) { +#pragma comment(linker, "/EXPORT:LaunchGoogleChrome=_LaunchGoogleChrome@0,PRIVATE") +DLLEXPORT BOOL __stdcall LaunchGoogleChrome() { wchar_t launch_cmd[MAX_PATH]; size_t size = _countof(launch_cmd); - if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kChromeRegKey, + if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kChromeRegClientStateKey, kChromeRegLastLaunchCmd, launch_cmd, &size)) { size = _countof(launch_cmd); - if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kChromeRegKey, + if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kChromeRegClientStateKey, kChromeRegLaunchCmd, launch_cmd, &size)) { return false; } } - STARTUPINFOW si = {sizeof(si)}; - PROCESS_INFORMATION pi = {0}; - if (!CreateProcess(NULL, const_cast<wchar_t*>(launch_cmd), NULL, NULL, - FALSE, 0, NULL, NULL, &si, &pi)) + HRESULT hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + if (hr != S_OK) { + if (hr == S_FALSE) + ::CoUninitialize(); + return false; + } + + if (::CoInitializeSecurity(NULL, -1, NULL, NULL, + RPC_C_AUTHN_LEVEL_PKT_PRIVACY, + RPC_C_IMP_LEVEL_IDENTIFY, NULL, + EOAC_DYNAMIC_CLOAKING, NULL) != S_OK) { + ::CoUninitialize(); return false; + } - // Handles must be closed or they will leak - CloseHandle(pi.hThread); + bool impersonation_success = false; + if (IsRunningElevated()) { + wchar_t* curr_proc_sid; + if (!GetUserIdForProcess(GetCurrentProcessId(), &curr_proc_sid)) { + ::CoUninitialize(); + return false; + } - // If the caller wants the process handle, we won't close it. - if (proc_handle) { - *proc_handle = pi.hProcess; - } else { - CloseHandle(pi.hProcess); + DWORD pid = 0; + ::GetWindowThreadProcessId(::GetShellWindow(), &pid); + if (pid <= 0) { + ::LocalFree(curr_proc_sid); + ::CoUninitialize(); + return false; + } + + wchar_t* exp_proc_sid; + if (GetUserIdForProcess(pid, &exp_proc_sid)) { + if (_wcsicmp(curr_proc_sid, exp_proc_sid) == 0) { + HANDLE process_handle = ::OpenProcess( + PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, TRUE, pid); + if (process_handle != NULL) { + HANDLE process_token; + HANDLE user_token; + if (::OpenProcessToken(process_handle, TOKEN_DUPLICATE | TOKEN_QUERY, + &process_token) && + ::DuplicateTokenEx(process_token, + TOKEN_IMPERSONATE | TOKEN_QUERY | + TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE, + NULL, SecurityImpersonation, + TokenPrimary, &user_token) && + (::ImpersonateLoggedOnUser(user_token) != 0)) { + impersonation_success = true; + } + ::CloseHandle(user_token); + ::CloseHandle(process_token); + ::CloseHandle(process_handle); + } + } + ::LocalFree(exp_proc_sid); + } + + ::LocalFree(curr_proc_sid); + if (!impersonation_success) { + ::CoUninitialize(); + return false; + } } - return true; -}
\ No newline at end of file + + bool ret = false; + CComPtr<IProcessLauncher> ipl; + if (!FAILED(ipl.CoCreateInstance(__uuidof(ProcessLauncherClass), NULL, + CLSCTX_LOCAL_SERVER))) { + if (!FAILED(ipl->LaunchCmdLine(launch_cmd))) + ret = true; + ipl.Release(); + } + + if (impersonation_success) + ::RevertToSelf(); + ::CoUninitialize(); + return ret; +} diff --git a/chrome/installer/gcapi/gcapi.h b/chrome/installer/gcapi/gcapi.h index da56b23..7848e40 100755 --- a/chrome/installer/gcapi/gcapi.h +++ b/chrome/installer/gcapi/gcapi.h @@ -23,10 +23,10 @@ extern "C" { // for the reason, you can pass NULL for reasons. DLLEXPORT BOOL __stdcall GoogleChromeCompatibilityCheck(DWORD *reasons); -// This function launches Google Chrome after a successful install. If -// proc_handle is not NULL, the process handle of the newly created process -// will be returned. -DLLEXPORT BOOL __stdcall LaunchGoogleChrome(HANDLE* proc_handle); +// This function launches Google Chrome after a successful install. Make +// sure COM library is NOT initalized before you call this function (so if +// you called CoInitialize, call CoUninitialize before calling this function). +DLLEXPORT BOOL __stdcall LaunchGoogleChrome(); // Funtion pointer type declarations to use with GetProcAddress. typedef BOOL (__stdcall * GCCC_CompatibilityCheck)(DWORD *); diff --git a/chrome/installer/gcapi/gcapi.vsprops b/chrome/installer/gcapi/gcapi.vsprops new file mode 100644 index 0000000..d59c7a8 --- /dev/null +++ b/chrome/installer/gcapi/gcapi.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="gcapi" + InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\google_update\using_google_update.vsprops" + > +</VisualStudioPropertySheet> diff --git a/chrome/installer/gcapi/gcapi_dll.vcproj b/chrome/installer/gcapi/gcapi_dll.vcproj index ac09788..2a15fa6 100755 --- a/chrome/installer/gcapi/gcapi_dll.vcproj +++ b/chrome/installer/gcapi/gcapi_dll.vcproj @@ -17,7 +17,7 @@ <Configuration
Name="Debug|Win32"
ConfigurationType="2"
- InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\debug.vsprops"
+ InheritedPropertySheets=".\gcapi.vsprops;$(SolutionDir)..\build\debug.vsprops"
>
<Tool
Name="VCCLCompilerTool"
@@ -29,7 +29,7 @@ <Configuration
Name="Release|Win32"
ConfigurationType="2"
- InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\release.vsprops"
+ InheritedPropertySheets=".\gcapi.vsprops;$(SolutionDir)..\build\release.vsprops"
>
<Tool
Name="VCCLCompilerTool"
diff --git a/chrome/installer/gcapi/gcapi_lib.vcproj b/chrome/installer/gcapi/gcapi_lib.vcproj index 2524db7..75da6c5 100755 --- a/chrome/installer/gcapi/gcapi_lib.vcproj +++ b/chrome/installer/gcapi/gcapi_lib.vcproj @@ -17,7 +17,7 @@ <Configuration
Name="Debug|Win32"
ConfigurationType="4"
- InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\debug.vsprops"
+ InheritedPropertySheets=".\gcapi.vsprops;$(SolutionDir)..\build\debug.vsprops"
>
<Tool
Name="VCCLCompilerTool"
@@ -29,7 +29,7 @@ <Configuration
Name="Release|Win32"
ConfigurationType="4"
- InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\release.vsprops"
+ InheritedPropertySheets=".\gcapi.vsprops;$(SolutionDir)..\build\release.vsprops"
>
<Tool
Name="VCCLCompilerTool"
diff --git a/chrome/installer/gcapi/gcapi_test.cc b/chrome/installer/gcapi/gcapi_test.cc index 78939497..8d3608c 100755 --- a/chrome/installer/gcapi/gcapi_test.cc +++ b/chrome/installer/gcapi/gcapi_test.cc @@ -38,4 +38,5 @@ void call_dynamically() { int main(int argc, char* argv[]) { call_dynamically(); call_statically(); + printf("LaunchChrome returned %d.\n", LaunchGoogleChrome()); } |