找回密码
 加入
搜索
查看: 11746|回复: 20

[系统综合] 请教: AU3 操作Access 的问题, 密码错误脚本异常退出! (已解决)

 火.. [复制链接]
发表于 2012-4-27 19:12:31 | 显示全部楼层 |阅读模式
本帖最后由 user3000 于 2012-4-29 17:48 编辑

已自行找到解决方法, 具体情况请参阅15楼的上一楼!

用AU3 语句试图访问有密码的数据库时,  如果密码是错误的, 将会产生致命性崩溃错误, 如同引用数组时, 下标越界了!
搜索论坛内, 相关信息很少; 至少我只有在这个帖子顶楼的最后面看到这么一句:" 注意:如果旧密码不对的时候,会出错。到现在我还没有找到解决办法。同时也希望那位高手能完善这段代码。"
可惜, 没有任何相关回音.
相关帖子: 用ADO更改ACCESS数据库密码
http://www.autoitx.com/forum.php ... cess%2B%C3%DC%C2%EB

最近研究了点数据库操作相关的知识, 发现帮助里相关的 Access 操作已经跟不上'形势'了!
第1个, 它没有考虑打开有密码的数据库! 我发现有坛友说, access 数据库加密码等于没有? 很容易被破解?
第2个, 我以前用的时候, 就发现该UDF实现不了精确查找, 它的函数中唯一能返回以行为单位是 _accessQueryLike ;
          可是, 它工作方式是类似 StringInStr, 只要那一行的那字段(列)包含了查找字符串, 就将全都会被返回! 所以, 不能当作精确查找!
          比如下面这个表, 如果是查找游戏名为天龙八部的游戏, 所有数据行都会被返回!
         

    游戏名称     游戏类型
    天龙八部     单机游戏
    天龙八部2   单机游戏
    天龙八部2   网络游戏
    天龙八部3   网络游戏


这几天就有了一种冲动, 想把 access.au3 的函数全部更新一下, 增加支持密码操作, 增加精确查找等操作...
精确查找操作的函数已经几乎完成了, 但现在发现了如标题所说的错误, 这实在让人深受打击, 不能解决这问题, 做出来的UDF可以说存在致命性缺陷了!

还有, access的安全性确实低到让人可以不考虑给它上密码的程度吗?!
请跟帖发言的朋友提出有意义或有用的意见或建议, 严禁发无意义的话语, 否则不要怪我给他-20的评分了!
发表于 2012-4-27 21:22:25 | 显示全部楼层
本帖最后由 netegg 于 2012-4-27 21:24 编辑

密码的问题不清楚,不过精确查找貌似access本身就没有,换句话说,所谓的精确查找更确切说是脱离access后的数据操作
另外,你给的那个例子说明的是什么,指定字段内查找?这个原来的access udf里有啊_accessQueryStr
 楼主| 发表于 2012-4-27 21:58:47 | 显示全部楼层
本帖最后由 user3000 于 2012-4-27 23:42 编辑

回复 2# netegg
_accessQueryStr 除了确认该字符串在数据库存在外, 完全没有别的用处吧?
它是: 数据存在, 则返回字符串本身!

我说的精确查找应当如我下面的函数:

(考虑不周, 已取消隐藏, 请用心给予回复!)
#Region
#cs
 ;  函数名 _accessQueryStrEX  , 作用: 按已知字段值, 获取该行特定字段的数据.  
   应该还要加上字段名的判断, 如果第4个参数, 设置了不存在的字段字, 会返回空值!
         ;  参数说明: 1,  $DB_Path  数据库文件(非脚本目录下需列出绝对路径)
                           2, $DB_Table  要查询的数据表名
                           3, $Finds         查询条件, 有格式要求. 接受数组, 类似: Local $Finds[3] = ['pcname', 'pc001', 'pcoo2']
                                                                                 或字符串, 类似:  Local $Finds = 'PCName|PC001|PC002'
                                                                                 其中: PCName 为字段(列)名 , pc001 和 pc002 为该字段下某一行的数值)
                          4,  $return_Columns = '*'     要求查询后返回的字段(列)的数据,  默认是所有字段
                                                                       如上面的查询条件, 将返回跟 pc001 及 pc002 有关的那行(所有字段)的所有数据. 
                          5, $password = Default     数据库的密码, 默认是不用密码的方式打开数据库.
                          6, $CloseDB = True            查询结束是否关闭已打开的数据库. 默认操作是关闭. ; 不知道有用不?
                          
         查询成功: 
                        返回一数组:  $Array[n][2]
                                          $Array[0][0] 查询到的数据串数量
                                          $Array[1][0]  ... $Array[n][0] 有关字段名的字符串, 以 '|' 字符分隔, 
                                          $Array[1][1]  ... $Array[n][1] 有关各行数据的字符串, 也是以 '|' 分开.
       查询失败:
                    返回 -1 并设置 @errer
                     @errer 1  打开数据库失败
                     @errer 2  设置的查找条件有误?
                     @errer 3  第3个参数错误, 符合格式要求
N 维2#ce
#endregion

$query = _accessQueryStrEX(@ScriptDir & "\sys1.mdb", 'group1', 'PCName|ooo|PC001|pc002|pc003', 'PcName,IPaddress', 123)
If Not @error Then
        MsgBox(0, 'number', $query[0][0])
        For $i = 1 To $query[0][0]
                MsgBox(0, $query[$i][0], $query[$i][1])
        Next
Else
        MsgBox(0, 'err', @error)
EndIf

Func _accessQueryStrEX($DB_Path, $DB_Table, $Finds, $return_Columns = '*', $password = Default, $CloseDB = True)
        $oADO = _OpenDaTaBase($DB_Path, $password)

        $rs = ObjCreate("ADODB.recordset")
        $rs.ActiveConnection = $oADO
        If IsObj($rs) = 0 Then Return SetError(1, 0, -1)
        
        Local $find, $row
        If IsArray($Finds) Then
                $row = UBound($Finds)
                If $row = 1 Then Return SetError(3, 0, -1) ; 错误的查找条件参数
                $find = ' where ' & $Finds[0] & " in ('" & $Finds[1] & "'"
                For $i = 2 To UBound($Finds) - 1
                        $find &= ",'" & $Finds[$i] & "'"
                Next
                $find &= ')'
        ElseIf StringInStr($Finds, '|') Then
                $s = StringSplit($Finds, '|')
                $row = $s[0]
                $find = ' where ' & $s[1] & " in ('" & $s[2] & "'"
                For $i = 3 To $s[0]
                        $find &= ",'" & $s[$i] & "'"
                Next
                $find &= ')'
        Else
                Return SetError(3, 0, -1) ; 错误的查找条件参数
                ; Chr(42 * 星号, 代表查询并返回所有列
        EndIf
        
        $sql = "select " & $return_Columns & " from " & $DB_Table & $find
        $rs.Open($sql, $oADO)
        If $rs.bof Or $rs.eof Then Return SetError(2, 0, -1) ; 查找失败, 可能是查找的条件不正确
        Local $return[$row][2], $count = 0
        
        While Not $rs.BOF And Not $rs.EOF
                $count += 1
                If $count == $row Then ExitLoop
                ;If @error Then ExitLoop
                For $x In $rs.Fields
                        
                        If $x.name <> '' And $x.value <> '' Then
                                $return[$count][0] &= $x.name & Chr(124) ; Chr(124) 垂直线
                                $return[$count][1] &= $x.value & Chr(124)
                        EndIf
                Next
                $return[$count][0] = StringTrimRight($return[$count][0], 1)
                $return[$count][1] = StringTrimRight($return[$count][1], 1)
                
                $rs.MOVENEXT
        WEnd
        $return[0][0] = $count
        
        If $CloseDB Then
                $rs.Close
                $oADO.Close
        EndIf
        Return $return
EndFunc   ;==>_accessQueryStrEX

;#cs
Func _adoProvider() ; 获取当前系统的 Access 数据库驱动版本
        Local $oProvider = "Microsoft.Jet.OLEDB.4.0; "
        Local $objCheck = ObjCreate("Access.application")
        If IsObj($objCheck) Then
                Local $oVersion = $objCheck.Version
                If StringLeft($oVersion, 2) == "12" Then $oProvider = "Microsoft.ACE.OLEDB.12.0; "
        EndIf
        Return $oProvider
EndFunc   ;==>_adoProvider
;#ce
Func _OpenDaTaBase($DB_Path, $password = Default)
        Local $oADO = 'ADODB.Connection'
        If IsObj($oADO) Then
                $oADO = ObjGet('', $oADO)
        Else
                $oADO = ObjCreate("ADODB.Connection")
                $oADO.Provider = _adoProvider()
                If $password = Default Then
                        $oADO.Open($DB_Path)
                Else
                        $oADO.Open("Data Source=" & $DB_Path & ";Jet Oledb:Database Password=" & $password)
                EndIf
        EndIf
        Return $oADO
EndFunc   ;==>_OpenDaTaBase


以下是可作测试用的带密码的数据库文件:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
发表于 2012-4-27 22:24:51 | 显示全部楼层
你看看_accessQueryStr的第四个参数
发表于 2012-4-27 22:33:24 | 显示全部楼层
回复学习一下
发表于 2012-4-27 22:36:40 | 显示全部楼层
回复  netegg
_accessQueryStr 除了确认该字符串在数据库存在外, 完全没有别的用处吧?
它是: 数据存在,  ...
user3000 发表于 2012-4-27 21:58


user3000兄,没想到下面加了“必须参与讨论者才可观看”,只是好奇,抱歉
发表于 2012-4-27 22:37:04 | 显示全部楼层
本帖最后由 netegg 于 2012-4-27 23:00 编辑

作为闲话,这样做的好处是什么,如果有必要的话,_accessSaveXML就一切ok(可能需要正则或者其他方式处理下)

试了下,_accessQueryStr确实有点鸡肋
发表于 2012-4-27 22:39:18 | 显示全部楼层
_accessQueryStr这个没什么用,返回本身的,我都不用那个udf了,我是下别人的源码来改
发表于 2012-4-27 23:30:23 | 显示全部楼层
本帖最后由 风行者 于 2012-4-27 23:31 编辑

对于ACCESS数据库加密码只要将access.au3内部函数_dbOpen和 _accessCreateDB 改一改就可以,没必要写新函数
不过还是建议改用sqlite
 楼主| 发表于 2012-4-27 23:40:48 | 显示全部楼层
回复 7# netegg
    我觉得 UDF 的意义在于使用的普遍性及方便性!  不方便, 没有人会去用它! 没有普遍性, UDF则不值得花时间去编写!
    当一个没有数据库操作基础的人尝试操作数据库时,  一个良好的UDF, 必然是他一条大道, 可以帮他节省大量时间和精力;  有心人甚于可以通过这条路'入门' 相关的数据库基础操作!
   如果已经懂得用 _accessSaveXML 来搞定问题, 我想他应该也有修改相关UDF来达到自己的目的了吧!

   我这样做, 也是想给自己实践的机会吧? 把 AU3 及 acceess 的操作尽可能完美的结合在一起. 希望能为  中文版 AU3 作出一点贡献吧!
发表于 2012-4-27 23:45:21 | 显示全部楼层
回复 10# user3000

这话我同意,所以我才说我说的是闲话,只是多个方法而已,具体如何操作当然是使用者的事情
 楼主| 发表于 2012-4-27 23:48:06 | 显示全部楼层
对于ACCESS数据库加密码只要将access.au3内部函数_dbOpen和 _accessCreateDB 改一改就可以,没必要写新函数 ...
风行者 发表于 2012-4-27 23:30


改了 就是 新的了
会改的人, 估计都不会用这些函数, 而是直接自己写代码, 弄出符合自己使用的函数!

论坛里不少帖子都是这样! 如果能整理融合到新版的 AU3 中, 不是更能方便后人?
发表于 2012-4-28 01:50:23 | 显示全部楼层
回复 12# user3000
这个也同意,但是udf首先考虑的不应该是结果,而是排错,除非能把所有的错误情况都写齐了,否则起到的作用可能并不是方便,而是更迷惑

当然自己用是另一码事
 楼主| 发表于 2012-4-29 17:45:59 | 显示全部楼层
找到解决问题的方法了!
其实就在帮助里的" OLE/COM 参考".
不多说了, 有兴趣者请自行查阅该帮助! 只不过很多内容没汉化!
以前也正因为这个原因所以没怎么用心看该帮助! 打算抽点时间把这内容全汉化, 再放到中文资料版块去!

以下例子, 可以完全做到操作对象的容错!
(是借用别人的代码加入了检错代码)
Global $g_eventerror = 0, $oswf
$oMyError = ObjEvent("AutoIt.Error", "MyErrFunc") 
; 建立捕捉错误事件, 如果不建立, 运行至代码 $oswf.width = @DesktopWidth 脚本将崩溃!
_Form()
$oswf.width = @DesktopWidth
If $g_eventerror Then ConsoleWrite("上一行代码运行, 有错误发生了(1).")
$oswf.height = @DesktopHeight
If $g_eventerror Then ConsoleWrite("上一行代码运行, 有错误发生了(2).")
While 1
        Switch GUIGetMsg()
                Case -3
                        Exit
        EndSwitch
WEnd
Func _Form()
        $hForm = GUICreate("form", 600, 400)
        GUISetBkColor(0x000000)
        $oswf = ObjCreate("ShockwaveFlash.ShockwaveFlash.10")
        $octrl = GUICtrlCreateObj($oswf, 0, 0, 400, 300)
        GUISetState()
        $oswf.movie = "http://player.youku.com/player.php/sid/XMzYyOTM2MDA0/isAutoPlay/true/v.swf"
        Sleep(3000)
        GUISetState(@SW_MAXIMIZE)
EndFunc   ;==>_Form
Func MyErrFunc() ; 该函数完全抄自帮助文件
        $HexNumber = Hex($oMyError.number, 8)
        MsgBox(0, "", "We intercepted a COM Error !" & @CRLF & _
                        "Number is: " & $HexNumber & @CRLF & _
                        "Windescription is: " & $oMyError.windescription)

        $g_eventerror = 1 ; something to check for when this function returns
EndFunc   ;==>MyErrFunc

评分

参与人数 1贡献 +1 收起 理由
Alam + 1

查看全部评分

 楼主| 发表于 2012-6-16 06:08:04 | 显示全部楼层
本帖最后由 user3000 于 2012-6-16 06:44 编辑

此为为提供免费下载链接的回复帖, 请论坛管理员高抬贵手!





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×

评分

参与人数 1贡献 +7 收起 理由
Alam + 7

查看全部评分

您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-4-30 14:11 , Processed in 0.084253 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表