visual basic 6 macro, the clipboard & third-party software add-on

Hi all,

I'm having an issue with a macro I wrote to get an ID from a third-party product.  I need the ID from the third-party screen (form) to figure out which record I'm on, because there is no data layer in the SDK.  Basically, I created a DLL that adds an option to the product's menu.  When the user clicks the new option on the menu, the program moves the cursor (using Alt-G) to the first field on the form, then "presses" Ctrl-C.  This works great if it is isolated--I can use ctrl-v to paste the contents of the ID field after it runs.  However, as soon as I add anything else to it, like MsgBox Clipboard.GetText, for example, it doesn't work.  Since my whole reason to do the "macro" exercise is to capture the info in the clipboard, I really need to fix this.  Code follows, but please read my last comment, below.

The code is here in a sub of a Functions.bas module:
    Clipboard.Clear
    ' Alt-G:
    Call keybd_event(vbKeyMenu, 0, 0, 0)
    Call keybd_event(vbKeyG, 0, 0, 0)
    Call keybd_event(vbKeyG, 0, KEYEVENTF_KEYUP, 0)
    Call keybd_event(vbKeyMenu, 0, KEYEVENTF_KEYUP, 0)
    Call keybd_event(vbKeyControl, 0, 0, 0)
    ' Ctrl-C:
    Call keybd_event(vbKeyC, 0, 0, 0)
    Call keybd_event(vbKeyC, 0, KEYEVENTF_KEYUP, 0)
    Call keybd_event(vbKeyControl, 0, KEYEVENTF_KEYUP, 0)

And in the Globals:
Public Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)

And in the declarations of the Functions module:
Declare Function apiFindWindow Lib "user32" Alias "FindWindowA" _
   (ByVal lpclassname As Any, ByVal lpCaption As Any) As Long

Final Comment:
I noticed that when it works (if it runs by itself without any code after it), my cursor is where it should be -- in the ID field -- and the whole field is selected.  When I run it with my "msgbox" command (or any command) after it, the focus is not on the ID field.    I'm not sure if this matters but I figured I'd include it in case it helps.

Thanks,
jr
LVL 4
jruheAsked:
Who is Participating?
 
aikimarkCommented:
create a small project with two textbox controls, a timer control, and two command buttons.

text1.text will be the title of the dialog window
text2.text will be the text you want to send to that dialog window
Set the interval for the timer control to 2000 (2 seconds), and set the enabled property = False
Command1_Click() enables the timer control
Command2_Click() disables the timer control
The timer1_Timer() routine does the following:
Private Sub timer1_Timer()
  On Error Resume Next
  AppActivate Text1.text
  If Err = 0 Then
    SendKeys Text2.Text
  Else
    Err.Cls
  End If
End Sub

Open in new window

0
 
aikimarkCommented:
You could assign the value in the clipboard object to a variable, rather than including it in the msgbox statement directly.

If the variable assignment removes the item from the clipboard, you can add it back to the clipboard.

Question: Have you considered SendMessage() API or SendKeys, rather than keybd_event() API?
0
 
jruheAuthor Commented:
Thanks for your response a1kimark :)

Yes--I actually only used MsgBox to show the problem--indeed I do need it in a variable and have attempted to do something like MyVar = Clipboard.GetText, but it doesn't work--it's like, if there's any code at all after the keyboard events, the keyboard events don't work.  It may be some kind of quirk with the products' API, but it's undocumented.

Do you have more info on SendMessage() or SendKeys?  I tried SendKeys but it didn't appear to work at all (and ugh--I didn't save the code I used!).  That said, I've never used anything like this, so if you've got a good example of either, I'd like to see it.  

Thanks,
Joy
0
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

 
jruheAuthor Commented:
I considered this (or something akin -- note I don't have access to the interface itself so I can't populate a textbox and it looks like I can't use SendKeys if that's what it does).   It was just supposed to populate the clipboard contents on a form that I don't have access to, and then run some code based on that.  However, your suggestion gave me an idea:  perhaps I can create a form whose "visible" property is set to False, and add the timer to it.  The menu command (which I do have access to) could fire the form, then fire the Keyboard Event commands to collect the data then do the rest of the program based on the contents.

I will try that this week. . .  thank you.  meantime, if you know of a timer object that you don't need an interface for, I'd be obliged.

One thing I should "say out loud" before I close. . .  It feels like the clipboard contents are falling out of scope if other commands are added.  It's fine encapsulated (without any commands after the Clipboard GetText command--kind of like it's dabbling within the main program's form and the clipboard (to the user) is still in scope--Ctrl-V will yield the data it copied).  However, once other commands are added, it's almost like the scope of the whole program event stays within my program (as evidenced by the fact that, in the former scenario (no commands after GetText), the cursor ends up in the field that it copied (and all data is selected in that field).  In the latter scenario (commands after GetText--even those that don't mess with the interface--like if a very random MyVar = "abc" was the only command after it copies the clipboard), the cursor ends up off the screen entirely--no field has focus.

I'll try your suggestion this week and truly appreciate your help so far and any thoughts you may have on the above.

jr
0
 
aikimarkCommented:
why can't you use Sendkeys?

There is a Sleep() API that you can use in place of a timer.  Be sure to include a DoEvents statement in the loop so that your code can respond to user-directed stop (looping) action.
0
 
jruheAuthor Commented:
I was thinking I couldn't use SendKeys because I thought it was an object method--I thought you had to specify the form to use it, but I was incorrect.

I just tested it and ran into the issue that the forms run from within the third-party program/API have to be modal.  When I try to run the Timer form modelessly, the API throws an error.  So I can't use AppActivate().  I'm batting a thousand here, aren't I?  :-)

Checking the sleep() api now. . .  will update when I've got enough info to make it interesting!

jr
0
 
jruheAuthor Commented:
Woot Woot!  It worked with a combination of your Timer Control and having the API menu call use an EXE (which will end up containing the rest of the logic). . .  

THANK YOU--you're great!

jr
0
 
jruheAuthor Commented:
Timely, concise--what I needed.  Thank you
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.