用python & bat写软件安装脚本 + HM NIS Edit自动生成软件安装脚本

2019-03-11更新:原来NSIS脚本也可以禁用64位文件操作重定向的!

1、在安装脚本的开始处定义 LIBRARY_X64。

!include "MUI.nsh"
!include "Library.nsh"

;如果做32位安装包就把下句注释。
!define LIBRARY_X64

2、在调用涉及目标机器上系统目录(即$SYSDIR)的函数前用 ${DisableX64FSRedirection}。

在安装包的第一个Section中调用一次即可。
!ifdef  LIBRARY_X64
 ${DisableX64FSRedirection}
!endif 

 

之前问题主要在于64位重定向问题,所以自己用python写了个脚本。找到了NSIS禁用重定向方法就可以无论32位还是64位都可以使用NSIS来写脚本了。

 

 

原文:

前些天自己做了一年多的软件成功交付客户,客户提出些完善意见,其中一条就是要一个软件安装脚本。

 

这个之前也尝试python做过,只不过当时有更紧急的任务,最后就没深入尝试。

这次我就捡起了之前的python工程,继续做做。

 

整个过程很简单:

1,把软件解压到客户选择的目录

2,把一个dll程序复制到windows\system32目录

3,创建一个桌面快捷方式

 

因为就这么几步,所以我以为很容易搞,就选择了久违的python自己写,而没有选择一些成熟的自动生成脚本工具。

 

首先肯定要有个界面吧,主要是要用户选择安装目录。我用Tkinter写了个简陋的界面,这个不多说。

 

解压压缩包的话,python有很好的库zipfile:

def unzip(zipFilePath, destDir):
    zfile = zipfile.ZipFile(zipFilePath)
    for name in zfile.namelist():
        (dirName, fileName) = os.path.split(name)
        if fileName == '':
            # directory
            newDir = destDir + '/' + dirName
            if not os.path.exists(newDir):
                os.mkdir(newDir)
        else:
            # file
            fd = open(destDir + '/' + name, 'wb')
            fd.write(zfile.read(name))
            fd.close()
    zfile.close()

 

创建桌面快捷方式python肯定也有库,但我最后选择了使用bat脚本。

set Program=这里要写快捷方式对应的程序目录,且必须是绝对路径。

在python里将这个路径填写上,然后程序里运行bat脚本即可。

@ echo off

set Program=
 
set LnkName=manager software
 
set WorkDir=
 
set Desc=soft
 
if not defined WorkDir call:GetWorkDir "%Program%"
(echo Set WshShell=CreateObject("WScript.Shell"^)
echo strDesKtop=WshShell.SpecialFolders("DesKtop"^)
echo Set oShellLink=WshShell.CreateShortcut(strDesKtop^&"\%LnkName%.lnk"^)
echo oShellLink.TargetPath="%Program%"
echo oShellLink.WorkingDirectory="%WorkDir%"
echo oShellLink.WindowStyle=1
echo oShellLink.Description="%Desc%"
echo oShellLink.Save)>makelnk.vbs
echo SUCCESS
makelnk.vbs
del /f /q makelnk.vbs
exit
goto :eof
:GetWorkDir
set WorkDir=%~dp1
set WorkDir=%WorkDir:~,-1%
goto :eof

 

上面都算顺利,最后竟然在本以为很简单的复制文件到系统目录上出了问题。

不管怎样努力,都没法将文件复制到windows\system32目录下。

一开始本以为是权限问题。

在程序开始前加入这样的代码:

def is_admin():
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False


if is_admin():
    #主程序代码
else:
    # Re-run the program with admin rights
    ctypes.windll.shell32.ShellExecuteW(None, u"runas", unicode(sys.executable), unicode(__file__), None, 1)

这样在运行前就会弹窗要求获取管理员权限。

 

按道理这样程序就已经有了管理员权限了,可还是没有复制到system32目录下。

 

后来在同事帮我看这个问题,他弄了一会,发现其实是64位系统下,系统自动重定向到C:\Windows\SysWOW64目录下了!

所以一定要在复制操作前,禁止重定向。

    with disable_file_system_redirection():
        shutil.copy2('sdfp_lib.dll',os.getenv("SystemDrive")+'\\windows\\system32')

 

上述,便是用python写我的软件自动安装脚本的全过程,后面会附上我的全部代码。

我先再讲下要实现这种软件自动安装脚本需求 最常用最合适的实现方法。

 

其实用工具自动生成就好了!

这个HM NIS Edit工具。

点击文件,选择新建脚本向导。

 

然后按照向导一般的安装,基本的安装需求都可以简单实现。

重点是这一步:

左边可以添加分组,右边可以给每个分组添加安装指令,可以给组添加单独的文件,也可以给组添加主程序目录。每个组再配置安装目标目录。这个目标目录有很多选择,包括系统目录、用户选择目录…………不赘述。

 

这个工具编译好脚本,就生成了一个Setup.exe文件。这就是安装程序。要安装的软件文件都包含在这个exe里了,很厉害。

 

按道理,只要用这个工具就可以完成我的需求了,但在64位系统还有些问题,那就是依然会有系统重定向现象。本来要复制到system32目录下的dll还是会被复制到C:\Windows\SysWOW64下。

 

最后我就决定,做两个版本。

32位的安装程序用HM NIS Edit工具自动生成。

64位我自己用python写。

 

另外,python转化成exe文件的写法,之前文章介绍过:

https://www.cnblogs.com/rixiang/p/7274026.html

 

附上py完整代码:

# -*- coding: utf-8 -*-
from __future__ import print_function
from Tkinter import *
import os
import sys
import subprocess
import shutil

reload(sys)
defaultencoding = 'utf-8'
import ctypes

import tkFileDialog as filedialog
import zipfile
from shutil import copyfile


class disable_file_system_redirection:
    _disable = ctypes.windll.kernel32.Wow64DisableWow64FsRedirection
    _revert = ctypes.windll.kernel32.Wow64RevertWow64FsRedirection
    def __enter__(self):
        self.old_value = ctypes.c_long()
        self.success = self._disable(ctypes.byref(self.old_value))
    def __exit__(self, type, value, traceback):
        if self.success:
            self._revert(self.old_value)
            

def unzip(zipFilePath, destDir):
    zfile = zipfile.ZipFile(zipFilePath)
    for name in zfile.namelist():
        (dirName, fileName) = os.path.split(name)
        if fileName == '':
            # directory
            newDir = destDir + '/' + dirName
            if not os.path.exists(newDir):
                os.mkdir(newDir)
        else:
            # file
            fd = open(destDir + '/' + name, 'wb')
            fd.write(zfile.read(name))
            fd.close()
    zfile.close()

def choose_directory():
    global dir_choosen
    global dir_choosen2
    dir_choosen = filedialog.askdirectory(initialdir='C:')
    # unzip my program to directory choosen
    dir_choosen2 = dir_choosen
    dir_choosen = dir_choosen + '/tgsoft'
    if not os.path.exists(dir_choosen):
        os.makedirs(dir_choosen)
    entryText.set(dir_choosen)

def install():
    if dir_choosen2.strip()=='' or dir_choosen.strip()=='':
        return -1
    unzip('tgsoft.zip',dir_choosen)
    with disable_file_system_redirection():
        shutil.copy2('sdfp_lib.dll',os.getenv("SystemDrive")+'\\windows\\system32')
    str_bat = ''
    f = open('CREATE_SHORTCUT.bat', 'r')
    line = f.readline()             
    while line:
        str_bat+=line
        line = f.readline()
    f.close()
    nPos=str_bat.index('=')+1
    str_bat = str_bat[:nPos]+dir_choosen2+"\\tgsoft\\ManagerSoftware.exe"+str_bat[nPos:]
    f = open('CREATE_SHORTCUT2.bat', 'w') # 若是'wb'就表示写二进制文件
    f.write(str_bat)
    f.close()
    child = subprocess.Popen('CREATE_SHORTCUT2.bat',shell=False)
    # reset the window
    file_label.destroy()
    file_entry.destroy()
    file_btn.destroy()
    b2.destroy()
    w = Label(master, text="安装成功\n感谢使用")
    w.grid(row=0)    

def is_admin():
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False


if is_admin():
    global master
    master = Tk()
    master.title('指静脉注册软件安装程序')
    master.geometry('400x100')
    global file_label
    file_label = Label(master, text="选择软件安装路径")
    file_label.grid(row=0)
    global entryText
    entryText = StringVar()
    global file_entry
    file_entry = Entry(master,textvariable=entryText)
    file_entry.grid(row=0, column=1)
    global file_btn
    file_btn = Button(master, text='点击选择路径', command=choose_directory)
    file_btn.grid(row=0,column=2)
    global b1
    b1 = Button(master, text='  退 出  ', command=master.quit)
    b1.grid(row=1,column=0)
    global b2
    b2 = Button(master, text='  确 定  ', command=install)
    b2.grid(row=1,column=1)
    mainloop()
else:
    # Re-run the program with admin rights
    ctypes.windll.shell32.ShellExecuteW(None, u"runas", unicode(sys.executable), unicode(__file__), None, 1)

 

转载于:https://www.cnblogs.com/rixiang/p/10313014.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
脚本由i-Autoit[AutoitCN专用版]生成 , 2009年05月25日 使用说明: 0.【中键】刷新目标程序窗口信息 包括:标题、文本、控件(类、枚举)、目标窗口进程名 1.【F1】选择目标程序,Au3InfoA.exe隐藏激活 2.【F2】保存目前脚本 3.【F5】新建脚本 4.【File】选择需要打包的资源文件(如图标、文本等) 5..定义变量,输入字符后: 【+】增加变量供随时调用 【$】插入脚本编辑框 选择项: 【Local】【Dim】【Global】【Const】连同输入框字符一起插入 【$】只插入输入框字符作为变量使用 6.【Win】=WinWaitActive ( "窗口标题", "窗口文本"} 自动插入激活目标窗口的语句 7.【Send】模拟键盘相关命令,可自定义 8.【SendX】发送文字,获取目标控件信息(类、枚举)后,选择【中文】或者【英文】 8.【选空】uncheck控件;【选中】check控件 9.【Click】模拟点击控件,可自定义为双击 10.【Tree】下一版本实现该功能 11.【Select】选择下拉列表的子项 12.【MClick】模拟点击屏幕任意位置 13.【XClick】增强模拟点击,使脚本适用于任意PC,下一版本实现该功能 14.【Adlib】检测意外进程和弹窗并强制关闭 15.【进程】【弹窗】查杀已知进程和弹窗 16.【Delete】默认为【本机】,选【其他】使脚本适用于任何PC 17.【AutoRun】添加任意存在文件到注册表自启动项 18.【DelRun】删除指定注册表启动项 19.【测试】自动生成脚本,并可选择测试任意已存在脚本 20.【编译】选择脚本对象和编译图标之后,编译为任意PC可执行的exe

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值