?
Solved

PostMessage instead of SendKeys to control MS Access

Posted on 2005-03-01
8
Medium Priority
?
965 Views
Last Modified: 2008-02-20
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
Comment
Question by:schworak
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
8 Comments
 
LVL 7

Expert Comment

by:Smallint
ID: 13429516
Another application can intercept messages too... so this will not improve security. Why are you using SendKeys to type password??

Cheers
0
 
LVL 13

Expert Comment

by:rettiseert
ID: 13434729
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
 
LVL 3

Author Comment

by:schworak
ID: 13435945
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
Technology Partners: 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!

 
LVL 10

Expert Comment

by:Jini Jose
ID: 13436877
are you looking for any password breaking programme ?

0
 
LVL 3

Author Comment

by:schworak
ID: 13439349
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
 
LVL 13

Accepted Solution

by:
rettiseert earned 2000 total points
ID: 13441534
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
 
LVL 3

Author Comment

by:schworak
ID: 13443858
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
 
LVL 3

Author Comment

by:schworak
ID: 13443931
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

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!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: Martin
Here are a few simple, working, games that you can use as-is or as the basis for your own games. Tic-Tac-Toe This is one of the simplest of all games.   The game allows for a choice of who goes first and keeps track of the number of wins for…
Background What I'm presenting in this article is the result of 2 conditions in my work area: We have a SQL Server production environment but no development or test environment; andWe have an MS Access front end using tables in SQL Server but we a…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…
Suggested Courses
Course of the Month11 days, 16 hours left to enroll

752 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question