سؤال

كيف يمكنني إرسال الأمر إلى خدمة Windows من C ++؟ رمز .NET المكافئ هو:

ServiceController sc = new ServiceController("MyService");
sc.ExecuteCommand(255);
هل كانت مفيدة؟

المحلول

من C ++ الأصلي ، ستحتاج إلى:

  1. افتح مقبضًا لمدير التحكم في الخدمة ،
  2. استخدم مدير التحكم في الخدمة للحصول على مقبض خدمة للخدمة التي تريد التحكم فيها ،
  3. إرسال رمز تحكم أو رموز إلى الخدمة ، و
  4. أغلق المقابض المفتوحة في الخطوات 1 و 2.

على سبيل المثال ، يعيد هذا الرمز تشغيل خدمة التزامن الوقت. أولاً ، أقوم بإنشاء فئة غلاف لمقابض الخدمة ، لإغلاقها تلقائيًا عند مغادرة الكتلة.

class CSC_HANDLE
{
public:
 CSC_HANDLE(SC_HANDLE h) : m_h(h) { }
 ~CSC_HANDLE() { ::CloseServiceHandle(m_h); }
 operator SC_HANDLE () { return m_h; }
private:
 SC_HANDLE m_h;
};

ثم أفتح مدير التحكم في الخدمة (باستخدام OpenScmanager ()) والخدمة التي أريد السيطرة عليها. لاحظ أن معلمة DWDesiredAccess OpenService () يجب أن تتضمن أذونات لكل عنصر تحكم أريد إرساله ، أو تفشل وظائف التحكم ذات الصلة.

BOOL RestartTimeService()
{
    CSC_HANDLE hSCM(::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, GENERIC_READ));
    if (NULL == hSCM) return FALSE;

    CSC_HANDLE hW32Time(::OpenService(hSCM, L"W32Time", SERVICE_START | SERVICE_STOP | SERVICE_QUERY_STATUS));
    if (NULL == hW32Time) return FALSE;

لإيقاف الخدمة ، أستخدمها ControlService () لإرسال رمز service_control_stop ، ثم تحقق من قيمة الإرجاع للتأكد من نجاح الأمر. إذا تم الإبلاغ عن أي خطأ بخلاف error_service_not_active ، أفترض أن بدء الخدمة لن تنجح.

    SERVICE_STATUS ss = { 0 };
    ::SetLastError(0);
    BOOL success = ::ControlService(hW32Time, SERVICE_CONTROL_STOP, &ss);
    if (!success)
    {
        DWORD le = ::GetLastError();
        switch (le)
        {
        case ERROR_ACCESS_DENIED:
        case ERROR_DEPENDENT_SERVICES_RUNNING:
        case ERROR_INVALID_HANDLE:
        case ERROR_INVALID_PARAMETER:
        case ERROR_INVALID_SERVICE_CONTROL:
        case ERROR_SERVICE_CANNOT_ACCEPT_CTRL:
        case ERROR_SERVICE_REQUEST_TIMEOUT:
        case ERROR_SHUTDOWN_IN_PROGRESS:
            return FALSE;

        case ERROR_SERVICE_NOT_ACTIVE:
        default:
            break;
        }
    }

بعد توجيه الخدمة للتوقف ، أنتظر أن يذكر مدير الخدمة أن الخدمة قد توقفت في الواقع. يحتوي هذا الرمز على أخطاء محتملين ، والتي قد ترغب في تصحيحها لرمز الإنتاج:

  1. ستعلق Sleep (1000) حلقة الرسالة في هذا الموضوع ، لذلك يجب عليك استخدام طريقة أخرى لتأخير التنفيذ إذا كانت هذه الوظيفة ستعمل على مؤشر ترابط واجهة المستخدم. يمكنك بناء حلقة نوم مع حلقة مناسبة msgwaitformultipleobjectsex ().
  2. عاد DWORD من getTickCount () سوف تلتف حول الصفر في نهاية المطاف. إذا كانت تتجول أثناء انتظار هذه الوظيفة ، فقد يستسلم الانتظار عاجلاً مما كنت أقصد.

    DWORD waitstart(::GetTickCount());
    while (true)
    {
        ZeroMemory(&ss, sizeof(ss));
        ::QueryServiceStatus(hW32Time, &ss);
        if (SERVICE_STOPPED == ss.dwCurrentState) break;
        ::Sleep(1000);
        DWORD tick(::GetTickCount());
        if ((tick < waitstart) || (tick > (waitstart + 30000))) return FALSE;
    }
    

أخيرًا ، مع العلم أن الخدمة في حالة توقف ، أتصل إبدأ الخدمة() قم بتشغيله مرة أخرى.

    success = ::StartService(hW32Time, 0, NULL);
    if (!success) return FALSE;

    return TRUE;
}

نصائح أخرى

فيما يلي برنامج صغير سيتصل بخدمة تسمى "MyService" ثم إرسال أمر 141 (الذي يتم تعريفه بواسطة الخدمة)

// ServiceCommunicator.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <Windows.h>
#include <iostream>

using namespace std;

int main()
{
    SC_HANDLE managerHandle;
    SC_HANDLE serviceHandle;

    SERVICE_STATUS   controlParms;
    DWORD retStatus;

    managerHandle = OpenSCManager(NULL, NULL, GENERIC_READ);
    if (NULL != managerHandle)
    {
        serviceHandle = OpenService(managerHandle, L"MYSERVICE", SERVICE_USER_DEFINED_CONTROL | SERVICE_QUERY_STATUS);

        if (NULL != serviceHandle)
        {
            cout << "connected to Service" << endl;
            retStatus = ControlService(serviceHandle, 141, &controlParms);

            if (retStatus)
            {
                //Get the return code from the service
                cout << "For command 141, return code from service was " << controlParms.dwWin32ExitCode << endl;
            }
            else
                cout << "Sending command 141 failed" << endl;

            CloseServiceHandle(serviceHandle);
        }
        else
        {
            cout << "could not connect to Service" << endl;
        }

        CloseServiceHandle(managerHandle);
    }
    else
    {
        cout << "could not open service manager" << endl;
    }
    return 0;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top