Created
January 22, 2023 16:37
-
-
Save smourier/b2c5c4b030b203ec1e754ca3ce753df0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <windows.h> | |
| #include <strsafe.h> | |
| #include <atlbase.h> | |
| #include <mfapi.h> | |
| #include <stdio.h> | |
| #pragma comment(lib, "advapi32") | |
| #pragma comment(lib, "mfreadwrite") | |
| #pragma comment(lib, "mfplat") | |
| #pragma comment(lib, "mfuuid") | |
| wchar_t SVCNAME[] = L"SvcName"; | |
| SERVICE_STATUS gSvcStatus; | |
| SERVICE_STATUS_HANDLE gSvcStatusHandle; | |
| HANDLE ghSvcStopEvent = NULL; | |
| VOID SvcInstall(void); | |
| VOID WINAPI SvcCtrlHandler(DWORD); | |
| VOID WINAPI SvcMain(DWORD, LPWSTR*); | |
| VOID ReportSvcStatus(DWORD, DWORD, DWORD); | |
| VOID SvcInit(DWORD, LPWSTR*); | |
| VOID SvcReportEvent(LPCWSTR); | |
| // | |
| // Purpose: | |
| // Entry point for the process | |
| // | |
| // Parameters: | |
| // None | |
| // | |
| // Return value: | |
| // None, defaults to 0 (zero) | |
| // | |
| int __cdecl _tmain(int argc, wchar_t* argv[]) | |
| { | |
| // If command-line parameter is "install", install the service. | |
| // Otherwise, the service is probably being started by the SCM. | |
| if (lstrcmpi(argv[1], L"install") == 0) | |
| { | |
| SvcInstall(); | |
| return 0; | |
| } | |
| // TO_DO: Add any additional services for the process to this table. | |
| SERVICE_TABLE_ENTRY DispatchTable[] = | |
| { | |
| { SVCNAME, (LPSERVICE_MAIN_FUNCTION)SvcMain }, | |
| { NULL, NULL } | |
| }; | |
| // This call returns when the service has stopped. | |
| // The process should simply terminate when the call returns. | |
| if (!StartServiceCtrlDispatcher(DispatchTable)) | |
| { | |
| SvcReportEvent(L"StartServiceCtrlDispatcher"); | |
| } | |
| } | |
| // | |
| // Purpose: | |
| // Installs a service in the SCM database | |
| // | |
| // Parameters: | |
| // None | |
| // | |
| // Return value: | |
| // None | |
| // | |
| VOID SvcInstall() | |
| { | |
| SC_HANDLE schSCManager; | |
| SC_HANDLE schService; | |
| wchar_t szUnquotedPath[MAX_PATH]; | |
| if (!GetModuleFileName(NULL, szUnquotedPath, MAX_PATH)) | |
| { | |
| printf("Cannot install service (%d)\n", GetLastError()); | |
| return; | |
| } | |
| // In case the path contains a space, it must be quoted so that | |
| // it is correctly interpreted. For example, | |
| // "d:\my share\myservice.exe" should be specified as | |
| // ""d:\my share\myservice.exe"". | |
| wchar_t szPath[MAX_PATH]; | |
| StringCbPrintf(szPath, MAX_PATH, L"\"%s\"", szUnquotedPath); | |
| // Get a handle to the SCM database. | |
| schSCManager = OpenSCManager( | |
| NULL, // local computer | |
| NULL, // ServicesActive database | |
| SC_MANAGER_ALL_ACCESS); // full access rights | |
| if (NULL == schSCManager) | |
| { | |
| printf("OpenSCManager failed (%d)\n", GetLastError()); | |
| return; | |
| } | |
| // Create the service | |
| schService = CreateService( | |
| schSCManager, // SCM database | |
| SVCNAME, // name of service | |
| SVCNAME, // service name to display | |
| SERVICE_ALL_ACCESS, // desired access | |
| SERVICE_WIN32_OWN_PROCESS, // service type | |
| SERVICE_DEMAND_START, // start type | |
| SERVICE_ERROR_NORMAL, // error control type | |
| szPath, // path to service's binary | |
| NULL, // no load ordering group | |
| NULL, // no tag identifier | |
| NULL, // no dependencies | |
| NULL, // LocalSystem account | |
| NULL); // no password | |
| if (schService == NULL) | |
| { | |
| printf("CreateService failed (%d)\n", GetLastError()); | |
| CloseServiceHandle(schSCManager); | |
| return; | |
| } | |
| else printf("Service installed successfully\n"); | |
| CloseServiceHandle(schService); | |
| CloseServiceHandle(schSCManager); | |
| } | |
| // | |
| // Purpose: | |
| // Entry point for the service | |
| // | |
| // Parameters: | |
| // dwArgc - Number of arguments in the lpszArgv array | |
| // lpszArgv - Array of strings. The first string is the name of | |
| // the service and subsequent strings are passed by the process | |
| // that called the StartService function to start the service. | |
| // | |
| // Return value: | |
| // None. | |
| // | |
| VOID WINAPI SvcMain(DWORD dwArgc, LPWSTR* lpszArgv) | |
| { | |
| // Register the handler function for the service | |
| gSvcStatusHandle = RegisterServiceCtrlHandler( | |
| SVCNAME, | |
| SvcCtrlHandler); | |
| if (!gSvcStatusHandle) | |
| { | |
| SvcReportEvent(L"RegisterServiceCtrlHandler"); | |
| return; | |
| } | |
| // These SERVICE_STATUS members remain as set here | |
| gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; | |
| gSvcStatus.dwServiceSpecificExitCode = 0; | |
| // Report initial status to the SCM | |
| ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000); | |
| // Perform service-specific initialization and work. | |
| wchar_t Buffer[256]; | |
| auto hr = MFStartup(MF_VERSION); | |
| StringCchPrintf(Buffer, ARRAYSIZE(Buffer), L"MFStartup hr:%08X", hr); | |
| OutputDebugString(Buffer); | |
| MFT_REGISTER_TYPE_INFO const g_InputTypeInfo[]{ MFMediaType_Video, MFVideoFormat_HEVC }; | |
| IMFActivate** activates = NULL; | |
| UINT32 activateCount = 0; | |
| hr = MFTEnumEx(MFT_CATEGORY_VIDEO_DECODER, MFT_ENUM_FLAG_ALL, g_InputTypeInfo, NULL, &activates, &activateCount); | |
| StringCchPrintf(Buffer, ARRAYSIZE(Buffer), L"MFTEnumEx hr:%08X count:%i", hr, activateCount); | |
| OutputDebugString(Buffer); | |
| if (activates) | |
| { | |
| activates[0]->Release(); | |
| CoTaskMemFree(activates); | |
| } | |
| OutputDebugString(L"OK"); | |
| SvcInit(dwArgc, lpszArgv); | |
| } | |
| // | |
| // Purpose: | |
| // The service code | |
| // | |
| // Parameters: | |
| // dwArgc - Number of arguments in the lpszArgv array | |
| // lpszArgv - Array of strings. The first string is the name of | |
| // the service and subsequent strings are passed by the process | |
| // that called the StartService function to start the service. | |
| // | |
| // Return value: | |
| // None | |
| // | |
| VOID SvcInit(DWORD dwArgc, LPWSTR* lpszArgv) | |
| { | |
| // TO_DO: Declare and set any required variables. | |
| // Be sure to periodically call ReportSvcStatus() with | |
| // SERVICE_START_PENDING. If initialization fails, call | |
| // ReportSvcStatus with SERVICE_STOPPED. | |
| // Create an event. The control handler function, SvcCtrlHandler, | |
| // signals this event when it receives the stop control code. | |
| ghSvcStopEvent = CreateEvent( | |
| NULL, // default security attributes | |
| TRUE, // manual reset event | |
| FALSE, // not signaled | |
| NULL); // no name | |
| if (ghSvcStopEvent == NULL) | |
| { | |
| ReportSvcStatus(SERVICE_STOPPED, GetLastError(), 0); | |
| return; | |
| } | |
| // Report running status when initialization is complete. | |
| ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0); | |
| // TO_DO: Perform work until service stops. | |
| while (1) | |
| { | |
| // Check whether to stop the service. | |
| WaitForSingleObject(ghSvcStopEvent, INFINITE); | |
| ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0); | |
| return; | |
| } | |
| } | |
| // | |
| // Purpose: | |
| // Sets the current service status and reports it to the SCM. | |
| // | |
| // Parameters: | |
| // dwCurrentState - The current state (see SERVICE_STATUS) | |
| // dwWin32ExitCode - The system error code | |
| // dwWaitHint - Estimated time for pending operation, | |
| // in milliseconds | |
| // | |
| // Return value: | |
| // None | |
| // | |
| VOID ReportSvcStatus(DWORD dwCurrentState, | |
| DWORD dwWin32ExitCode, | |
| DWORD dwWaitHint) | |
| { | |
| static DWORD dwCheckPoint = 1; | |
| // Fill in the SERVICE_STATUS structure. | |
| gSvcStatus.dwCurrentState = dwCurrentState; | |
| gSvcStatus.dwWin32ExitCode = dwWin32ExitCode; | |
| gSvcStatus.dwWaitHint = dwWaitHint; | |
| if (dwCurrentState == SERVICE_START_PENDING) | |
| gSvcStatus.dwControlsAccepted = 0; | |
| else gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; | |
| if ((dwCurrentState == SERVICE_RUNNING) || | |
| (dwCurrentState == SERVICE_STOPPED)) | |
| gSvcStatus.dwCheckPoint = 0; | |
| else gSvcStatus.dwCheckPoint = dwCheckPoint++; | |
| // Report the status of the service to the SCM. | |
| SetServiceStatus(gSvcStatusHandle, &gSvcStatus); | |
| } | |
| // | |
| // Purpose: | |
| // Called by SCM whenever a control code is sent to the service | |
| // using the ControlService function. | |
| // | |
| // Parameters: | |
| // dwCtrl - control code | |
| // | |
| // Return value: | |
| // None | |
| // | |
| VOID WINAPI SvcCtrlHandler(DWORD dwCtrl) | |
| { | |
| // Handle the requested control code. | |
| switch (dwCtrl) | |
| { | |
| case SERVICE_CONTROL_STOP: | |
| ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); | |
| // Signal the service to stop. | |
| SetEvent(ghSvcStopEvent); | |
| ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0); | |
| return; | |
| case SERVICE_CONTROL_INTERROGATE: | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| // | |
| // Purpose: | |
| // Logs messages to the event log | |
| // | |
| // Parameters: | |
| // szFunction - name of function that failed | |
| // | |
| // Return value: | |
| // None | |
| // | |
| // Remarks: | |
| // The service must have an entry in the Application event log. | |
| // | |
| VOID SvcReportEvent(LPCWSTR szFunction) | |
| { | |
| HANDLE hEventSource; | |
| LPCWSTR lpszStrings[2]; | |
| wchar_t Buffer[80]; | |
| hEventSource = RegisterEventSource(NULL, SVCNAME); | |
| if (NULL != hEventSource) | |
| { | |
| StringCchPrintf(Buffer, 80, L"%s failed with %d", szFunction, GetLastError()); | |
| OutputDebugString(Buffer); | |
| lpszStrings[0] = SVCNAME; | |
| lpszStrings[1] = Buffer; | |
| ReportEvent(hEventSource, // event log handle | |
| EVENTLOG_ERROR_TYPE, // event type | |
| 0, // event category | |
| 0xC1234567, // event identifier | |
| NULL, // no security identifier | |
| 2, // size of lpszStrings array | |
| 0, // no binary data | |
| lpszStrings, // array of strings | |
| NULL); // no binary data | |
| DeregisterEventSource(hEventSource); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It is the ActivateObject() that would produce the "missing codec" error.