zoukankan      html  css  js  c++  java
  • Python搭建调用本地dll的Windows服务(浏览器可以访问,附测试dll64位和32位文件)

    一、前言说明

      博客声明:此文链接地址https://www.cnblogs.com/Vrapile/p/14113683.html请尊重原创,未经允许禁止转载!!!

      1. 功能简述

      (1)本文提供生成好的测试dll文件,提供用Python调用dll生成windows服务接口的方法,在浏览器可以打开的样例。 

      

      (2)网上有调用dll的文章,有生成dll的文章,如果仅仅是尝试做python调用dll的开发,还需要花时间下载visual studio去生成dll

        网上基本下载不到测试用的dll,因此整理此文章供读者参阅

      (3)参照1:Python之Windows服务,参照2:python实现编写windows服务,参照3:vs2019生成64位dll(动态链接库)并用python3.7调用

      (4)提供我封装好的dll路径:点击下载dll或右键在新标签页打开下载dll(原文链接长期可以访问,如果不能访问很可能是未经允许转载或者复制的)

      

      2. 我的开发环境

      (1)Python3.8语言,Pycharm工具,Windows10环境

     

    二、接口源码设计

      1. PyCharm界面及项目路径

      

       1. 文件结构说明

      (1)MyService是项目名字

      (2)build、disk两个文件夹编译启动服务会自动生成

      (3)dll路径文件夹,放dll文件

      (4)log路径文件夹,放日志文件,没有会自动创建

      (5)service包文件夹,主要开发位置,调用dll和业务逻辑等都在此文件夹下

      (6)test包文件夹,放测试代码等,可忽略

      (7)util包文件夹,封装一些工具类

      (8)DllService.py,系统主入口文件,只需要将service包文件夹下的内容引用到此文件的"SvcStop"里即可

      (9)DllService.spec,编译启动服务会自动生成

      (10)start.bat,编译项目生成服务的启动命令,启动方法要用管理员权限

        cd进入文件目录,./start.bat运行脚本,如下图:

       

      2. 运行成功效果如下图:

      

       3. 服务未成功生成,直接看cmd窗口报错信息,如果是生成的服务已停止,说明服务启动报错了,查看报错原因方法:

        win10设置——控制面板——管理工具——事件查看器——Windows日志——应用程序——筛选当前日志(勾选错误)

      

      

      2. 文件代码

      (1)DllService.py,生成服务文件,此文件基本不用大改动    

     1 # -*- coding:utf-8 -*-
     2 import win32timezone  # 虽然看起来没被应用,但是不能少,否则启动服务会报错
     3 import win32serviceutil
     4 import win32service
     5 import win32event
     6 import servicemanager
     7 import os
     8 import sys
     9 from util import logger
    10 
    11 
    12 class DllService(win32serviceutil.ServiceFramework):
    13     _svc_name_ = 'DllService'  # 服务名,服务启动停止唯一标识
    14     _svc_display_name_ = 'DllService'  # 服务显示名称,可与服务名不同
    15     _svc_description_ = 'DLL本地服务-测试浏览器调用'  # 服务描述,可任意填写
    16 
    17     def __init__(self, args):
    18         win32serviceutil.ServiceFramework.__init__(self, args)
    19         self.stop_event = win32event.CreateEvent(None, 0, 0, None)
    20         self.run = True
    21 
    22 
    23     def SvcDoRun(self):
    24         from service.TestService import TestService
    25         logger.info(" Service is running ")
    26         TestService.run(port=12345)
    27 
    28 
    29     def SvcStop(self):
    30         self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
    31         win32event.SetEvent(self.stop_event)
    32         self.ReportServiceStatus(win32service.SERVICE_STOPPED)
    33         self.run = False
    34         logger.info(" Service is stopped ")
    35 
    36 
    37 if __name__ == '__main__':
    38     if len(sys.argv) == 1:
    39         try:
    40             event_src_dll = os.path.abspath(servicemanager.__file__)
    41             servicemanager.PrepareToHostSingle(DllService)  # 此处是文件名
    42             servicemanager.Initialize('DllService', event_src_dll )  # 此处是服务名
    43             servicemanager.StartServiceCtrlDispatcher()
    44         except win32service.error as details:
    45             import winerror
    46             if details == winerror.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
    47                 win32serviceutil.usage()
    48     else:
    49         win32serviceutil.HandleCommandLine(DllService)  # 此处是文件名

        

      (2)TestService.py,具体服务文件

      CORS(TestService, supports_credentials=True)  解决浏览器访问跨域问题

      因为sys.path[0]地址为:E:PythonMyServicedistDllServicease_library.zip,因此需要返回3级回到主目录boot_path 

      此处因为我本地Python环境为64位,因此只能调用64位dll,32位dll调用后续如果有人想看再更新  

     1 # -*- coding:utf-8 -*-
     2 import os
     3 import sys
     4 from flask import Flask, request
     5 from flask_cors import *
     6 import traceback
     7 import json
     8 import ctypes
     9 from util import ResponseMessage, logger
    10 
    11 
    12 TestService = Flask(__name__)
    13 CORS(TestService, supports_credentials=True)
    14 
    15 boot_path = os.path.abspath(os.path.join(sys.path[0], "../../.."))
    16 
    17 
    18 # ajaxJson["src"] = "http://127.0.0.1:12345/test";
    19 # ajaxJson["data"] = {"data":"{"aaa":123,"bbb":"456"}"};
    20 # JL.ajax(ajaxJson);
    21 @TestService.route("/test", methods=['GET', 'POST'])
    22 def test():
    23     # noinspection PyBroadException
    24     try:
    25         data = request.values.get('data')
    26         data_dict = json.loads(data)
    27         logger.info("request:" + str(data_dict))
    28         dll_path = os.path.join(os.path.join(boot_path, "dll"), "MyDll64.dll")
    29         windll = ctypes.windll.LoadLibrary(dll_path)
    30         result_add = windll.myAdd(int(data_dict["aaa"]), int(data_dict["bbb"]))
    31         result_max = windll.myMax(int(data_dict["aaa"]), int(data_dict["bbb"]))
    32         return_data = dict()
    33         return_data["add"] = result_add
    34         return_data["max"] = result_max
    35         return_data["dll_path"] = dll_path
    36     except:
    37         logger.error("error:" + traceback.format_exc())
    38         return ResponseMessage.error(traceback.format_exc())
    39     logger.info("response:" + str(ResponseMessage.ok(return_data)))
    40     return ResponseMessage.ok(return_data)

      3. logger.py,日志工具封装文件

      如上文中引用方式:from util import logger, 使用方式:logger.info(" Service is stopped ")

      此文已更改日志保存路径为项目根路径的log下,没有会自动创建

     1 #!/usr/bin/python
     2 # -*- coding: utf-8 -*-
     3 """
     4 Created on Feb 23, 2020
     5 @author: Vrapile
     6 """
     7 import sys
     8 import os
     9 import datetime
    10 import logging
    11 from logging.handlers import RotatingFileHandler
    12 
    13 
    14 boot_path = os.path.abspath(os.path.join(sys.path[0], "../../.."))
    15 
    16 logger = logging.getLogger(__name__)
    17 logger.setLevel(level=logging.INFO)
    18 log_path = os.path.join(boot_path, 'log')
    19 if not os.path.exists(log_path):
    20     os.makedirs(log_path)
    21 handler = RotatingFileHandler(os.path.join(log_path, '%s.log' % datetime.date.today()), maxBytes=5 * 1024 * 1024, backupCount=10)
    22 handler.setLevel(level=logging.INFO)
    23 formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    24 handler.setFormatter(formatter)
    25 logger.addHandler(handler)
    26 
    27 
    28 def debug(text):
    29     logger.debug(text)
    30 
    31 
    32 def info(text):
    33     logger.info(text)
    34 
    35 
    36 def warning(text):
    37     logger.warning(text)
    38 
    39 
    40 def error(text):
    41     logger.error(text)
    42 
    43 
    44 def critical(text):
    45     logger.critical(text)

      

      4. ResponseMessage.py提供标准化响应json数据,引用使用方式见TestService.py

     1 #!/usr/bin/python3
     2 # -*- coding: utf-8 -*-
     3 """
     4 Created on Feb 23, 2020
     5 @author: Vrapile
     6 """
     7 import json
     8 
     9 
    10 def ok(data, code=200):
    11     return_dict = dict()
    12     return_dict["code"] = code
    13     return_dict["success"] = True
    14     return_dict["data"] = data
    15     return_dict["message"] = None
    16     return_dict["flag"] = 0
    17     return json.dumps(return_dict, ensure_ascii=False)
    18 
    19 
    20 def error(message, code=500):
    21     return_dict = dict()
    22     return_dict["code"] = code
    23     return_dict["success"] = False
    24     return_dict["data"] = None
    25     return_dict["message"] = message
    26     return_dict["flag"] = 1
    27     return json.dumps(return_dict, ensure_ascii=False)
    28 
    29 
    30 def res(data):
    31     if data[0]:
    32         return ok(data[1])
    33     else:
    34         return error(data[1])

      

      5. start.bat文件,封装编译启动命令,需要管理员权限的cmd,启动方法上文已有说明

      其中等待3秒是必须的,等待释放文件资源,否则删除dist和build基本都会报错

     1 sc stop DllService
     2 sc delete DllService
     3 :: 等待3秒
     4 TIMEOUT /T 3 
     5 rmdir /s/q dist
     6 rmdir /s/q build
     7 del DllService.spec
     8 pyinstaller DllService.py
     9 distDllServiceDllService.exe install
    10 sc start DllService
    11 TIMEOUT /T 30 

       

    三、总结

      1. 浏览器访问地址:http://127.0.0.1:12345/test?data={"aaa":123,"bbb":456}

      2. 通过Python调用dll,提供本地浏览器访问是可以实现的,js访问效果如下:

      

      3. 主要解决现在很多银行都是提供dll文件支付,而公司业务又是浏览器系统,不能直接访问本地dll,因此此文方案可以解决此类问题

  • 相关阅读:
    详细的解说public,protected,Default和private的权限问题
    谈谈java中静态变量与静态方法在有继承关系的两个类中调用
    谈谈java中成员变量与成员方法继承的问题
    谈谈嵌套for循环的理解
    JAVA基础细谈
    Css的使用细谈
    Hibernate映射
    hibernate基本
    struts2
    s:form标签
  • 原文地址:https://www.cnblogs.com/Vrapile/p/14113683.html
Copyright © 2011-2022 走看看