Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 989
  • Last Modified:

PostMessage instead of SendKeys to control MS Access

I have a front end that does a bunch of work. One thing it does is open a particular MS Access database that is password protected. The front end currently uses AppActivate and SendKeys to key in the password for the user.

I know, this is a bad way to do it for so many reasons. That is why I need your help.

How can I use PostMessage (or any other API method) to communicate directly with the password window so another application can't intercept the key commands and see the password?

Windows XP, VB6, MS Access 2000
0
schworak
Asked:
schworak
1 Solution
 
SmallintCommented:
Another application can intercept messages too... so this will not improve security. Why are you using SendKeys to type password??

Cheers
0
 
rettiseertCommented:
This is very dirty, but is works:

Paste this in a new module:
'--------------------------------------------------

Option Explicit

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Boolean
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long

Private PasswordWindowTitle As String
Private HWNDAccess As Long
Private HWNDPasswordAccess As Long

Private Function ClassNameOf(hwnd As Long) As String
   
    Dim strResult As String
    Dim strLen As Long
   
    strResult = Space$(64)
   
    strLen = GetClassName(hwnd, strResult, 64)
   
    ClassNameOf = Left$(strResult, strLen)

End Function

Public Function HwndFromProcessID(ProcessID As Long) As Long
   Dim hWndJob As Long, PID As Long
   Const GW_HWNDNEXT = 2
   hWndJob = FindWindow(vbNullString, vbNullString)
   Do Until hWndJob = 0
      If GetParent(hWndJob) = 0 Then
         Call GetWindowThreadProcessId(hWndJob, PID)
         If PID = ProcessID Then Exit Do
      End If
      hWndJob = GetWindow(hWndJob, GW_HWNDNEXT)
   Loop
   HwndFromProcessID = hWndJob
End Function

Public Sub OpenAccessDBAndSetPassword(AccessPath As String, DBPath As String, Password As String, AccessPasswordWindowTitle As String)

    Dim ProcessID As Long

    PasswordWindowTitle = AccessPasswordWindowTitle
    HWNDPasswordAccess = 0
   
    ProcessID = Shell(Chr(34) + AccessPath + Chr(34) + Space$(1) + Chr(34) + DBPath + Chr(34))

    HWNDAccess = HwndFromProcessID(ProcessID)
   
    Do While HWNDPasswordAccess = 0
        EnumWindows AddressOf EnumWindowsProc, HWNDAccess
        DoEvents
    Loop
   
    EnumChildWindows HWNDPasswordAccess, AddressOf EnumChildProc, 0

End Sub

Public Function EnumChildProc(ByVal hwnd As Long, ByVal lParam As Long) As Boolean

    Const WM_SETTEXT = &HC
   
    Debug.Print hwnd
   
    If ClassNameOf(hwnd) = "Edit" Then
        SendMessage hwnd, WM_SETTEXT, 0, ByVal "A"
    End If
   
    EnumChildProc = True
   
End Function

Public Function EnumWindowsProc(ByVal hwnd As Long, ByVal lParam As Long) As Boolean
    Dim sSave As String, Ret As Long
   
    Ret = GetWindowTextLength(hwnd)
    sSave = Space(Ret)
    GetWindowText hwnd, sSave, Ret + 1
   
    If sSave = PasswordWindowTitle And GetParent(hwnd) = lParam Then      'This is the password window of my access
        HWNDPasswordAccess = hwnd
    End If
   
    EnumWindowsProc = True

End Function

'--------------------------------------------------
'Now you can call OpenAccessDBAndSetPassword, to open a new session of MSAccess with a default database and set a password, for example:

OpenAccessDBAndSetPassword "c:\Location\of\MSAccess.exe", "c:\Location\of\database.mdb", "secretPassword", "Title of Access Password Window"

In the 4th argument you must specify the title of the access window who's asking for the password. In my computer (wich is in spanish) the title of this window is "Solicitud de contraseña", I don't know the title of this window in the English version of MS Access.
If this parameter is wrong, the program may loop forever, so be prepared to press Ctrl-Break
0
 
schworakAuthor Commented:
OH SO CLOSE!

It took a little tweaking but it gets the password into the text box. But it doesn't click the OK button. I tried adding an ENTER to the password but it just stuck the character into the text box.

Any thoughts?

If I can get it to submit the password I will be all set.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Jini Jose.Net Team LeadCommented:
are you looking for any password breaking programme ?

0
 
schworakAuthor Commented:
No, I know the password. It is a small part of our daily tool set. I don't want some users to directly have the password because we don't have control over changing it. So we created a front end that helps everyone here in the office perform various tasks including opening MS Word templates and Excel spread sheets and web pages relating to our jobs. One program is this MS Access database which is password protected. I want the front end to open and log in to it without the user keying in the database password.

It is so verry close to working using the code above!
0
 
rettiseertCommented:
This shoud work, I'm sorry, the "last version" had some minor bugs.
This time there's a new parameter for the OpenAccessDBAndSetPassword function. You must set the title of the OK button of the password window. Again, my Access is in spanish so I don't know the title of this button in the english version (maybe the word "OK" ?)





Option Explicit

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
Private Declare Function getWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Boolean
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetDlgCtrlID Lib "user32" (ByVal hwndCtl As Long) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Private PasswordToSet As String
Private TitleOfPasswordWindow As String
Private TitleOfOKButton As String

Private HWNDAccess As Long
Private HWNDPasswordWindow As Long

Private Function ClassNameOf(hwnd As Long) As String
    Dim strResult As String, strLen As Long
    strResult = Space$(64)
    strLen = GetClassName(hwnd, strResult, 64)
    ClassNameOf = Left$(strResult, strLen)
End Function

Private Function TitleOf(hwnd As Long) As String
    Dim sSave As String, Ret As Long
    Ret = GetWindowTextLength(hwnd)
    sSave = Space(Ret)
    getWindowText hwnd, sSave, Ret + 1
End Function

Public Function HwndFromProcessID(ProcessID As Long) As Long
   Dim hWndJob As Long, PID As Long
   Const GW_HWNDNEXT = 2
   hWndJob = FindWindow(vbNullString, vbNullString)
   Do Until hWndJob = 0
      If GetParent(hWndJob) = 0 Then
         Call GetWindowThreadProcessId(hWndJob, PID)
         If PID = ProcessID Then Exit Do
      End If
      hWndJob = GetWindow(hWndJob, GW_HWNDNEXT)
   Loop
   HwndFromProcessID = hWndJob
End Function

Public Sub OpenAccessDBAndSetPassword(PathToMSAccess As String, PathToDatabase As String, Password As String, PasswordWindowTitle As String, OKButtonTitle As String)

    Dim ProcessID As Long
   
    PasswordToSet = Password
    TitleOfPasswordWindow = PasswordWindowTitle
    TitleOfOKButton = OKButtonTitle
    HWNDPasswordWindow = 0
   
    ProcessID = Shell(Chr(34) + PathToMSAccess + Chr(34) + Space$(1) + Chr(34) + PathToDatabase + Chr(34))
    HWNDAccess = HwndFromProcessID(ProcessID)
   
    Do While HWNDPasswordWindow = 0
        EnumWindows AddressOf EnumWindowsProc, HWNDAccess
        DoEvents
    Loop
   
    EnumChildWindows HWNDPasswordWindow, AddressOf EnumChildProcToSetPassword, 0
    EnumChildWindows HWNDPasswordWindow, AddressOf EnumChildProcToClickOK, 0

End Sub

Public Function EnumChildProcToClickOK(ByVal hwnd As Long, ByVal lParam As Long) As Boolean

    Const WM_COMMAND = &H111
    Dim Ret As Long, sSave As String, CtrlID As Long
   
    Ret = GetWindowTextLength(hwnd)
    sSave = Space(Ret)
    getWindowText hwnd, sSave, Ret + 1
   
    If sSave = TitleOfOKButton Then
        CtrlID = GetDlgCtrlID(hwnd)
        PostMessage HWNDPasswordWindow, WM_COMMAND, CtrlID, hwnd
        EnumChildProcToClickOK = False
    Else
        EnumChildProcToClickOK = True
    End If
   
End Function

Public Function EnumChildProcToSetPassword(ByVal hwnd As Long, ByVal lParam As Long) As Boolean

    Const WM_SETTEXT = &HC
   
    If ClassNameOf(hwnd) = "Edit" Then
        SendMessage hwnd, WM_SETTEXT, 0, ByVal PasswordToSet
    End If
   
    EnumChildProcToSetPassword = True
   
End Function

Public Function EnumWindowsProc(ByVal hwnd As Long, ByVal lParam As Long) As Boolean
    Dim sSave As String, Ret As Long
   
    Ret = GetWindowTextLength(hwnd)
    sSave = Space(Ret)
    getWindowText hwnd, sSave, Ret + 1
   
    If sSave = TitleOfPasswordWindow And GetParent(hwnd) = lParam Then      'This is the password window of my access
        HWNDPasswordWindow = hwnd
    End If
   
    EnumWindowsProc = True

End Function
0
 
schworakAuthor Commented:
Thanks so much!

Here are the parts I still had to change to make it Access 97 / Access 2000 compatable.


Public Function EnumChildProcToSetPassword(ByVal hwnd As Long, ByVal lParam As Long) As Boolean
    Const WM_SETTEXT = &HC
       
    If InStr(LCase(ClassNameOf(hwnd)), "edit") > 0 Then
        SendMessage hwnd, WM_SETTEXT, 0, ByVal PasswordToSet
    End If
   
    EnumChildProcToSetPassword = True
   
End Function


And when launching the program...

    ProcessID = Shell(Chr(34) + PathToMSAccess + Chr(34) + Space$(1) + PathToDatabase, vbMaximizedFocus)



Because I am passing parameters as well as the database name I can't have the quotes added in the shell command around the PathToDatabase.

But other than that.... AWESOME!
0
 
schworakAuthor Commented:
As for security, I am not worried about someone learning the password if they are going to write code to intercept the windows messages.

The main problem was that the password would end up in Excel or Word docuemnts by mistake. So the security isn't 100% but it is much better than just giving out the password to all our users.

Thanks so much for all the help!
0

Featured Post

Become an Android App Developer

Ready to kick start your career in 2018? Learn how to build an Android app in January’s Course of the Month and open the door to new opportunities.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now