// Provides an API for Dart console applications to
// integrate themselves as Windows Services
// The entry point to this API is the Init(...)
// function at the bottom of this file.
// The Init(...) function registers the ServiceMain(...)
// function as the actual windows service function.
// the ServiceMain function does the following:
//
// 1. Registers the ServiceCtrlHandler(...) function
// as the service control handler, which is essentially
// tasked to handle control requests (in this case we
// are only handling the request to stop the service).
//
// 2. Creates an event object that and then waits indefinitely
// for the event to be set.
//
// The ServiceCtrlHandler(...) function responds to a
// close request by setting the event created by the
// ServiceMain(...) function, essentially freeing
// the latter from the indefinite wait and terminating
// it.
// The functions in this file don't actually
// do any work, but keep the Windows Service
// alive. The work be initiated by the calling
// application either before or after the call to Init(...).
// Because this was developed for the purpose
// of enabling Dart applications to run as
// Windows Services, it it the Dart Application
// that needs to call Init(...) using Dart FFI.
// It must also be the Dart Application to
// spawn an isolate that does the actual work
// before the call to Init(...)
#include <Windows.h>
#include <tchar.h>
#include "service.h"
SERVICE_STATUS g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
LPWSTR w_service_name;
void UpdateStatus(
DWORD newState,
DWORD checkPoint,
DWORD exitCode,
DWORD controlsAccepted)
{
g_ServiceStatus.dwControlsAccepted = controlsAccepted;
g_ServiceStatus.dwCurrentState = newState;
g_ServiceStatus.dwWin32ExitCode = exitCode;
g_ServiceStatus.dwCheckPoint = checkPoint;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
}
// Responds to control events. This implementation is
// only responding to the SERVICE_CONTROL_STOP event
// This method signals the ServiceMain function
// that it can stop waiting before terminating.
void WINAPI ServiceCtrlHandler(DWORD CtrlCode)
{
if (CtrlCode != SERVICE_CONTROL_STOP || g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
return;
UpdateStatus(SERVICE_STOP_PENDING, 4, 0, 0);
SetEvent(g_ServiceStopEvent);
}
void InitServiceStatus()
{
ZeroMemory(&g_ServiceStatus, sizeof(g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
UpdateStatus(SERVICE_START_PENDING, 0, 0, 0);
}
// This function essentially creates an event object
// and enters a holding pattern until that event object
// is set by the ServiceCtrlHandler(...) in response
// to a close request.
// The function doesn't actually do any work,
// except to keep the Windows Service alive.
void WINAPI ServiceMain(DWORD argc, LPTSTR* argv)
{
g_StatusHandle = RegisterServiceCtrlHandler(w_service_name, ServiceCtrlHandler);
if (g_StatusHandle == NULL)
return;
InitServiceStatus();
g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_ServiceStopEvent == NULL)
{
UpdateStatus(SERVICE_STOPPED, 1, GetLastError(), 0);
return;
}
UpdateStatus(SERVICE_RUNNING, 0, 0, SERVICE_ACCEPT_STOP);
while (WaitForSingleObject(g_ServiceStopEvent, INFINITE) != WAIT_OBJECT_0)
;
CloseHandle(g_ServiceStopEvent);
UpdateStatus(SERVICE_STOPPED, 3, 0, 0);
}
LPWSTR get_service_name(const char* service_name)
{
int max_count = strlen(service_name);
int size = max_count + 1;
LPWSTR ret = malloc(sizeof(wchar_t) * size);
size_t outSize;
mbstowcs_s(&outSize, ret, size, service_name, max_count);
return ret;
}
/// This is the entry point that should be called
/// by the Dart application (or any application
/// of a similar kind of platform) in order to
/// integrate itself as a Windows Service.
/// It registers the ServiceMain(...) function
/// as the service main function. Please consult
/// the comments at that function to understand
/// what it does.
int init(const char* service_name)
{
w_service_name = get_service_name(service_name);
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{w_service_name, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL, NULL}
};
if (StartServiceCtrlDispatcher(ServiceTable) == FALSE)
return GetLastError();
}
Service. h头文件自然要小得多:
#pragma once
#ifdef WINSERVICE_EXPORTS
#define WINSERVICE_API __declspec(dllexport)
#else
#define WINSERVICE_API __declspec(dllimport)
#endif
WINSERVICE_API int init(const char* service_name);
只需确保将WINSERVICE_EXPORTS添加到其中一个定义中,或者用项目中的相应定义替换它。
dart
我还需要在Dart方面做一些修改。下面是我的原型:
import 'dart:ffi' as ffi;
import 'dart:io';
import 'dart:isolate';
import 'package:ffi/ffi.dart';
import 'package:grpc/grpc.dart' as grpc;
// These two types represent the
// Init(...) function of the C API
typedef init_func = ffi.Int32 Function(ffi.Pointer<Utf8>);
typedef Init = int Function(ffi.Pointer<Utf8>);
// Entry point to the Dart application.
// When run as a Windows Service,
// this is still the entry point.
// This code is not embeded but is started
// as a regular console application.
void main() async {
final init = createInit();
// Starts the actual work in a separate Isolate
await Isolate.spawn(run, 'message');
final serviceName = Utf8.toUtf8('MProto_Server_from_Dart');
// calls the Init(...) function
var result = init(serviceName);
if (result != 0) return;
// blocks this Isolate indefinitely from continuing
while (true) {
sleep(Duration(days: 365));
}
}
// Creates the instance of the proxy to the Init(...)
// function.
Init createInit() {
final path =
r'[PATH to the C compiled DLL]';
final dylib = ffi.DynamicLibrary.open(path);
// ignore: omit_local_variable_types
final Init init =
dylib.lookup<ffi.NativeFunction<init_func>>('init').asFunction();
return init;
}
// Performs the actual work that needs to
// be done, in this case, we are hosting
// a gRPC service, but this should
// work with any other kind of
// payload, namely other types of
// http services.
void run(String message) async {
print('inside isolate');
var server = grpc.Server(
[
// my service classes
],
);
await server.serve(port: 5001);
}
使用Dart for Windows服务与使用任何其他可执行文件没有区别;您只需要使用正确的参数调用dart.exe。 但是Windows不支持任意exe作为Windows服务运行,因为它们需要一点元数据/引导。我对NSSM - the Non-Sucking Service Manager有很好的体验。在评论中建议使用SC.exe;但是我无法让它在最新版本的Windows Server上运行:(
4条答案
按热度按时间rlcwz9us1#
===最新更新===
我最初的答案是使用C和Dart FFI来引导Windows服务。但是,这些都不是真正需要的,因为使用Docker和Windows容器可以有一个非常非常简单的解决方案。
除了将应用程序作为Windows服务运行之外,另一种方法是将其编译为可执行的Windows控制台应用程序,创建一个Docker文件和一个包含该应用程序的Windows Docker映像。在服务器上,您将需要Docker,您可以使用--restart选项简单地运行映像。为了测试这一点,Windows 10支持使用Windows容器的Docker。
因此,简单的解决方案是,我们实际上不需要将Dart代码作为Windows服务运行,因为我们可以将其作为服务器上的Docker容器运行。
===原始答案===
我到达真的很晚的游戏,但我想出了一个方法来绕过这个问题,而不必使用第3方应用程序。
我的解决方案是一种黑客,但嘿,它的工作。我编译的dart应用程序作为一个可执行文件,然后注册为Windows服务,使用sc.exe创建。sc.exe创建的问题是,应用程序的主要功能需要执行一些额外的步骤,以通知Windows它正在运行。如果不这样做,Windows服务陷入“启动状态”。
我不认为有一个pub包可以履行这一职责。但是,有两个东西我们可以用途:Dart:FFI,以及Mohit Arora的以下文章,该文章解释了如何用C创建Windows服务。https://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus
我抓住Mohit的代码,做了大量的修改(包括将其反向移植到C,因为... C)
C
下面是Service. c文件的完整代码:
Service. h头文件自然要小得多:
只需确保将WINSERVICE_EXPORTS添加到其中一个定义中,或者用项目中的相应定义替换它。
dart
我还需要在Dart方面做一些修改。下面是我的原型:
laik7k3q2#
使用Dart for Windows服务与使用任何其他可执行文件没有区别;您只需要使用正确的参数调用dart.exe。
但是Windows不支持任意exe作为Windows服务运行,因为它们需要一点元数据/引导。我对NSSM - the Non-Sucking Service Manager有很好的体验。在评论中建议使用SC.exe;但是我无法让它在最新版本的Windows Server上运行:(
ffdz8vbo3#
使用WinSW
WinSW将任何应用程序作为Windows服务进行 Package 和管理。
1.在项目中创建
service
目录。1.在GitHub上找到最新的release of WinSW,你很可能是专门寻找WinSW-x64.exe。将这个文件复制到你项目的
service
目录下,并将它重命名为你的链接,例如service\MyApp-Service.exe
。1.使用下面的示例配置为服务
service\MyApp-Service.xml
创建配置文件。1.从命令行运行
.\MyApp-Service.exe install
。您的服务应列在Windows服务中。配置XML示例:
8wigbo564#
查看dart软件包
dart_windows_service_support
他使用
dart:ffi
和dll
文件使dart能够在Windows服务模式下运行https://pub.dev/packages/dart_windows_service_support