要求:一个EXE,如何将它做成这样的效果:
1、双击它时,像一个FORMS程序那样正常显示窗体运行。
2、注册成系统服务,每次都可以从service.msc中启动它。

也就是说,没注册之前,它可以当作普通FORMS程序运行,注册之后,它就可以当系统服务运行。

做法:

参考Delphi 里面scktsrvr的源代码,Program Files/Borland/Delphi7/Bin 搜索scktsrvr 就会看到有个scktsrvr.dpr,查看它的工程源程序,原理:在启动程序时,通过启动的方式来决定如何加载程序。

必须的地方使用红色标记:

program RODBLayer;

{#ROGEN:RODBLayerServices.rodl} // RemObjects: Careful, do not remove!

uses
  uROComInit,

//增加引用
  SvcMgr,  Forms,    SysUtils,  WinSvc,

RODBLayerService in 'RODBLayerService.pas' {RODBServices: TService},
  RODBLayerServices_Intf in 'RODBLayerServices_Intf.pas',
  RODBLayerServices_Invk in 'RODBLayerServices_Invk.pas',
  uADOConnectionPool in 'uADOConnectionPool.pas',
  uConnectionPool in 'uConnectionPool.pas',
  Comm in 'Comm.pas',
  Config in 'Config.pas' {ConfigFrm},
  RODBLayerServices_Impl in 'RODBLayerServices_Impl.pas';

{$R *.RES}
{$R RODLFile.res}

//步骤一、查找是否通过命令行来注册或注消 ,如是则表明是系统服务
function Installing: Boolean;

begin
  Result := FindCmdLineSwitch('INSTALL',['-','/','/'], True) or
            FindCmdLineSwitch('UNINSTALL',['-','/','/'], True);
end;

//步骤二、检测是否是系统服务中启动服务;
function StartServiceBoolean;

var
  Mgr, Svc: Integer;
  UserName, ServiceStartName: string;
  Config: Pointer;
  Size: DWord;
begin
  Result := False;
  Mgr := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
  if Mgr <> 0 then
  begin

//'RODBServices'代表服务名(services name),不是指服务显示名(services display name)

//它根据你的服务而定。
    Svc := OpenService(Mgr, PChar('RODBServices'), SERVICE_ALL_ACCESS);
    Result := Svc <> 0;
    if Result then
    begin
      QueryServiceConfig(Svc, nil, 0, Size);
      Config := AllocMem(Size);
      try
        QueryServiceConfig(Svc, Config, Size, Size);
        ServiceStartName := PQueryServiceConfig(Config)^.lpServiceStartName;
        if CompareText(ServiceStartName, 'LocalSystem') = 0 then
          ServiceStartName := 'SYSTEM';
      finally
        Dispose(Config);
      end;
      CloseServiceHandle(Svc);
    end;
    CloseServiceHandle(Mgr);
  end;
  if Result then
  begin
    Size := 256;
    SetLength(UserName, Size);
    GetUserName(PChar(UserName), Size);
    SetLength(UserName, StrLen(PChar(UserName)));
    Result := CompareText(UserName, ServiceStartName) = 0;
  end;
end;

//步骤三、判断

begin
  if not Installing then
  begin
    CreateMutex(nil, True, 'RODBServices');  //创建一个互斥体;
    if GetLastError = ERROR_ALREADY_EXISTS then
    begin
      MessageBox(0, PChar('The RODBServices is already running'), '提示', MB_ICONERROR);
      Halt;
    end;
  end;
  if Installing or StartService then  //两者之一为真,表明是系统服务。否则为Forms程序;
  begin
     SvcMgr.Application.Initialize;
     SvcMgr.Application.CreateForm(TRODBServices, RODBServices);
  SvcMgr.Application.CreateForm(TConfigFrm, ConfigFrm);
     ConfigAppName:='SvcMgr'; //使用它来标识出Application属于哪种,从而为关闭TConfigFrm窗体提供依据;这一行只跟你的实际应用有关。不过程序要退出时,要根据是系统服务还是普通FORMS做出不同的退出动作。如下:
     SvcMgr.Application.Run;
  end else
  begin
     Forms.Application.Initialize;
     Forms.Application.CreateForm(TRODBServices, RODBServices);
     Forms.Application.CreateForm(TConfigFrm,ConfigFrm);
     ConfigAppName:='Forms';
     Forms.Application.Run;
  end;
end.

{接上,用来说明不同的退出动作如何做的。

procedure TConfigFrm.BtnCloseClick(Sender: TObject);
begin
  if MessageDlgPos('您确定要退出服务端吗?',mtConfirmation,[mbOK, mbCancel],0,
  Mouse.CursorPos.X-160,Mouse.CursorPos.Y-130)<>mrOk then Exit;
  RODBServices.ServiceStop(RODBServices,IsConsole) ;
  if ConfigAppName='SvcMgr' then   //前面代码都相同,仅这里要变一下。
    RODBServices.Status:=csStopped
  else
    Close;
end;}

系统服务和普通FORMS程序共存一体的实现的更多相关文章

  1. .net core 开发 Windows Forms 程序

    我是一名 ASP.NET 程序员,专注于 B/S 项目开发.累计文章阅读量超过一千万,我的博客主页地址:https://www.itsvse.com/blog_xzz.html 引言 .net cor ...

  2. 分析现有 WPF / Windows Forms 程序能否顺利迁移到 .NET Core 3.0

    本文转自 https://blog.csdn.net/WPwalter/article/details/82859449 使用 .NET Core 3.0 Desktop API Analyzer 分 ...

  3. 分析现有 WPF / Windows Forms 程序能否顺利迁移到 .NET Core 3.0(使用 .NET Core 3.0 Desktop API Analyzer )

    今年五月的 Build 大会上,微软说 .NET Core 3.0 将带来 WPF / Windows Forms 这些桌面应用的支持.当然,是通过 Windows 兼容包(Windows Compa ...

  4. 关于oracle 11g 64位与 32位的 plsql、及其他32位应用程序共存的问题

    因为 plsql 不支持 64位 oracle 客户端,所以plsql 必须使用 oracle 的 32位 instanclient 包.  解压缩后放一个目录,例如: D:\Oracle\insta ...

  5. DELPHI编写服务程序总结(在系统服务和桌面程序之间共享内存,在服务中使用COM组件)

    DELPHI编写服务程序总结 一.服务程序和桌面程序的区别 Windows 2000/XP/2003等支持一种叫做“系统服务程序”的进程,系统服务和桌面程序的区别是:系统服务不用登陆系统即可运行:系统 ...

  6. atitit.添加win 系统服务 bat批处理程序服务的法总结instsrv srvany java linux

    atitit.添加win 系统服务 bat批处理程序服务的法总结instsrv srvany  java linux 系统服务不同于普通视窗系统应用程式.不可能简简单单地通过运行一个EXE就启动视窗系 ...

  7. 如何为Windows Forms应用程序添加启动参数(Start-Up Parameters)

    很多场合下,我们需要通过命令行或者快捷方式在Windows Forms程序启动时向其传递参数. 这些参数可能是用来加载某一个文档,或者是应用程序的初始化配置文件. 特别是对那些需要高度自定义配置的大程 ...

  8. atitit.加入win 系统服务 bat批处理程序服务的法总结instsrv srvany java linux

    atitit.加入win 系统服务 bat批处理程序服务的法总结instsrv srvany  java linux 系统服务不同于普通视窗系统应用程式.不可能简简单单地通过执行一个EXE就启动视窗系 ...

  9. DOS程序员手册(九)

    第14章参考手册概述     本书余下的章节将向读者们介绍BIOS.DOS各种各样API函数和服务,作为一名程 序员,了解和掌握这些知识是很有好处的.在所介绍的参考手册中,每部手册都汇集了大 量的资源 ...

随机推荐

  1. String中对字符串进行操作的一些方法

    1.substring 作用:根据字符串下标进行截取 public class StrTest { public static void main(String[] args) { String a ...

  2. table中head表头固定,body滚动

    <style type="text/css"> .table-head { background-color: #; color: #; } .table-body { ...

  3. 原生WebGL绘制3个点

    <html> <body> <canvas width = "300" height = "300" id = "my_ ...

  4. Javascript class获取回调函数数据

    /********************************************************************** * Javascript class获取回调函数数据 * ...

  5. http解析过程

    HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端.HTTP协议采用了请求/响应模型.客户端向服务器发送一个请求报文,请求报文包含请求的方法.URL. ...

  6. react写单选按钮或table标签

    首先,原理是一样的: class Loca_choose_wrap extends Component{ constructor(){ super(); this.state={ port_name: ...

  7. acm 2072

    ////////////////////////////////////////////////////////////////////////////////#include<iostream ...

  8. Example [mybatis] 的用法

    example.or() .andField1EqualTo() .andField2IsNull(); example.or() .andField3NotEqualTo() .andField4I ...

  9. Nginx学习安装配置和Ftp配置安装

    什么是代理? 什么是正向代理? 什么是反向代理? Nginx与负载均衡有什么联系? 如何在centos7 中安装Nginx-------------安装配置---------------------- ...

  10. SpringMVC(二)高级

    高级参数绑定 1.1. 绑定数组 1.1.1. 需求 在商品列表页面选中多个商品,然后删除. 1.1.2. 需求分析 功能要求商品列表页面中的每个商品前有一个checkbok,选中多个商品后点击删除按 ...