Is the SendKeys juice worth the squeeze?

by Michael S. Kaplan, published on 2006/06/10 05:35 -07:00, original URI: http://blogs.msdn.com/michkap/archive/2006/06/10/625285.aspx


There was a funny scene in Superman II where after a ton of oranges Lois Lane has just a tiny bit of actual Orange Juice. And that was even with someone like Superman wielding the juicer. The truth is that the juice is not always worth the squeeze....

So, looking to SendKeys, the SendKey statement has been around in Visual Basic for a long time.

It is at its core an attempt to get around all of the confusion of the difference between WM_KEYDOWN and WM_CHAR. It accomplishes this by shoving them all in one string that the caller passes in and then parsing out what it needs to.

Most people still found it to be fairly confusing, for what it is worth. Some of the most complex problems come out of such attempts at simplification. :-)

While people may primitively try to emulate this behavior by passing their own WM_CHAR (or even WM_KEYDOWN for the more sophisticated among the developer crowd), VB has long accomplished its task in a much more complicated way: via a SetWindowsHookEx function call to create a WH_JOURNALPLAYBACK hook. The journal stuff is described simply:

WH_JOURNALPLAYBACK

Installs a hook procedure that posts messages previously recorded by a WH_JOURNALRECORD hook procedure. For more information, see the JournalPlaybackProc hook procedure.

WH_JOURNALRECORD

Installs a hook procedure that records input messages posted to the system message queue. This hook is useful for recording macros. For more information, see the JournalRecordProc hook procedure.

.NET and its SendKeys class carry on that bold, low level tradition of using the journaling support.

You can dig in further to understand more about it if you like, although to be honest it may not be worth the trouble. As many developers have found, the current incarnation in both VB and in .NET does really strange things in beta builds of IE7 (character duplication, etc.) and actual exceptions in beta builds of Vista due to some of the security changes in the OS.

Of course, most developers only care about security when it affects them; otherwise most of them run as Administrators on their boxes and many of them are finding Vista to be a new experience since even administrators have to approve some of the changes they run (and developers get no free pass to run their code with impunity).

SendKeys was in its own way doing the same sort of thing -- moving to some of the lowest levels to do its work. And because of that, it is now having problems.

Of course people are looking at the problem now and working out the best way to solve the problem, though with a security decision to not allow less privileged windows to talk to windows with higher privileges, it is hard to imagine supporting the random VB application that assumes it can talk to any window it pleases.

So there will have to be some changes for developers, no matter what problems are solved on the .NET or OS side.

I would highly recommend staying away from SendKeys at this point.

Now looking back, every step that SendKeys went through to get where it is was done for sensible reasons. But now, having reached this point it is reasonable to wonder whether the juice was, in fact, worth the squeeze.

In my opinion, it wasn't....

 

This post brought to you by 𐂓 (U+10093, a.k.a. LINEAR B MONOGRAM B127 KAPO)


# Pasquale Esposito on Wednesday, June 21, 2006 12:27 PM:

My God! If I think of all the VB6 applications I have sold over the last few years which make large use of SendKeys... I can't believe I have to provide all my customers with un apdated version.

What's the point in neutralizing the SendKeys command when it is equally possible to get the same results resorting to WinAPI32?

What is even more crazy is that SendKeys seems not to work even under .NET 2.0. I really hate it when Microsoft is not compatible with Microsoft!

Let's hope this bug will be fixed when the final version of Windows Vista is released.

# Michael S. Kaplan on Wednesday, June 21, 2006 10:37 PM:

Hello Pasquale --

Well, how many times have developers opened registry keys in their applications asking for all access because they did not realize that they may not have the permissions?

This is the moral equivalent of what happened with SendKeys and its dependence on journal hooks. I am pretty sure there is some thought beng put into how to fix this problem, though it would be a mistake to fix it on the Win32 side as opposed to the app that is making the mistake (in this case SendKeys), as it would be a mistake to allow people to have any sort of privilege elevation....

# Pasquale Esposito on Thursday, June 22, 2006 1:11 PM:

I only used SendKeys to move the focus from a TextBox to the next one or to simulate the pressure of the F1 key in order to launch the help file. I'm afraid millions of VB6 programmers did the same.

Don't you think it could have been much wiser to neutralize SendKeys only in the case of an interaction with an external application? What should the millions of VB6 developers tell their customers now? "Please, if you decide to upgrade to Vista, don't ever push the Help button or press Enter to move to the next TextBox, otherwise the program will crash!"

And, besides, don't you think it is absurd (or even unprofessional) to support SendKeys in .NET 2.0 and make it incompatible with a concomitant operating system?

If you give me teeth, you should not take them away from me the next day.

# Michael S. Kaplan on Thursday, June 22, 2006 2:17 PM:

Hello Pasquale --

You are kind of making my case for me here. :-)

The SendKeys implementation is serious overkill for most of the scenarios where it is used. That is the whole point of the post!

There are people working to address the sceanrio, and while do not know about the plans or the timeline, I suspect that dealing with the overkill of the implementation might be high on the list....

# Pasquale Esposito on Thursday, June 22, 2006 3:34 PM:

Thanks for your prompt reply and sorry for bothering you again.

The fact is that I just panicked when I heard that, under Windows Vista, all of my VB5/6 applications are going to crash, simply because in all of my applications I used the following cursed line of code:
----------
Private Sub cmdHelp_Click()
   SendKeys "{F1}"
End Sub
----------
and this other one:
----------
Private Sub txtSurname_KeyPress(KeyAscii As Integer)
   If KeyAscii = 13 Then SendKeys "{Tab}"    
End Sub
----------

Now, I think it is tremendously unfair to penalize all the developers who used SendKeys, simply because their only fault was to rely on code they MS provided VB6 natively with.

In theory, the solution to the problem exists (you have to replace SendKeys with an API function) but what is difficult to do is provide all of your customers with an updated version of the software they bought from you.

This is the reason why in my previous post I said that, in my opinion, MS should prevent SendKeys from causing an exception under Vista if it is only used inside the application in contexts like the ones I mentioned.

MS promised that, if a VB6 app works under XP, it will also work under Vista. Let's wait and see how reliable they are...

# bwking on Friday, July 07, 2006 10:52 PM:

We have a number of VB6 apps that make heavy use if the SendKeys command. Do you think there may be a slight chance that MS might relax the restricition at all?
If the sendkeys is within the context of the app that called it, I don't see a reason why it should be denied.

# Michael S. Kaplan on Friday, July 07, 2006 11:01 PM:

I think I explained why -- it is not that what you are wanting should require such permissions; it is that the way VB is doing it requires heavy permissions. They are not restricting their request on your behalf, and because of this, you need a lot more permissions than you think you ought to.

It is not your fault -- it is VB's. But even if they scale back how sendkeys works in .NET, whether or how they would alter VB6/VBA is an unknown to me, that offhand seems to me to be unlikely but do not know the exact plans here....

# Michael S. Kaplan on Friday, July 07, 2006 11:55 PM:

To put it another way -- you need to borrow $5. Instead of using the form for $5 loans, the teller uses the form for $100,000 wire transfers that require approval from the manager, who by default says NO to these things.

The bug is that the teller used the wrong form for your $5 loan. The problem is that the teller is an automated response system written eight years ago that probably can't be updated to change the forms they fill out, to change this "one size fits all" strategy....

# Pasquale Esposito on Sunday, July 09, 2006 1:16 PM:

Your explanation would be flawless if it were not for the fact that you can still write potentially malicious code resorting to the Windows API.

In other words, the measure taken by MS would make sense if it were impossible for a VB application to press/send keys programmatically, BUT IT IS STILL POSSIBLE using SendInput.

Here is a function that will allow you to work around the limitation under Windows Vista:

----------
Option Explicit

Private Const KEYEVENTF_KEYUP = &H2
Private Const INPUT_KEYBOARD = 1

Private Type KEYBDINPUT
wVk As Integer
wScan As Integer
dwFlags As Long
time As Long
dwExtraInfo As Long
End Type

Private Type GENERALINPUT
dwType As Long
xi(0 To 23) As Byte
End Type

Private Declare Function SendInput Lib "user32.dll" (ByVal nInputs As Long, pInputs As GENERALINPUT, ByVal cbSize As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)

Public Function SendKeysA(ByVal vKey As Integer, Optional booDown As Boolean = False)
Dim GInput(0) As GENERALINPUT
Dim KInput As KEYBDINPUT
KInput.wVk = vKey
If Not booDown Then
   KInput.dwFlags = KEYEVENTF_KEYUP
End If
GInput(0).dwType = INPUT_KEYBOARD
CopyMemory GInput(0).xi(0), KInput, Len(KInput)
Call SendInput(1, GInput(0), Len(GInput(0)))
End Function

----------

So hackers will continue to develop harmful software calling SendInput, whereas honest VB6 programmers will have to waste tens and tens of hours to update their software. THIS IS CRAZY!

# Michael S. Kaplan on Sunday, July 09, 2006 2:52 PM:

Pasquale,

Actually, my logic is still intact -- there is as lot more you can do with journal playback hooks than just key input.

Which has been my point all along! The method VB uses is quite simply overkill. Like "Someone stole my lunch money? Give me a submachine gun."

# Pasquale Esposito on Monday, July 10, 2006 7:14 AM:

Okay, let's keep it simple, in order to make myself clear. The situation (that I consider as ABSURD) is the following:

1. MS points out there is a problem with SendKeys because this statement allows hackers to write malicious code.

2. MS decides to neutralize SendKeys under Windows Vista because they want to prevent hackers from writing malicious code.

3. SendKeys has also been used by millions of honest VB6 programmers over the last years to write harmless code.

4. MS does NOT neutralize the SendInput API that still allows hackers to write the same malicious code as the one they could write with SendKeys.

5. MS does not take into any account that a hacker's criminal mind will not stop writing harmful code simply because SendKeys does not work anymore. Obviously, he or she will now use SendInput instead.

6. So, while hackers have not been stopped from doing anything, honest VB6 programmers who relied on standard VB6 code will now have to roll up their sleeves and amend all the software they have distributed over the last few years.

The measure MS took was, "Somebody wrote some malicious code using SendKeys. I'll now grab a submachine gun and exterminate millions of innocent people... and let bastards commit the same crime again!"

Sorry, I still cannot see what sense it makes.

# Michael S. Kaplan on Monday, July 10, 2006 9:37 AM:

Pasquale, let me make it not only simpler but also accurate (which you does not):

1) The VB team uses a method to enable SendKeys that they should not have.
2) That METHOD -- *NOT* the SendKeys call itself -- allows much more theoretical access to the system then it ought to
3) Vista locks down the METHOD.
4) Pasquale and others refeuse to understand #1 - #3 above, thinking that MS locked down SendKeys itself as a security hole.

That is about as simple as I can make it. And I am REALLY hoping that it is simple enough to allow you to understand what the problem is. It is NOT that SendKeys is insecure -- it is that the grenade they attached it to is.

The issues *YOU* point out with SendInput actually suggest both a workaround for users and also a potential category of solutions for the people who own the SendKeys code (all of this was known long before you suggested the latter, and possibly in some cases the former).

I am really hoping that this makes sense now, finally. Since it is the central issue I was trying to point out, it is frutrating to me that it is apparently not being communicated....

# Pasquale Esposito on Monday, July 10, 2006 12:30 PM:

Who invented "that METHOD that allows much more theoretical access to the system then it ought to?" Pasquale or Microsoft?

Pasquale's only fault was to rely on standard (allegedly legitimate) code provided by Microsoft. Pasquale was stupid because he did not understand that Microsoft is not compatible with Microsoft!

So, who is going to pay for somebody else's mistake? Millions of innocent VB6 users are!

If you want to act professionaly, you should sort out the problem in such a way that all the terabytes of VB6 software currently in circulation should not be prevented from working. If you don't, you will let somebody else pay for the grenade YOU attached to SendKeys.

Do you know what it means to provide all of your customers with an updated version of your software as soon as Windows Vista is released? Most of them may not be willing to pay for the upgrade.

You have made your point perfectly. But, possibly, I haven't made mine. So, I'll state it once again in plain English: IT IS UNFAIR TO LET OTHER PEOPLE PAY FOR YOUR MISTAKES.

Believe me, this is frustrating also to me. And to millions of other VB6 users.

# Michael S. Kaplan on Monday, July 10, 2006 3:01 PM:

Perhaps through understanding the nature of the problem, customers will be armed with the knowledge of what to ask for, and who to ask it of.

If there is anything I want this blog to highlight -- it is that Microsoft is not one single monolith that understands every aspect of every problem. Microsoft is a huge number of different people in different groups, and I am being as transparent as I can about all that I know here.

Just remember -- I do not even have permission to view the VB6 source code (or the VBA source code) -- so I could not go off randomly fix bugs myself in random products, even if I were the sort of person random enough to try that sort of thing.

But now I have acted as a messenger about the issue, and you have decided to shoot the messenger for hurting millions of VB users. :-(

# Pasquale Esposito on Monday, July 10, 2006 5:04 PM:

Michael, I am not taking it out on you. I know you are not the one who developed VB6.

I was just complaining about MS' attitude towards their customers.

The SendKeys issue may look like a minor problem, but it isn't.

Over the last five years, I have sold more than 3,000 (three-thousand) licenses of my software developed in VB6. Unfortunately, in all of my applications I used SendKeys to implement at least two functions: opening the Help file page (simulating the pressure of the F1 key) and moving the focus from one TextBox to the next (simulating the pressure of the Tab key).

Now, three thousand customers of mine will have problems using my software under Windows Vista and, believe me, this is very hard cheese for me to swallow.

A few weeks ago I made up my mind to switch to Delphi just because I would not be able to trust MS again.

# Pasquale Esposito on Monday, July 31, 2006 3:51 AM:

Hello, I have some very good news! This morning I received the following message from Chris Mayo, the VB Program Manager responsible for Visual Basic 6 on Vista:

----------
re: Vista To Support Legacy VB6 Apps
Pasquale,

I'm the VB Program Manager responsible for Visual Basic 6 on Vista.  The SendKeys issues has been corrected and will be released in Vista RC1.  The calls to SendKeys that work under Windows XP will work the same way under Vista.

Hope that helps.
Thanks,
Chris Mayo
Visual Basic Program Manager
Sunday, July 30, 2006 7:38 PM by cmayo
----------

You can reach the Blog page at

http://blogs.msdn.com/davbosch/archive/2006/02/26/539470.aspx

Thank you, Microsoft, from the bottom of my heart!

# Craig Matthews on Monday, March 17, 2008 5:10 PM:

I wonder why it is that the SendKeys issue was reported to Pasquale Esposito on July 30, 2006 by Visual Basic Program Manager Chris Mayo as being "fixed" still does exactly the same thing for me on March 17, 2008?

With UAC turned off, running as a "normal" user, running a compiled (by myself) VB6 application I still get the run-time error 70 "Permission denied".

# Michael S. Kaplan on Monday, March 17, 2008 6:24 PM:

Running Vista SP1 (or Server2008), which as Chris indicated is where the "fix" was put?

# rohit_kap11 on Wednesday, July 09, 2008 7:32 AM:

The problem remains the same.

until and unless we (The VB6 Programmers) r confirmed about the exact solution of the problem. even i m facing lots of problems as i have also delivered thousand copies of my software worldwide, in which around 346 complains, i have got by mail regarding the error 70.

pls make it clear that how can our old s/w run on new OS flawlessely. i dont wanna change the code again n again, just bcs ...

# Yuhong Bao on Thursday, April 23, 2009 1:03 AM:

rohit_kap11 and Craig Matthews: Are you sure you are using the version of msvbvm60.dll shipped with Vista? Because older versions won't contain this fix.


referenced by

2010/05/13 Minimalism isn't laziness, really; it's trying to do the job right without side effects!

2007/09/10 The SendKeys *blog post* juice was definitely not worth the squeeze

2006/07/13 IME + .NET = Input Madness Editor?

go to newer or older post, or back to index or month or day