├── LICENSE ├── README.md └── src ├── config └── mainForm.table ├── default.aproj ├── lib └── config.aardio ├── main.aardio └── res ├── donate.png ├── exeicon.ico ├── info.png └── shortcut.png /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 bituplink 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | ================================================================================= 24 | 25 | 版权(c) 2018 bituplink 26 | 27 | 使用该许可证的软件被授予以下权限,免费,任何人可以得到这个软件及其相关文档的一个拷贝,并且 28 | 经营该软件不受任何限制,包括无限制的使用、复制、修改、合并、出版、发行、发放从属证书、或者 29 | 出售该软件的拷贝的权利。同时允许获得这些软件的用户享受这些权利,使其服从下面的条件: 30 | 31 | 以上的版权通知和权限通知应该包含在所有该软件的拷贝中或者是其他该软件的真实部分中。 32 | 该软件按本来的样子提供,没有任何形式的担保,不管是明确地或者暗含的,包含这些但是不受商业性质 33 | 的担保的限制。适合一个特定的用途并且不受侵犯。作者和版权持有人在任何场合对使用该软件涉及的 34 | 任何要求、损害或者其他责任都不应负责。不管它是正在起作用还是只是合同形式、民事侵权或是其他 35 | 方式,如由它引起,在其作用范围内、与该软件有联系、该软件的使用或者有这个软件引起的其他行为。 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # checkFileHash 2 | 这是一个对文件进行md5和sha值校验的小工具,支持拖拽,复制信息到剪贴板,以及另存文件,勾选输出项等特性,代码基于aardio开发 3 | 4 | ##### 更新记录 5 | * 2019.05.16 v0.7版本发布,修改了程序bug,增加了crc,sha384,sha512校验方式,增加了创建桌面快捷方式和置顶的功能 6 | 7 | ![snapshot](https://imgsrc.io/images/2019/05/16/checkFileHash-v0.7.png) 8 | 9 | ##### 程序优点: 10 | * win平台全支持,无需其他额外的组件支持 11 | * 小巧,单文件,只有500K,拥有UI界面,交互简单便捷 12 | * 支持拖拽文件,保存结果,灵活选择输出内容 13 | * 支持勾选输出选项,支持记忆勾选内容 14 | * 支持创建快捷方式 15 | * 支持窗口置顶 16 | 17 | ##### 获得exe执行程序 18 | * github releases下载: [releases](https://github.com/bituplink/checkFileHash/releases) 19 | * 访问官网下载: [官网](http://www.bituplink.com/windows_checkfilehash.html) 20 | * 访问百度云盘下载: [百度网盘](https://pan.baidu.com/s/1khtOU-FCWWqk4RRwJSJYQw) 密码: s6s3 21 | * 下载源码,并使用[aardio IDE](http://ide.update.aardio.com/releases/aardio.7z)加载项目文件(src目录下),运行并发布后,在publish目录下获得 22 | 23 | ### 运行说明 24 | * 下载exe文件,放在任意目录下,双击exe打开并执行程序 25 | * 按照需求勾选或者去勾选右侧的选项 26 | * 点击按钮添加文件,或者直接拖拽文件到软件框内 27 | * 点击复制按钮将输出结果复制到系统粘贴板(可选) 28 | * 点击并选择好位置,然后校验结果到文本文件中(可选) 29 | * 软件是绿色软件,只会在软件所在目录生成配置项文件,建议单独创建一个目录保存,并在桌面建立快捷方式 30 | 31 | 32 | ### 建议和改进 33 | 1. github提issue 34 | 2. 发送邮件到 bituplink@protonmail.com 35 | 36 | 37 | ### 捐助 38 | 如果觉得程序对你有帮助或者想要支持我(毕竟写程序和调试代码也是很费时费力的,哎呦,我的酸脖子和鼠标手呀 ┬_┬),可以小额赞助下 39 | 40 | 方式一: 支付宝捐助 41 | * ![alipay](http://www.bituplink.com/wp-content/uploads/alipay.png) 42 | 43 | 方式二: 微信捐助 44 | * ![wxpay](http://www.bituplink.com/wp-content/uploads/wxpay.png) 45 | -------------------------------------------------------------------------------- /src/config/mainForm.table: -------------------------------------------------------------------------------- 1 | {checkboxSha1=1;checkboxSha384=0;afterLoad=null;checkboxShowSize=1;checkboxSha256=1;checkboxModTime=1;beforeSave=null;checkboxSha512=0;checkboxShowName=1;checkboxMd5=1;checkboxCrc=0} 2 | -------------------------------------------------------------------------------- /src/default.aproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/lib/config.aardio: -------------------------------------------------------------------------------- 1 | //config 配置文件 2 | import fsys.config; 3 | config = ..fsys.config("/config/"); 4 | 5 | /** 6 | config = ..fsys.config( 7 | ..fsys.joinpath( ..fsys.getSpecial( 0x1c /*_CSIDL_LOCAL_APPDATA*/ ),"应用程序名" ) 8 | ); 9 | **/ 10 | 11 | //不需要序列化的配置名字前请添加下划线 12 | namespace config { 13 | __appName = "checkFileHash"; 14 | __appVersion = "0.7"; 15 | __appDescription = "文件哈希校验工具"; 16 | __website = "http://www.bituplink.com/"; 17 | } 18 | 19 | /**intellisense(config) 20 | __appName = 应用程序名 21 | __appVersion = 应用程序内部版本号 22 | __appDescription = 程序说明 23 | __website = 官方网站 24 | 25 | saveAll() = 写入所有配置到文件 26 | mainForm.load() = 从配置文件(文件名"default")载入\n加载成功返回对象,加载失败返回null空值\n!fsys_table. 27 | mainForm.save() = 存储到配置文件(文件名"default") 28 | mainForm.mixin = @.mixin(\n 键名 = 值__;\n 键名 = 值;\n);//该数会自动调用save函数保存配置到文件 29 | mainForm.控件名称 = 控件默认值\n调用save()函数同步控件当前值 30 | mainForm.属性名 = 自配置文件(文件名"default")读写属性\n属性值可以是支持序列化的普通变量,支持table对象.\n配置文件在首次使用时自动加载,退出程序时自动保存. 31 | ? = 配置文件名,\n读写配置并序列化为一个表对象,\n表的成员值可以是支持序列化的普通变量,支持table对象\n配置文件在首次使用时自动加载,退出程序时自动保存\n!fsys_table. 32 | end intellisense**/ 33 | -------------------------------------------------------------------------------- /src/main.aardio: -------------------------------------------------------------------------------- 1 | import win; 2 | import win.ui; 3 | import win.ui.menu; 4 | import fsys.dlg; 5 | import fsys; 6 | import fsys.file; 7 | import win.clip; 8 | import win.ui.tooltip; 9 | import process; 10 | import win.ui.atom; 11 | import crypt; 12 | import crypt.hmac; 13 | import console; 14 | import fsys.lnk; 15 | /*DSG{{*/ 16 | mainForm = win.form(text="文件哈希校验 v0.7 by bituplink.com";right=567;bottom=294;acceptfiles=1;border="dialog frame";max=false) 17 | mainForm.add( 18 | btnAddFile={cls="button";text="添加文件";left=0;top=1;right=104;bottom=34;z=2}; 19 | btnCopyResult={cls="button";text="复制结果";left=104;top=1;right=208;bottom=34;z=3}; 20 | btnSaveResult={cls="button";text="保存结果";left=208;top=1;right=312;bottom=34;flat=1;z=4}; 21 | buttonClear={cls="button";text="清空记录";left=312;top=1;right=416;bottom=34;flat=1;z=16}; 22 | checkboxCrc={cls="checkbox";text="CRC32值";left=472;top=253;right=549;bottom=270;z=11}; 23 | checkboxMd5={cls="checkbox";text="MD5值";left=472;top=122;right=553;bottom=141;checked=1;z=6}; 24 | checkboxModTime={cls="checkbox";text="修改时间";left=472;top=97;right=553;bottom=115;checked=1;z=13}; 25 | checkboxSha1={cls="checkbox";text="SHA1值";left=472;top=149;right=553;bottom=168;checked=1;z=7}; 26 | checkboxSha256={cls="checkbox";text="SHA256值";left=472;top=175;right=553;bottom=194;checked=1;z=12}; 27 | checkboxSha384={cls="checkbox";text="SHA384值";left=472;top=201;right=553;bottom=220;z=14}; 28 | checkboxSha512={cls="checkbox";text="SHA512值";left=472;top=227;right=553;bottom=246;z=15}; 29 | checkboxShowName={cls="checkbox";text="文件名称";left=472;top=47;right=553;bottom=65;checked=1;z=8}; 30 | checkboxShowSize={cls="checkbox";text="文件大小";left=472;top=72;right=553;bottom=90;checked=1;z=5}; 31 | editShowZone={cls="edit";text='鼠标拖拽文件到这里,或者点击上方"添加文件"按钮';left=1;top=35;right=463;bottom=293;bgcolor=16777215;edge=1;font=LOGFONT(name='宋体');hscroll=1;multiline=1;readonly=1;z=1}; 32 | plusDonate={cls="plus";left=469;top=7;right=495;bottom=33;foreRepeat="center";foreground="\res\donate.png";notify=1;repeat="center";z=9}; 33 | plusHelpInfo={cls="plus";left=501;top=7;right=527;bottom=33;foreRepeat="center";foreground="\res\info.png";notify=1;repeat="center";z=10}; 34 | plusShortcut={cls="plus";left=533;top=7;right=559;bottom=33;foreRepeat="center";foreground="\res\shortcut.png";notify=1;repeat="center";z=18}; 35 | static_top={cls="static";text="窗口置顶";left=417;top=9;right=468;bottom=27;notify=1;transparent=1;z=17} 36 | ) 37 | /*}}*/ 38 | 39 | // 单实例运行功能 40 | var atom,hwndConflict = mainForm.atom("C90B636F-54A5-4DC2-98A7-62FF5276F411"); 41 | if(!atom){ 42 | /*为窗口设置原子值可以避免一个程序重复运行多个实例*/ 43 | win.quitMessage();//程序退出 44 | return; 45 | }; 46 | 47 | // 增加用户设置项配置能力 48 | import config; 49 | mainForm.bindConfig( config.mainForm,{ 50 | checkboxShowName = "checked"; 51 | checkboxShowSize = "checked"; 52 | checkboxModTime = "checked"; 53 | checkboxMd5 = "checked"; 54 | checkboxSha1 = "checked"; 55 | checkboxSha256 = "checked"; 56 | checkboxSha384 = "checked"; 57 | checkboxSha512 = "checked"; 58 | checkboxCrc = "checked"; 59 | 60 | } ); 61 | 62 | // 在窗口上创建tooltip对象, mainForm是界面主窗口的名称,可以改变,但是需要保持一致 63 | var toolTipObj = win.ui.tooltip(mainForm); 64 | 65 | // 给控件添加悬停提示, btnAddFile是之前创建的按键控件的名称, 0x10/*_TTF_SUBCLASS*/参数表示默认提示 66 | toolTipObj.addTool(mainForm.btnAddFile, "点击打开选择文件对话框,选择需要校验的文件", 0x10/*_TTF_SUBCLASS*/ ); 67 | toolTipObj.addTool(mainForm.btnCopyResult, "拷贝校验结果到剪切板", 0x10/*_TTF_SUBCLASS*/ ); 68 | toolTipObj.addTool(mainForm.btnSaveResult, "将校验结果另存到指定位置和名称的文件", 0x10/*_TTF_SUBCLASS*/ ); 69 | toolTipObj.addTool(mainForm.buttonClear, "清空显示的校验结果", 0x10/*_TTF_SUBCLASS*/ ); 70 | 71 | toolTipObj.addTool(mainForm.plusDonate, "捐助支持我", 0x10/*_TTF_SUBCLASS*/ ); 72 | toolTipObj.addTool(mainForm.plusHelpInfo, "访问官网获取更多信息", 0x10/*_TTF_SUBCLASS*/ ); 73 | toolTipObj.addTool(mainForm.static_top, "点击切换窗口置顶状态", 0x10/*_TTF_SUBCLASS*/ ); 74 | toolTipObj.addTool(mainForm.plusShortcut, "生成桌面快捷方式", 0x10/*_TTF_SUBCLASS*/ ); 75 | 76 | 77 | // 拖放会触发onDropFiles事件 78 | mainForm.onDropFiles = function(files){ 79 | // 软件只接受单文件的校验,不处理文件列表,只取一个文件 80 | getAndCheckFile(files[1]); 81 | } 82 | 83 | mainForm.btnAddFile.oncommand = function(id,event){ 84 | var fileAddedInfo = fsys.dlg.open("所有文件|*.*|"); 85 | 86 | getAndCheckFile(fileAddedInfo); 87 | } 88 | 89 | mainForm.btnCopyResult.oncommand = function(id,event){ 90 | win.clip.write(mainForm.editShowZone.text) 91 | } 92 | 93 | mainForm.btnSaveResult.oncommand = function(id,event){ 94 | 95 | // 如果没有内容也不保存到文件,通过获取内容的长度进行判断 96 | if(!#mainForm.editShowZone.text){ 97 | mainForm.msgbox("还没有哈希校验结果无法保存,请先进行校验!") 98 | return; 99 | } 100 | 101 | fileOutputInfo = fsys.dlg.save("文本文件|*.txt|", "另存为", dir, mainForm.hwnd, , "文件哈希校验结果.txt") 102 | 103 | // 如果取消选择,需要先判断文件路径是否存在,不存在则不执行下面的文件 104 | if(fileOutputInfo == null){ 105 | return; 106 | } 107 | 108 | string.save(fileOutputInfo, mainForm.editShowZone.text); 109 | } 110 | 111 | function getAndCheckFile(fileAdded){ 112 | 113 | // 清空上一次的数值,确保一次只保留一份校验结果 114 | mainForm.editShowZone.text = ""; 115 | 116 | //如果取消选择,需要先判断文件路径是否存在,不存在则不执行下面的文件 117 | if(fileAdded == null){ 118 | return; 119 | } 120 | 121 | // 根据文件路径加载文件,获取文件名 122 | var fileAddedName = io.splitpath(fileAdded).file; 123 | 124 | if(mainForm.checkboxShowName.checked){ 125 | mainForm.editShowZone.appendText("文件名称: " ,fileAddedName, '\r\n'); 126 | } 127 | 128 | // 获取文件的大小,默认单位byte 129 | fileAddedObj = fsys.file(fileAdded); 130 | var fileAddedSize64 = fileAddedObj.size64(); 131 | 132 | var file_size_bytes = tonumber(fileAddedSize64); 133 | var file_size_string = ""; 134 | 135 | if(mainForm.checkboxShowSize.checked){ 136 | 137 | if(file_size_bytes <= 1024){ 138 | file_size_string = file_size_bytes + " bytes"; 139 | } 140 | elseif(file_size_bytes > 1024 && file_size_bytes < 1048576){ 141 | file_size_string = string.format("%.2f", (file_size_bytes / 1024)) + " KB "; 142 | file_size_string = file_size_string + "(" + file_size_bytes + " bytes" + ")"; 143 | } 144 | elseif(file_size_bytes = 1048576){ 145 | file_size_string = "1 MB "; 146 | file_size_string = file_size_string + "(" + file_size_bytes + " bytes" + ")"; 147 | } 148 | elseif(file_size_bytes > 1048576 && file_size_bytes < 1073741824){ 149 | file_size_string = string.format("%.2f",(file_size_bytes / (1024 * 1024))) + " MB "; 150 | file_size_string = file_size_string + "(" + file_size_bytes + " bytes" + ")"; 151 | } 152 | elseif(file_size_bytes = 1073741824){ 153 | file_size_string = "1 GB "; 154 | file_size_string = file_size_string + "(" + file_size_bytes + " bytes" + ")"; 155 | } 156 | elseif(file_size_bytes > 1073741824 && file_size_bytes < 1099511627776){ 157 | file_size_string = string.format("%.2f", (file_size_bytes / (1024 * 1024 * 1024))) + " GB "; 158 | file_size_string = file_size_string + "(" + file_size_bytes + " bytes" + ")"; 159 | } 160 | else { 161 | file_size_string = "文件超过1TB "; 162 | file_size_string = file_size_string + "(" + file_size_bytes + " bytes" + ")"; 163 | } 164 | 165 | mainForm.editShowZone.appendText("文件大小: " ,file_size_string, '\r\n'); 166 | } 167 | 168 | 169 | // 获取最后一次修改时间 170 | fileTime = fileAddedObj.getTime(); 171 | fileLastModifyTime = fileTime.write.local(true) 172 | fileLastModifyTime.format = "%Y-%m-%d %H:%M:%S" 173 | 174 | if(mainForm.checkboxModTime.checked){ 175 | mainForm.editShowZone.appendText("修改时间: ",tostring(fileLastModifyTime) , '\r\n'); 176 | } 177 | 178 | // 179 | var md5 = crypt().createHashByMd5(); 180 | var sha1 = crypt().createHashBySha1(); 181 | var crc32; 182 | var sha256 = crypt(,0x18/*_PROV_RSA_AES*/).createHash(0x800C/*_CALG_SHA_256*/); 183 | var sha384 = crypt(,0x18/*_PROV_RSA_AES*/).createHash(0x800D/*_CALG_SHA_384*/); 184 | var sha512 = crypt(,0x18/*_PROV_RSA_AES*/).createHash(0x800E/*_CALG_SHA_512*/); 185 | 186 | var fileAdded,err = io.open(fileAdded, "rbR");//R 随机优化 187 | if(!fileAdded) { 188 | mainForm.editShowZone.appendText( "打开文件失败: " , path , '\n',err , '\n' ); 189 | return; 190 | } 191 | 192 | var bufSize = 0xA00000 193 | while ( 194 | var buffer,readSize = raw.buffer( bufSize ); 195 | readSize = fileAdded.readBuffer(buffer); //读文件 196 | readSize 197 | ){ 198 | md5.hashBuffer(buffer,readSize); 199 | sha1.hashBuffer(buffer,readSize); 200 | crc32 = string.crc32(buffer,crc32,readSize); 201 | sha256.hashBuffer(buffer,readSize); 202 | sha384.hashBuffer(buffer,readSize); 203 | sha512.hashBuffer(buffer,readSize); 204 | } 205 | 206 | fileAdded.close(); 207 | 208 | if(mainForm.checkboxMd5.checked){ 209 | mainForm.editShowZone.appendText("MD5值: " , md5.getHexValue(), '\r\n'); 210 | } 211 | 212 | if(mainForm.checkboxSha1.checked){ 213 | mainForm.editShowZone.appendText("SHA1值: " , sha1.getHexValue(), '\r\n'); 214 | } 215 | 216 | if(mainForm.checkboxSha256.checked){ 217 | mainForm.editShowZone.appendText("SHA256值: " , sha256.getHexValue(), '\r\n'); 218 | } 219 | 220 | if(mainForm.checkboxSha384.checked){ 221 | mainForm.editShowZone.appendText("SHA384值: " , sha384.getHexValue(), '\r\n'); 222 | } 223 | 224 | if(mainForm.checkboxSha512.checked){ 225 | mainForm.editShowZone.appendText("SHA512值: " , sha512.getHexValue(), '\r\n'); 226 | } 227 | 228 | if(mainForm.checkboxCrc.checked){ 229 | mainForm.editShowZone.printf('CRC32值: %X', crc32 ); 230 | } 231 | 232 | } 233 | 234 | mainForm.plusDonate.oncommand = function(id,event){ 235 | process.execute("http://www.bituplink.com/donate"); 236 | } 237 | 238 | mainForm.plusHelpInfo.oncommand = function(id,event){ 239 | process.execute("http://www.bituplink.com/windows_checkfilehash.html"); 240 | } 241 | 242 | mainForm.buttonClear.oncommand = function(id,event){ 243 | // 清空上一次的数值 244 | mainForm.editShowZone.text = ""; 245 | } 246 | 247 | mainForm.static_top.oncommand = function(id,event){ 248 | if(mainForm.static_top.text = "窗口置顶"){ 249 | win.setTopmost(mainForm.hwnd,true) 250 | mainForm.static_top.text = "取消置顶" 251 | }else{ 252 | win.setTopmost(mainForm.hwnd,false) 253 | mainForm.static_top.text = "窗口置顶" 254 | } 255 | } 256 | 257 | mainForm.plusShortcut.skin( 258 | background = { 259 | hover = "/res/images/btn-hover.png"; 260 | focus = "/res/images/btn-focus.jpg"; 261 | active = "/res/images/btn-active.png"; 262 | disabled = "/res/images/btn-disabled.png"; 263 | } 264 | ) 265 | 266 | mainForm.plusShortcut.oncommand = function(id,event){ 267 | //创建桌面快捷方式 268 | lnk = fsys.lnk(); 269 | lnk.description = "checkFileHash快捷方式" 270 | 271 | lnk.path = io._exepath //设置目标路径 272 | lnk.setIcon(io._exepath, 0); //设置图标 273 | 274 | lnk.save(fsys.joinpath(fsys.getSpecial(0x0010 /*_CSIDL_DESKTOPDIRECTORY*/ ) ,"checkFileHash.lnk" )) 275 | } 276 | 277 | mainForm.enableDpiScaling(); 278 | mainForm.show(); 279 | 280 | return win.loopMessage(); 281 | -------------------------------------------------------------------------------- /src/res/donate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bituplink/checkFileHash/87b72ff0cdc9ed5cc4b7e2e993ffa3ea51b66f76/src/res/donate.png -------------------------------------------------------------------------------- /src/res/exeicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bituplink/checkFileHash/87b72ff0cdc9ed5cc4b7e2e993ffa3ea51b66f76/src/res/exeicon.ico -------------------------------------------------------------------------------- /src/res/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bituplink/checkFileHash/87b72ff0cdc9ed5cc4b7e2e993ffa3ea51b66f76/src/res/info.png -------------------------------------------------------------------------------- /src/res/shortcut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bituplink/checkFileHash/87b72ff0cdc9ed5cc4b7e2e993ffa3ea51b66f76/src/res/shortcut.png --------------------------------------------------------------------------------