CSharp Tips:调用API注册和注销Windows Service

C# WinForm中GridView控件的多选与全选功能实现指南 GridView是一个用于显示数据的网格控件,它可以以表格形式展示数据集,并允许用户进行查看、编辑、排序和分页等操作。它广泛应用于各种数据密集型应用程序中,为开发者提供了一个强大而灵活的方式来处理表格数据。DataGridView控件是.NET框架中用于展示和编辑表格数据的强大工具。单元格类型决定了DataGridView中数据的显示方式和交互行为。每个单元格可以独立地拥有不同的类型,例如文本、数字、日期或者更复杂的自定义类型。单元格类型不仅影响了数据的展示,还能控制用户的输入方式和数据的验证。 阅读详情
0、写在前面
    DotNET平台下的类库封装的相当完善,普通的应用完全可以利用类库完成所有的工作。对于Windows Service的支持也是一样,只需要继承DotNET下提供的ServiceBase就可以创建Windows的Service,调用ServiceControl类的方法就可以控制Service的启动和关闭,非常容易。
    然而生成了一个Service类型的应用程序之后,必须在SCM(Service Control Manager)中注册,才能够被当作一个Service被系统调用。但是对于Service的注册和注销却比较麻烦,DotNET的确也提供了对应的类ServiceInstaller和ServiceProcessInstaller,但是只能够和Installer的安装过程集成使用,不能够单独在普通应用程序中调用,也就是说为了安装一个Service用作测试,我不得不创建一个安装包。
    怎样利用API向SCM注册以及注销一个Service呢,下面就简单的介绍一下。
 
1、实现概述
    打开Control Panel中Service的管理工具,可以看到本机所有已注册的Service,选择一个Service的属性会发现一个Service有很多设置项:名称、描述、类型、运行帐号等。所有这些都可以通过调用API函数来设定。
    在Service的API中,每一个服务的实例通过句柄来表示,而需要服务的句柄之前必须要先要的到SCM的句柄(Handle),所以所有的调用都是通过OpenSCManager开始,成功的调用OpenSCManager后将获得一个SCM的句柄。如果是注册Service,那么利用SCM句柄调用CreateService来创建一个新的服务;如果是注销Service,则调用OpenService函数,获得一个已经存在的Service的句柄,然后利用这个服务句柄调用DeleteService注销服务。最后通过CloseServiceHandle关闭Service的句柄和SCM的句柄。
    过程很简单,在CSharp下比较麻烦的地方就是API的声明,下面会一一提到。
 
2、注册Service
    前面已经提到注册Service一共用到了三个API,OpenSCManager、CreateService和CloseServiceHandle。使用之前先介绍一下这些API的声明。
  [DllImport("advapi32.dll")]
  public static extern System.IntPtr OpenSCManager(
    System.String lpMachineName,
    System.String lpDatabaseName,
    System.UInt32 dwDesiredAccess
   );
  [DllImport("advapi32.dll",EntryPoint = "CreateServiceA")]
  public static extern System.IntPtr CreateService(
    System.IntPtr hSCManager,
    System.String lpServiceName,
    System.String lpDisplayName,
    System.UInt32 dwDesiredAccess,
    System.UInt32 dwServiceType,
    System.UInt32 dwStartType,
    System.UInt32 dwErrorControl,
    System.String lpBinaryPathName,
    System.String lpLoadOrderGroup,
    System.IntPtr lpdwTagId,
    System.String lpDependencies,
    System.String lpServiceStartName,
    System.String lpPassword
   );
  [DllImport("advapi32.dll")]
  public static extern System.Boolean CloseServiceHandle(
    System.IntPtr hSCObject
   );
    这个了关于Service的API都是在Advapi32.dll中实现的,函数的原型可以自行查找头文件,在Winsvc和Winbase中。
    熟悉Windows编程的话一定会了解,句柄类型就是一个32位的整型,在DotNET下用IntPtr来声明,DWORD对应UINT32,LPCSTR对应String类型,唯一需要强调的是CreateService这个函数的lpdwTagId,是一个DWORD*,这里声明也IntPtr,因为在调用中绝大多数情况下传递NULL值,如果用out UINT32,无法传递NULL值。
    仔细看CreateService中声明可以发现,这个函数真的可以做很多事情,其中包括Service的名称(lpServiceName,服务的标识,调用OpenSerive等函数时用到)、显示名(lpDisplayName,就是我们在Service的管理工具中看到的名称 )、服务类型(dwServiceType,指定服务的运行方式:独立进程、共享进程、驱动程序还是交互式登录模式等等)、启动类型(dwStartType,自动、手动还是禁止等等)、服务失败的严重性(dwErrorControl)、实现服务代码的二进制文件的路径(lpBinaryPathName)、加载顺序组的名称(lpLoadOrderGroup)、接受Tag标志码(lpdwTagId )、依赖服务的名称组(lpDependencies)、启动服务的帐号(lpServiceStartName,如果为NULL,表示使用LocalSystem)、启动服务帐号的口令(lpPassword)。如果调用成功,那么将返回一个非0的句柄,表示服务注册成功。
    看了上面的一系列属性说明,大家也许发现还少了一样,就是在Service的管理工具中最长最醒目的一栏Description,Description的设置需要调用另一个API,如下:
  public static extern System.Boolean ChangeServiceConfig2(
    System.IntPtr hService,
    System.UInt32 dwInfoLevel,
    ref System.String lpInfo
   );
    其中lpInfo的声明原型是一个LPVOID,如果设置Description属性的话指向的是一个结构:
 typedef struct _SERVICE_DESCRIPTION {
   LPTSTR
lpDescription;
 } SERVICE_DESCRIPTION, *LPSERVICE_DESCRIPTION;
    这个结构里面包含了一个字符指针,也就是说需要在函数调用时传递一个指向字符指针的指针,偷懒起见,ref System.String就足够了,无需再定义结构了,呵呵!
    完整的例子如下,常量定义见本文最后:
  private static System.Boolean RegistService()
  {
   System.Boolean  fRet = false;
   System.IntPtr  hServiceManager = IntPtr.Zero,hService = IntPtr.Zero;
   System.String  sServicePath = null,sDesc = null;
 
   sServicePath = Application.StartupPath + @"/sampleservice.exe";
   hServiceManager = OpenSCManager(Environment.MachineName,null,SC_MANAGER_ALL_ACCESS);
   if (hServiceManager != IntPtr.Zero)
   {
    hService = CreateService(hServiceManager,"sampleservice","Sample Service",SERVICE_ALL_ACCESS,
     SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,SERVICE_AUTO_START,SERVICE_ERROR_NORMAL,
     sServicePath,null,IntPtr.Zero,null,null,null);
    if (hService != IntPtr.Zero)
    {
     sDesc = "This is a sample service.";
     fRet = ChangeServiceConfig2(hService,SERVICE_CONFIG_DESCRIPTION,ref sDesc);
     CloseServiceHandle(hService);
     hService = IntPtr.Zero;
    }
    CloseServiceHandle(hServiceManager);
    hServiceManager = IntPtr.Zero;
   }
   return fRet;
  }
3、注销Service
    相对于注册,注销就简单很多了,用到了OpenSCManager、OpenService、DeleteService和CloseServiceHandle四个API,另两个API的声明如下:
  [DllImport("advapi32.dll")]
  public static extern System.IntPtr OpenService(
    System.IntPtr hSCManager,
    System.String lpServiceName,
    System.UInt32 dwDesiredAccess
   );
  [DllImport("advapi32.dll")]
  public static extern System.Boolean DeleteService(
    System.IntPtr hService
   );
    比较简单没什么可多说的看一个完整的例子:
  private static System.Boolean UnRegistService()
  {
   System.Boolean  fRet = false;
   System.IntPtr  hServiceManager = IntPtr.Zero,hService = IntPtr.Zero;
 
   hServiceManager = OpenSCManager(Environment.MachineName,null,SC_MANAGER_ALL_ACCESS);
   if (hServiceManager != IntPtr.Zero)
   {
    hService = OpenService(hServiceManager,"sampleservice",SERVICE_ALL_ACCESS);
    if (hService != IntPtr.Zero)
    {
     fRet = DeleteService(hService);
     CloseServiceHandle(hService);
     hService = IntPtr.Zero;
    }
    CloseServiceHandle(hServiceManager);
    hServiceManager = IntPtr.Zero;
   }
   return fRet;
  }
4、最后
    可以在实现Service的工程中增加一下额外的处理,Main函数中判断一下调用参数,如果是“-I”,则表示注册Service,如果是“-U”表示注销Service,反之则作为Service正常运行。
 
5、API和常量的声明
    本文所用到的所有API和常量如下:
  // declare APIs for service
  [DllImport("advapi32.dll")]
  public static extern System.IntPtr OpenSCManager(
    System.String lpMachineName,
    System.String lpDatabaseName,
    System.UInt32 dwDesiredAccess
   );
  [DllImport("advapi32.dll",EntryPoint = "CreateServiceA")]
  public static extern System.IntPtr CreateService(
    System.IntPtr hSCManager,
    System.String lpServiceName,
    System.String lpDisplayName,
    System.UInt32 dwDesiredAccess,
    System.UInt32 dwServiceType,
    System.UInt32 dwStartType,
    System.UInt32 dwErrorControl,
    System.String lpBinaryPathName,
    System.String lpLoadOrderGroup,
    System.IntPtr lpdwTagId,
    System.String lpDependencies,
    System.String lpServiceStartName,
    System.String lpPassword
   );
  [DllImport("advapi32.dll")]
  public static extern System.IntPtr OpenService(
    System.IntPtr hSCManager,
    System.String lpServiceName,
    System.UInt32 dwDesiredAccess
   );
  [DllImport("advapi32.dll")]
  public static extern System.Boolean DeleteService(
    System.IntPtr hService
   );
  [DllImport("advapi32.dll")]
  public static extern System.Boolean CloseServiceHandle(
    System.IntPtr hSCObject
   );
  [DllImport("advapi32.dll")]
  public static extern System.Boolean ChangeServiceConfig2(
    System.IntPtr hService,
    System.UInt32 dwInfoLevel,
    ref System.String lpInfo
   );
 
  public const System.UInt32 STANDARD_RIGHTS_REQUIRED = 0xF0000;
  // Service Control Manager object specific access types
  public const System.UInt32 SC_MANAGER_CONNECT = 0x0001;
  public const System.UInt32 SC_MANAGER_CREATE_SERVICE = 0x0002;
  public const System.UInt32 SC_MANAGER_ENUMERATE_SERVICE = 0x0004;
  public const System.UInt32 SC_MANAGER_LOCK = 0x0008;
  public const System.UInt32 SC_MANAGER_QUERY_LOCK_STATUS = 0x0010;
  public const System.UInt32 SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020;
  public const System.UInt32 SC_MANAGER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
    SC_MANAGER_CONNECT            |
    SC_MANAGER_CREATE_SERVICE     |
    SC_MANAGER_ENUMERATE_SERVICE  |
    SC_MANAGER_LOCK               |
    SC_MANAGER_QUERY_LOCK_STATUS  |
    SC_MANAGER_MODIFY_BOOT_CONFIG;
  // Service object specific access type
  public const System.UInt32 SERVICE_QUERY_CONFIG = 0x0001;
  public const System.UInt32 SERVICE_CHANGE_CONFIG = 0x0002;
  public const System.UInt32 SERVICE_QUERY_STATUS = 0x0004;
  public const System.UInt32 SERVICE_ENUMERATE_DEPENDENTS = 0x0008;
  public const System.UInt32 SERVICE_START = 0x0010;
  public const System.UInt32 SERVICE_STOP = 0x0020;
  public const System.UInt32 SERVICE_PAUSE_CONTINUE = 0x0040;
  public const System.UInt32 SERVICE_INTERROGATE = 0x0080;
  public const System.UInt32 SERVICE_USER_DEFINED_CONTROL = 0x0100;
  public const System.UInt32 SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED     |
    SERVICE_QUERY_CONFIG         |
    SERVICE_CHANGE_CONFIG        |
    SERVICE_QUERY_STATUS         |
    SERVICE_ENUMERATE_DEPENDENTS |
    SERVICE_START                |
    SERVICE_STOP                 |
    SERVICE_PAUSE_CONTINUE       |
    SERVICE_INTERROGATE          |
    SERVICE_USER_DEFINED_CONTROL;
  // service type
  public const System.UInt32 SERVICE_KERNEL_DRIVER = 0x00000001;
  public const System.UInt32 SERVICE_FILE_SYSTEM_DRIVER = 0x00000002;
  public const System.UInt32 SERVICE_ADAPTER = 0x00000004;
  public const System.UInt32 SERVICE_RECOGNIZER_DRIVER = 0x00000008;
  public const System.UInt32 SERVICE_DRIVER = SERVICE_KERNEL_DRIVER |
    SERVICE_FILE_SYSTEM_DRIVER |
    SERVICE_RECOGNIZER_DRIVER;
  public const System.UInt32 SERVICE_WIN32_OWN_PROCESS = 0x00000010;
  public const System.UInt32 SERVICE_WIN32_SHARE_PROCESS = 0x00000020;
  public const System.UInt32 SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS |
    SERVICE_WIN32_SHARE_PROCESS;
  public const System.UInt32 SERVICE_INTERACTIVE_PROCESS = 0x00000100;
  public const System.UInt32 SERVICE_TYPE_ALL = SERVICE_WIN32  |
    SERVICE_ADAPTER |
    SERVICE_DRIVER  |
    SERVICE_INTERACTIVE_PROCESS;
  // Start Type
  public const System.UInt32 SERVICE_BOOT_START = 0x00000000;
  public const System.UInt32 SERVICE_SYSTEM_START = 0x00000001;
  public const System.UInt32 SERVICE_AUTO_START = 0x00000002;
  public const System.UInt32 SERVICE_DEMAND_START = 0x00000003;
  public const System.UInt32 SERVICE_DISABLED = 0x00000004;
  // Error control type
  public const System.UInt32 SERVICE_ERROR_IGNORE = 0x00000000;
  public const System.UInt32 SERVICE_ERROR_NORMAL = 0x00000001;
  public const System.UInt32 SERVICE_ERROR_SEVERE = 0x00000002;
  public const System.UInt32 SERVICE_ERROR_CRITICAL = 0x00000003;
  // Info levels for ChangeServiceConfig2 and QueryServiceConfig2
  public const System.UInt32 SERVICE_CONFIG_DESCRIPTION = 1;
  public const System.UInt32 SERVICE_CONFIG_FAILURE_ACTIONS = 2;
JavaScript实现GridView全选功能及分页选择状态保持实战 或其内部复选框注入唯一的 阅读详情

相关推荐

CSharp API

CSharp API

Windows系统部署Redis的三种主流方案:WSL 2、Docker与源码编译详解

Redis作为基于内存的键值数据库,凭借其高性能和丰富的数据结构,在缓存、消息队列和会话存储等场景中广泛应用。其核心原理在于将数据存储在内存中,通过单线程模型和高效的数据结构实现极速读写,这为高并发应用提供了强大的技术支持。在技术价值层面,Redis不仅提升了系统响应速度,还通过持久化机制保障了数据可靠性。对于需要在Windows环境进行开发的工程师而言,虽然Redis原生面向Linux生态,但借助WSL 2和Docker等技术,可以高效构建本地开发环境。其中,WSL 2提供了近乎原生的Linux体验,便于

weixin_30394981的博客 403

C# Windows API大全 C sharp

C# Windows API大全,查询方便,希望对你有帮助! C sharp

关于GridView中自定义分页、单选、多选的简单应用

关于VS2005中GridView的自定义分页,单选、多选的简单应用。    图片效果:     简单示例,代码如下,    fenpage.aspx的代码:0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" align="top" alt="

cxyyxc的专栏 687

CSharp调用WindowsAPI入门_C#_windowsapi_

C#中调用Windows API开发编程指南

在MacBook M1/M2上,手把手教你打包包含嵌入模型的RagFlow Docker镜像(避坑指南)

本文详细指导如何在MacBook M1/M2上构建ARM64架构的RagFlow Docker镜像,涵盖环境准备、依赖处理、镜像构建及性能优化全流程。特别针对Apple Silicon芯片的兼容性问题提供解决方案,帮助开发者高效完成本地开发环境搭建。

weixin_26908317的博客 241

CheckBox实现跨页面多选【转】

在很多程序中需要使用CheckBox的跨页面复选功能,本例实现了GridView多页复选功能SelectMultiPages.aspx 1<%@PageLanguage="C#"AutoEventWireup="true"CodeFile="SelectMultiPages.aspx.cs"2Inherits="SelectMultiPages"%>34&l...

weixin_33939380的博客 309

Mediapipe手势识别实战——基于关节角度计算实现动态手势分类

本文详细介绍了如何利用Mediapipe进行手势识别,通过计算手指关节弯曲角度实现动态手势分类。文章从基础原理出发,讲解了关节角度计算的数学方法,并提供了Python实现代码。同时,还分享了数字手势和OK手势的识别实战经验,以及性能优化和工程实践中的关键技巧,帮助开发者快速掌握实时手势识别技术。

weixin_26891599的博客 403

GridView跨页面多选

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="GridView跨页多选._Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.o...

weixin_30706691的博客 148

告别命令行恐惧!用TBtools的MCScanX插件,5分钟搞定拟南芥和水稻的基因组共线性分析

本文介绍如何利用TBtools的MCScanX插件快速完成拟南芥和水稻的基因组共线性分析,无需命令行操作,5分钟即可生成专业可视化结果。通过图形化界面简化传统MCScanX的复杂流程,特别适合非生物信息背景的研究者,显著提升基因组数据分析效率。

dianzhuique8587的博客 377

【大模型微调】魔搭社区GPU进行LLaMA-Factory微调大模型自我认知

本教程介绍如何使用魔搭社区GPU资源和LLaMA-Factory工具进行大模型微调。主要内容包括环境配置、工具安装、模型训练和效果评估。通过LoRA算法进行自我认知微调,详细说明了从数据准备到模型导出的完整流程,并提供了参数调优和显存管理等实用技巧,帮助读者快速掌握大模型定制化训练方法。

LChuck的博客 2924

在ASP.NET中跨页面实现多选

       本文介绍如何在ASP.NET中实现多页面选择的问题。其具体思路很简单:用隐藏的INPUT记住每次选择的项目,在进行数据绑定时,检查保存的值,再在DataGrid中进行选中显示。下面时完整的代码和例子:       查看例子以下是引用片段:SelectMultiPages.aspx  AutoEventWireup="false" Inherits="eMeng.Exam.Se

tian_lee的专栏 468

华为昇腾 910B 实战:DeepSeek-R1 蒸馏模型高效部署与性能调优全解析

本文详细解析了在华为昇腾910B硬件平台上高效部署DeepSeek-R1蒸馏系列模型(14B/32B版本)的完整实战流程。内容涵盖从MindIE环境搭建、镜像获取、模型准备,到服务配置、内存参数调优、性能测试及常见问题排查,为开发者提供了基于昇腾910B进行大模型部署与优化的全链路指南。

weixin_28235513的博客 210

Winform中DatagridView 表头实现一个加上一个checkBox,实现全选选项功能

Winform中DatagridView 表头实现一个加上一个checkBox,实现全选选项功能

munangs的博客 1万+

【WRF-Urban】使用 CGLC-MODIS-LCZ_100m 数据集运行 WRF 时的城市参数化问题

【WRF-Urban】使用 CGLC-MODIS-LCZ_100m 数据集运行 WRF 时的城市参数化问题

WW、forever的博客 709

车载以太网测试-1【TC8物理层测试基础】

车载以太网物理层是车载网络的基础,负责将数字数据转换为适合在物理介质上传输的信号,并确保数据传输的可靠性、稳定性和高效性。它在车载网络系统中扮演着至关重要的角色,直接影响着车辆内部通信的性能和效率。1. 主要物理层标准车载以太网标准由IEEE 802.3和标准名称速率线缆类型编码方式应用场景100BASE-T1100 Mbps单对非屏蔽双绞线车载摄像头、传感器1 Gbps单对屏蔽/非屏蔽双绞线自动驾驶域控制器、高清视频10BASE-T1S10 Mbps单对双绞线幅移键控(ASK)

车载网络测试工程师的博客 4390

C# GridView列头添加CheckBox控件实现全选功

给DevExpress GridView的选择列Header添加CheckBox实现对所有数据行的全选功能 看图: 显示选择行的资料: /// /// C# GridView列头添加CheckBox控件实现全选功能  /// by C/S框架网 www.csframework.com  ///   public class GridCheckMa

4983

7.1华为OD机试真题 新系统 - 仓库盘点 (Java/Py/C/C++/Js/Go)

7.1华为OD机试真题 新系统 - 仓库盘点 (Java/Py/C/C++/Js/Go)

算法大师! 507

vue3+element-plus 表格全选和跨页勾选,以及全选全部功能

这个功能,需要考虑很多交互的逻辑,因为我写的是【全选全部】是一个checkbox的勾选框,所以要考虑取消勾选的功能,自然就有了上面真正实现时的难点。但是如果这个功能是通过一个按钮控制的,点击按钮就代表全选所有操作,那么自然不用考虑取消勾选和禁用的逻辑,因为全选所有时,就已经走完批量全选的流程了。两种实现方式根据业务具体的调整,这次也是为了记录实现这个功能时遇到的问题和思考。

鹤渺的星球 1万+

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

GridView中的CheckBox单击事件(oncheckedchanged)

在GridView中加入 CheckBox控件,想通过单击选中出现如下图所示效果: 具体做法是: 前台GV部份省掉。只加关键的CheckBox部份。 此代码需要注意的是:AutoPostBack="true" 此句的效果是选中后才会执行后台的代码。 后台代码:C#//单独选中 protected void ItemCheckBox_Ch

iflash50的专栏 4312

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Csharp编程指南+参考手册文档分享

 本节提供有关关键的 C# 语言功能和 C# 可通过 .NET Framework 访问的功能的详细信息。 本节中大部分内容都假定您已了解有关 C# 和一般编程概念的一些知识。如果您刚开始学习编程或 C#,则应从 Visual C# 指导教程开始。您可能还想访问 Visual C# 开发中心,此处提供很多教程、示例和视频,可帮助您入门。 有关特定的关键字、运算符和预处理器指令的信息

u013490060的专栏 4244

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

c# Gridview 点击checkbox 触发的事件

今天介绍下gridview中点击checkbox触发的事件,包括全选。 声明下,gridview中的checkbox不是在gridview设计器里面添加的,而是在gridview的属性中设置出来的,具体操作: 这个是触发全选,也可以触发单选。不过这个代码没有怎么判断是否选择了,那么请继续往下看。  private void dgvSheBeiView_SelectionChanged

主要从事JAVA开发,目前是优快云博客Java领域新星创作者、阿里云博客专家、担任公司研发经理、技术负责人等。热爱编程,喜欢在Python、C、C++领域探索。 9288

C#实现checkbox对GridView列表全选

前台 aspx

wwk0125的专栏 2027

编码系列--Base32编码

0、写在前面这里讨论的编码主要的目的是将不可显示的二进制数组转变为可显示的字符串,包括其逆运算。通过特定的协议传输数据,或者加密解密的时候都会用到类似的方法。在这类运算中用的比较多的是Base64,比如MIME中,DotNET中更是直接提供了Base64 Encode和Decode的方法,相当方便。但是Base64通常由“a-z”、“A-Z”、0-9以及“+”和“=”这些符号组成,当中包含

疾风之狼 2万+
上一篇: CSharp Tips:应用程序访问集成Windows认证的站点
下一篇: 编码系列--Base32编码
Mittermeyer
博客等级 码龄25年 60粉丝 28原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值