Chromium Code Reviews| Index: cloud_print/service/win/cloud_print_service.cc |
| diff --git a/cloud_print/service/win/cloud_print_service.cc b/cloud_print/service/win/cloud_print_service.cc |
| index 189821587159608192c579688a039152da78894f..67ff0943eb1e9662398d6fc500d4d75e4a1ae701 100644 |
| --- a/cloud_print/service/win/cloud_print_service.cc |
| +++ b/cloud_print/service/win/cloud_print_service.cc |
| @@ -4,9 +4,26 @@ |
| #include "cloud_print/service/win/cloud_print_service.h" |
| +#include <iomanip> |
| +#include <iostream> |
| + |
| +#include "base/at_exit.h" |
| +#include "base/command_line.h" |
| +#include "base/file_path.h" |
| +#include "base/path_service.h" |
| #include "base/win/scoped_handle.h" |
| #include "cloud_print/service/win/resource.h" |
| +namespace { |
| + |
| +const char kInstallSwitch[] = "install"; |
| +const char kUninstallSwitch[] = "uninstall"; |
| +const char kStartSwitch[] = "start"; |
| +const char kStopSwitch[] = "stop"; |
| + |
| +const char kUserDataDirSwitch[] = "user-data-dir"; |
| +const char kQuietSwitch[] = "quiet"; |
| + |
| // The traits class for Windows Service. |
| class ServiceHandleTraits { |
| public: |
| @@ -39,6 +56,51 @@ HRESULT HResultFromLastError() { |
| return hr; |
| } |
| +void InvalidUsage() { |
| + FilePath service_path; |
| + CHECK(PathService::Get(base::FILE_EXE, &service_path)); |
| + |
| + std::cerr << "Usage: "; |
|
gene
2012/05/10 22:11:45
cout?
Vitaly Buka (NO REVIEWS)
2012/05/10 22:49:12
Done.
|
| + std::cerr << service_path.BaseName().value(); |
| + std::cerr << " ["; |
| + std::cerr << "["; |
| + std::cerr << "["; |
| + std::cerr << " -" << kInstallSwitch; |
| + std::cerr << " -" << kUserDataDirSwitch << "=DIRECTORY"; |
| + std::cerr << " [ -" << kQuietSwitch << " ]"; |
| + std::cerr << "]"; |
| + std::cerr << "]"; |
| + std::cerr << " | -" << kUninstallSwitch; |
| + std::cerr << " | -" << kStartSwitch; |
| + std::cerr << " | -" << kStopSwitch; |
| + std::cerr << " ]\n"; |
| + std::cerr << "Manages cloud print service.\n\n"; |
| + |
| + static const char* kSwitchHelp[] = { |
| + kInstallSwitch, |
| + "Installs cloud print as windows service.", |
| + kUserDataDirSwitch, |
| + "User data directory with \"Service State\" file.", |
| + kQuietSwitch, |
| + "Fails without questions if something wrong.", |
| + kUninstallSwitch, |
| + "Uninstalls windows service.", |
| + kStartSwitch, |
| + "Starts windows service. May be combined with installation.", |
| + kStopSwitch, |
| + "Stops windows service.", |
| + }; |
| + |
| + for (size_t i = 0; i < arraysize(kSwitchHelp) / 2; ++i) { |
|
gene
2012/05/10 22:11:45
change this to not use i*2+1
Vitaly Buka (NO REVIEWS)
2012/05/10 22:49:12
Done.
|
| + std::cerr << std::setiosflags(std::ios::left); |
| + std::cerr << " -" << std::setw(15) << kSwitchHelp[i * 2]; |
| + std::cerr << kSwitchHelp[i * 2 + 1] << "\n"; |
| + } |
| + std::cerr << "\n"; |
| +} |
| + |
| +} // namespace |
| + |
| class CloudPrintServiceModule |
| : public ATL::CAtlServiceModuleT<CloudPrintServiceModule, IDS_SERVICENAME> { |
| public: |
| @@ -54,48 +116,51 @@ class CloudPrintServiceModule |
| return S_OK; |
| } |
| - // Override to set autostart and start service. |
| - HRESULT RegisterAppId(bool bService = false) { |
| - HRESULT hr = Base::RegisterAppId(bService); |
| - if (FAILED(hr)) |
| - return hr; |
| + HRESULT Install(const FilePath& user_data_dir) { |
| + if (!Uninstall()) |
|
gene
2012/05/10 22:11:45
We probably should not uninstall here, but rather
Vitaly Buka (NO REVIEWS)
2012/05/10 22:49:12
Done.
|
| + return E_FAIL; |
| - ServiceHandle service; |
| - hr = OpenService(SERVICE_CHANGE_CONFIG, &service); |
| + if (user_data_dir.empty()) { |
|
gene
2012/05/10 22:11:45
you can probably check this condition in the Parse
Vitaly Buka (NO REVIEWS)
2012/05/10 22:49:12
Done.
|
| + std::cerr << "Invalid value --user_data_dir=" << user_data_dir.value() << |
| + "\n"; |
| + return E_INVALIDARG; |
| + } |
| + |
| + FilePath service_path; |
| + CHECK(PathService::Get(base::FILE_EXE, &service_path)); |
| + CommandLine command_line(service_path); |
| + command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir); |
| + |
| + ServiceHandle scm; |
| + HRESULT hr = OpenServiceManager(&scm); |
| if (FAILED(hr)) |
| return hr; |
| - if (!::ChangeServiceConfig(service, SERVICE_WIN32_OWN_PROCESS, |
| - SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, NULL, NULL, NULL, NULL, |
| - L"NT AUTHORITY\\LocalService", NULL, NULL)) { |
| + ServiceHandle service( |
| + ::CreateService( |
| + scm, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS, |
| + SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, |
| + command_line.GetCommandLineString().c_str(), NULL, NULL, NULL, |
| + L"NT AUTHORITY\\LocalService", NULL)); |
| + |
| + if (!service.IsValid()) |
| return HResultFromLastError(); |
| - } |
| return S_OK; |
| } |
| - // Override to handle service uninstall case manually. |
| bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode) { |
| - if (!Base::ParseCommandLine(lpCmdLine, pnRetCode)) |
| - return false; |
| - |
| - const wchar_t tokens[] = L"-/"; |
| - *pnRetCode = S_OK; |
| - |
| - for (const wchar_t* cur = lpCmdLine; cur = FindOneOf(cur, tokens);) { |
| - if (WordCmpI(cur, L"UninstallService") == 0) { |
| - if (!Uninstall()) |
| - *pnRetCode = E_FAIL; |
| - return false; |
| - } else if (WordCmpI(cur, L"Start") == 0) { |
| - *pnRetCode = StartService(); |
| - return false; |
| - } else if (WordCmpI(cur, L"Stop") == 0) { |
| - *pnRetCode = StopService(); |
| - return false; |
| - } |
| + CHECK(pnRetCode); |
| + CommandLine command_line(CommandLine::NO_PROGRAM); |
| + command_line.ParseFromString(lpCmdLine); |
| + *pnRetCode = ParseCommandLine(command_line); |
| + if (*pnRetCode == S_OK) |
| + return true; // Run as service. |
| + if (FAILED(*pnRetCode)) { |
| + LOG(ERROR) << "Operation failed. 0x" << std::setw(8) << |
| + std::setbase(16) << *pnRetCode; |
| } |
| - return true; |
| + return false; // Exit process. |
| } |
| HRESULT PreMessageLoop(int nShowCmd) { |
| @@ -118,13 +183,70 @@ class CloudPrintServiceModule |
| } |
| private: |
| + // Returns S_OK if it's called as service. |
| + // Returns S_FALSE on success or usage error. |
| + // Returns error code for any other error. |
| + HRESULT ParseCommandLine(const CommandLine& command_line) { |
| + HRESULT hr = E_INVALIDARG; |
| + if (command_line.HasSwitch(kStopSwitch)) { |
| + hr = StopService(); |
|
gene
2012/05/10 22:11:45
I think we shall return here no matter what StopSe
Vitaly Buka (NO REVIEWS)
2012/05/10 22:49:12
Done.
|
| + if (FAILED(hr)) |
| + return hr; |
| + } |
| + |
| + if (command_line.HasSwitch(kUninstallSwitch)) { |
| + hr = Uninstall() ? S_OK : E_FAIL; |
| + if (FAILED(hr)) |
|
gene
2012/05/10 22:11:45
Same as above here.
Vitaly Buka (NO REVIEWS)
2012/05/10 22:49:12
Done.
|
| + return hr; |
| + } |
| + |
| + if (command_line.HasSwitch(kInstallSwitch)) { |
| + if (!command_line.HasSwitch(kUserDataDirSwitch)) { |
| + InvalidUsage(); |
| + return S_FALSE; |
| + } |
| + |
| + FilePath data_dir = command_line.GetSwitchValuePath(kUserDataDirSwitch); |
| + hr = Install(data_dir); |
| + if (FAILED(hr)) |
| + return hr; |
| + } |
| + |
| + if (command_line.HasSwitch(kStartSwitch)) { |
| + hr = StartService(); |
| + if (FAILED(hr)) |
| + return hr; |
| + } |
| + |
| + // No main switch matched, so it was called by SCM or just usage error. |
| + if (hr == E_INVALIDARG) { |
| + if (command_line.HasSwitch(kUserDataDirSwitch)) |
| + return S_OK; |
| + InvalidUsage(); |
| + } |
| + |
| + return S_FALSE; |
| + } |
| + |
| + HRESULT OpenServiceManager(ServiceHandle* service_manager) { |
| + if (!service_manager) |
| + return E_POINTER; |
| + |
| + service_manager->Set(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)); |
| + if (!service_manager->IsValid()) |
| + return HResultFromLastError(); |
| + |
| + return S_OK; |
| + } |
| + |
| HRESULT OpenService(DWORD access, ServiceHandle* service) { |
| if (!service) |
| return E_POINTER; |
| - ServiceHandle scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)); |
| - if (!scm.IsValid()) |
| - return HResultFromLastError(); |
| + ServiceHandle scm; |
| + HRESULT hr = OpenServiceManager(&scm); |
| + if (FAILED(hr)) |
| + return hr; |
| service->Set(::OpenService(scm, m_szServiceName, access)); |
| @@ -165,10 +287,7 @@ class CloudPrintServiceModule |
| CloudPrintServiceModule _AtlModule; |
| -int WINAPI WinMain(__in HINSTANCE hInstance, |
| - __in HINSTANCE hPrevInstance, |
| - __in LPSTR lpCmdLine, |
| - __in int nCmdShow) { |
| - return _AtlModule.WinMain(nCmdShow); |
| +int main() { |
| + base::AtExitManager at_exit; |
| + return _AtlModule.WinMain(0); |
| } |
| - |