Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "cloud_print/service/win/cloud_print_service.h" | 5 #include "cloud_print/service/win/cloud_print_service.h" |
| 6 | 6 |
| 7 #include <iomanip> | |
| 8 #include <iostream> | |
| 9 | |
| 10 #include "base/at_exit.h" | |
| 11 #include "base/command_line.h" | |
| 12 #include "base/file_path.h" | |
| 13 #include "base/path_service.h" | |
| 7 #include "base/win/scoped_handle.h" | 14 #include "base/win/scoped_handle.h" |
| 8 #include "cloud_print/service/win/resource.h" | 15 #include "cloud_print/service/win/resource.h" |
| 9 | 16 |
| 17 namespace { | |
| 18 | |
| 19 const char kInstallSwitch[] = "install"; | |
| 20 const char kUninstallSwitch[] = "uninstall"; | |
| 21 const char kStartSwitch[] = "start"; | |
| 22 const char kStopSwitch[] = "stop"; | |
| 23 | |
| 24 const char kServiceSwitch[] = "service"; | |
| 25 | |
| 26 const char kUserDataDirSwitch[] = "user-data-dir"; | |
| 27 const char kQuietSwitch[] = "quiet"; | |
| 28 | |
| 10 // The traits class for Windows Service. | 29 // The traits class for Windows Service. |
| 11 class ServiceHandleTraits { | 30 class ServiceHandleTraits { |
| 12 public: | 31 public: |
| 13 typedef SC_HANDLE Handle; | 32 typedef SC_HANDLE Handle; |
| 14 | 33 |
| 15 // Closes the handle. | 34 // Closes the handle. |
| 16 static bool CloseHandle(Handle handle) { | 35 static bool CloseHandle(Handle handle) { |
| 17 return ::CloseServiceHandle(handle) != FALSE; | 36 return ::CloseServiceHandle(handle) != FALSE; |
| 18 } | 37 } |
| 19 | 38 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 32 typedef base::win::GenericScopedHandle<ServiceHandleTraits> ServiceHandle; | 51 typedef base::win::GenericScopedHandle<ServiceHandleTraits> ServiceHandle; |
| 33 | 52 |
| 34 HRESULT HResultFromLastError() { | 53 HRESULT HResultFromLastError() { |
| 35 HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); | 54 HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); |
| 36 // Something already failed if function called. | 55 // Something already failed if function called. |
| 37 if (SUCCEEDED(hr)) | 56 if (SUCCEEDED(hr)) |
| 38 hr = E_FAIL; | 57 hr = E_FAIL; |
| 39 return hr; | 58 return hr; |
| 40 } | 59 } |
| 41 | 60 |
| 61 void InvalidUsage() { | |
| 62 FilePath service_path; | |
| 63 CHECK(PathService::Get(base::FILE_EXE, &service_path)); | |
| 64 | |
| 65 std::cout << "Usage: "; | |
| 66 std::cout << service_path.BaseName().value(); | |
| 67 std::cout << " ["; | |
| 68 std::cout << "["; | |
| 69 std::cout << "["; | |
| 70 std::cout << " -" << kInstallSwitch; | |
| 71 std::cout << " -" << kUserDataDirSwitch << "=DIRECTORY"; | |
| 72 std::cout << " [ -" << kQuietSwitch << " ]"; | |
| 73 std::cout << "]"; | |
| 74 std::cout << "]"; | |
| 75 std::cout << " | -" << kUninstallSwitch; | |
| 76 std::cout << " | -" << kStartSwitch; | |
| 77 std::cout << " | -" << kStopSwitch; | |
| 78 std::cout << " ]\n"; | |
| 79 std::cout << "Manages cloud print windows service.\n\n"; | |
| 80 | |
| 81 static const struct { | |
| 82 const char* name; | |
| 83 const char* description; | |
| 84 } kSwitchHelp[] = { | |
| 85 { kInstallSwitch, "Installs cloud print as service." }, | |
| 86 { kUserDataDirSwitch, "User data directory with \"Service State\" file." }, | |
| 87 { kQuietSwitch, "Fails without questions if something wrong." }, | |
| 88 { kUninstallSwitch, "Uninstalls service." }, | |
| 89 { kStartSwitch, "Starts service. May be combined with installation." }, | |
| 90 { kStopSwitch, "Stops service." }, | |
| 91 }; | |
| 92 | |
| 93 for (size_t i = 0; i < arraysize(kSwitchHelp); ++i) { | |
| 94 std::cout << std::setiosflags(std::ios::left); | |
| 95 std::cout << " -" << std::setw(15) << kSwitchHelp[i].name; | |
| 96 std::cout << kSwitchHelp[i].name << "\n"; | |
|
gene
2012/05/10 22:58:49
.name -> .description
Vitaly Buka (NO REVIEWS)
2012/05/10 23:04:54
Done.
| |
| 97 } | |
| 98 std::cout << "\n"; | |
| 99 } | |
| 100 | |
| 101 } // namespace | |
| 102 | |
| 42 class CloudPrintServiceModule | 103 class CloudPrintServiceModule |
| 43 : public ATL::CAtlServiceModuleT<CloudPrintServiceModule, IDS_SERVICENAME> { | 104 : public ATL::CAtlServiceModuleT<CloudPrintServiceModule, IDS_SERVICENAME> { |
| 44 public: | 105 public: |
| 45 typedef ATL::CAtlServiceModuleT<CloudPrintServiceModule, | 106 typedef ATL::CAtlServiceModuleT<CloudPrintServiceModule, |
| 46 IDS_SERVICENAME> Base; | 107 IDS_SERVICENAME> Base; |
| 47 | 108 |
| 48 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE, | 109 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE, |
| 49 "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}") | 110 "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}") |
| 50 | 111 |
| 51 HRESULT InitializeSecurity() { | 112 HRESULT InitializeSecurity() { |
| 52 // TODO(gene): Check if we need to call CoInitializeSecurity and provide | 113 // TODO(gene): Check if we need to call CoInitializeSecurity and provide |
| 53 // the appropriate security settings for service. | 114 // the appropriate security settings for service. |
| 54 return S_OK; | 115 return S_OK; |
| 55 } | 116 } |
| 56 | 117 |
| 57 // Override to set autostart and start service. | 118 HRESULT Install(const FilePath& user_data_dir) { |
| 58 HRESULT RegisterAppId(bool bService = false) { | 119 // TODO(vitalybuka): consider "lite" version if we don't want unregister |
| 59 HRESULT hr = Base::RegisterAppId(bService); | 120 // printers here. |
| 121 if (!Uninstall()) | |
| 122 return E_FAIL; | |
| 123 | |
| 124 FilePath service_path; | |
| 125 CHECK(PathService::Get(base::FILE_EXE, &service_path)); | |
| 126 CommandLine command_line(service_path); | |
| 127 command_line.AppendSwitch(kServiceSwitch); | |
| 128 command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir); | |
| 129 | |
| 130 ServiceHandle scm; | |
| 131 HRESULT hr = OpenServiceManager(&scm); | |
| 60 if (FAILED(hr)) | 132 if (FAILED(hr)) |
| 61 return hr; | 133 return hr; |
| 62 | 134 |
| 63 ServiceHandle service; | 135 ServiceHandle service( |
| 64 hr = OpenService(SERVICE_CHANGE_CONFIG, &service); | 136 ::CreateService( |
| 65 if (FAILED(hr)) | 137 scm, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS, |
| 66 return hr; | 138 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, |
| 139 command_line.GetCommandLineString().c_str(), NULL, NULL, NULL, | |
| 140 L"NT AUTHORITY\\LocalService", NULL)); | |
| 67 | 141 |
| 68 if (!::ChangeServiceConfig(service, SERVICE_WIN32_OWN_PROCESS, | 142 if (!service.IsValid()) |
| 69 SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, NULL, NULL, NULL, NULL, | |
| 70 L"NT AUTHORITY\\LocalService", NULL, NULL)) { | |
| 71 return HResultFromLastError(); | 143 return HResultFromLastError(); |
| 72 } | |
| 73 | 144 |
| 74 return S_OK; | 145 return S_OK; |
| 75 } | 146 } |
| 76 | 147 |
| 77 // Override to handle service uninstall case manually. | |
| 78 bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode) { | 148 bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode) { |
| 79 if (!Base::ParseCommandLine(lpCmdLine, pnRetCode)) | 149 CHECK(pnRetCode); |
| 80 return false; | 150 CommandLine command_line(CommandLine::NO_PROGRAM); |
| 81 | 151 command_line.ParseFromString(lpCmdLine); |
| 82 const wchar_t tokens[] = L"-/"; | 152 bool is_service = false; |
| 83 *pnRetCode = S_OK; | 153 *pnRetCode = ParseCommandLine(command_line, &is_service); |
| 84 | 154 if (FAILED(*pnRetCode)) { |
| 85 for (const wchar_t* cur = lpCmdLine; cur = FindOneOf(cur, tokens);) { | 155 LOG(ERROR) << "Operation failed. 0x" << std::setw(8) << |
| 86 if (WordCmpI(cur, L"UninstallService") == 0) { | 156 std::setbase(16) << *pnRetCode; |
| 87 if (!Uninstall()) | |
| 88 *pnRetCode = E_FAIL; | |
| 89 return false; | |
| 90 } else if (WordCmpI(cur, L"Start") == 0) { | |
| 91 *pnRetCode = StartService(); | |
| 92 return false; | |
| 93 } else if (WordCmpI(cur, L"Stop") == 0) { | |
| 94 *pnRetCode = StopService(); | |
| 95 return false; | |
| 96 } | |
| 97 } | 157 } |
| 98 return true; | 158 return is_service; |
| 99 } | 159 } |
| 100 | 160 |
| 101 HRESULT PreMessageLoop(int nShowCmd) { | 161 HRESULT PreMessageLoop(int nShowCmd) { |
| 102 HRESULT hr = Base::PreMessageLoop(nShowCmd); | 162 HRESULT hr = Base::PreMessageLoop(nShowCmd); |
| 103 if (FAILED(hr)) | 163 if (FAILED(hr)) |
| 104 return hr; | 164 return hr; |
| 105 | 165 |
| 106 hr = StartConnector(); | 166 hr = StartConnector(); |
| 107 if (FAILED(hr)) | 167 if (FAILED(hr)) |
| 108 return hr; | 168 return hr; |
| 109 | 169 |
| 110 LogEvent(_T("Service started/resumed")); | 170 LogEvent(_T("Service started/resumed")); |
| 111 SetServiceStatus(SERVICE_RUNNING); | 171 SetServiceStatus(SERVICE_RUNNING); |
| 112 return hr; | 172 return hr; |
| 113 } | 173 } |
| 114 | 174 |
| 115 HRESULT PostMessageLoop() { | 175 HRESULT PostMessageLoop() { |
| 116 StopConnector(); | 176 StopConnector(); |
| 117 return Base::PostMessageLoop(); | 177 return Base::PostMessageLoop(); |
| 118 } | 178 } |
| 119 | 179 |
| 120 private: | 180 private: |
| 181 HRESULT ParseCommandLine(const CommandLine& command_line, bool* is_service) { | |
| 182 if (!is_service) | |
| 183 return E_INVALIDARG; | |
| 184 *is_service = false; | |
| 185 | |
| 186 if (command_line.HasSwitch(kStopSwitch)) | |
| 187 return StopService(); | |
| 188 | |
| 189 if (command_line.HasSwitch(kUninstallSwitch)) | |
| 190 return Uninstall() ? S_OK : E_FAIL; | |
| 191 | |
| 192 if (command_line.HasSwitch(kInstallSwitch)) { | |
| 193 if (!command_line.HasSwitch(kUserDataDirSwitch)) { | |
| 194 InvalidUsage(); | |
| 195 return S_FALSE; | |
| 196 } | |
| 197 | |
| 198 FilePath data_dir = command_line.GetSwitchValuePath(kUserDataDirSwitch); | |
| 199 HRESULT hr = Install(data_dir); | |
| 200 if (FAILED(hr) || !command_line.HasSwitch(kStartSwitch)) | |
| 201 return hr; | |
| 202 | |
| 203 return StartService(); | |
|
gene
2012/05/10 22:58:49
if (command_line.HasSwitch(kStartSwitch)) ???
Vitaly Buka (NO REVIEWS)
2012/05/10 23:04:54
at line 200
On 2012/05/10 22:58:49, gene wrote:
| |
| 204 } | |
| 205 | |
| 206 if (command_line.HasSwitch(kStartSwitch)) | |
| 207 return StartService(); | |
| 208 | |
| 209 if (command_line.HasSwitch(kServiceSwitch)) { | |
| 210 user_data_dir_ = command_line.GetSwitchValuePath(kUserDataDirSwitch); | |
| 211 *is_service = true; | |
| 212 return S_OK; | |
| 213 } | |
| 214 | |
| 215 InvalidUsage(); | |
| 216 return S_FALSE; | |
| 217 } | |
| 218 | |
| 219 HRESULT OpenServiceManager(ServiceHandle* service_manager) { | |
| 220 if (!service_manager) | |
| 221 return E_POINTER; | |
| 222 | |
| 223 service_manager->Set(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)); | |
| 224 if (!service_manager->IsValid()) | |
| 225 return HResultFromLastError(); | |
| 226 | |
| 227 return S_OK; | |
| 228 } | |
| 229 | |
| 121 HRESULT OpenService(DWORD access, ServiceHandle* service) { | 230 HRESULT OpenService(DWORD access, ServiceHandle* service) { |
| 122 if (!service) | 231 if (!service) |
| 123 return E_POINTER; | 232 return E_POINTER; |
| 124 | 233 |
| 125 ServiceHandle scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)); | 234 ServiceHandle scm; |
| 126 if (!scm.IsValid()) | 235 HRESULT hr = OpenServiceManager(&scm); |
| 127 return HResultFromLastError(); | 236 if (FAILED(hr)) |
| 237 return hr; | |
| 128 | 238 |
| 129 service->Set(::OpenService(scm, m_szServiceName, access)); | 239 service->Set(::OpenService(scm, m_szServiceName, access)); |
| 130 | 240 |
| 131 if (!service->IsValid()) | 241 if (!service->IsValid()) |
| 132 return HResultFromLastError(); | 242 return HResultFromLastError(); |
| 133 | 243 |
| 134 return S_OK; | 244 return S_OK; |
| 135 } | 245 } |
| 136 | 246 |
| 137 HRESULT StartService() { | 247 HRESULT StartService() { |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 154 return HResultFromLastError(); | 264 return HResultFromLastError(); |
| 155 return S_OK; | 265 return S_OK; |
| 156 } | 266 } |
| 157 | 267 |
| 158 HRESULT StartConnector() { | 268 HRESULT StartConnector() { |
| 159 return S_OK; | 269 return S_OK; |
| 160 } | 270 } |
| 161 | 271 |
| 162 void StopConnector() { | 272 void StopConnector() { |
| 163 } | 273 } |
| 274 | |
| 275 FilePath user_data_dir_; | |
| 164 }; | 276 }; |
| 165 | 277 |
| 166 CloudPrintServiceModule _AtlModule; | 278 CloudPrintServiceModule _AtlModule; |
| 167 | 279 |
| 168 int WINAPI WinMain(__in HINSTANCE hInstance, | 280 int main() { |
| 169 __in HINSTANCE hPrevInstance, | 281 base::AtExitManager at_exit; |
| 170 __in LPSTR lpCmdLine, | 282 return _AtlModule.WinMain(0); |
| 171 __in int nCmdShow) { | |
| 172 return _AtlModule.WinMain(nCmdShow); | |
| 173 } | 283 } |
| 174 | |
| OLD | NEW |