您如何将DART应用程序作为Windows服务运行?

8yparm6h  于 2022-12-15  发布在  Windows
关注(0)|答案(4)|浏览(279)

我一直在研究在我的下一个项目中使用DART语言的可能性。在这一点上唯一真正阻碍我的是,我无法找到一种方法来运行DART应用程序作为一个windows服务。我已经运行了谷歌搜索,并阅读了DART网站上的许多文档。我找到的大多数信息都与在DART中创建服务器有关,但没有关于windows服务的信息。
有人能给我指一下方向或详细说明这样做的必要步骤吗?
谢谢你,乔恩

rlcwz9us

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文件的完整代码:

// 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);
}
laik7k3q

laik7k3q2#

使用Dart for Windows服务与使用任何其他可执行文件没有区别;您只需要使用正确的参数调用dart.exe。
但是Windows不支持任意exe作为Windows服务运行,因为它们需要一点元数据/引导。我对NSSM - the Non-Sucking Service Manager有很好的体验。在评论中建议使用SC.exe;但是我无法让它在最新版本的Windows Server上运行:(

ffdz8vbo

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示例:

<service>
  <id>MyApp</id>
  <name>My App</name>
  <description>My App's description</description>
  <executable>C:\tools\dart-sdk\bin\dart.exe</executable>
  <workingdirectory>C:\path\to\project</workingdirectory>
  <arguments>lib/main.dart</arguments>
  <log mode="roll"></log>
  <priority>high</priority>
</service>
8wigbo56

8wigbo564#

查看dart软件包dart_windows_service_support
他使用dart:ffidll文件使dart能够在Windows服务模式下运行
https://pub.dev/packages/dart_windows_service_support

相关问题