Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

SendKey to External Application Via Delphi

Posted on 2000-02-17
9
Medium Priority
?
605 Views
Last Modified: 2010-04-04
Hi All,

I Launch MS Word via Delphi using the following Code :
 
Temp := 'C:\DocumentTest.doc';
WordApp := CreateOleObject('Word.Application');
WordApp.Visible := True;
hndl := FindWindow(PChar('OpusApp'), nil);
if hndl <> 0 then
   ShowWindow(hndl, SW_Minimize);

WordApp.Documents.Open(Temp);
try
   begin
WordApp.ActiveDocument.MailMerge.Destination := wdSendToPrinter;
WordApp.ActiveDocument.MailMerge.Datasource.FirstRecord := wdDefaultFirstRecord;
WordApp.ActiveDocument.MailMerge.Datasource.LastRecord := wdDefaultLastRecord;
WordApp.ActiveDocument.MailMerge.Execute;
   end;
except
    begin
       showmessage('This is an Error');
    end;
end;
 
The above code, Launches MS Word, Merges the Data into Word . .  NOW HERE IS THE PROBLEM
 
Once,     WordApp.ActiveDocument.MailMerge.Execute; is called, Word opens a Print Dialog Box and the user has to click the ok button for printing to begin.  This is very cumbersome, if you print in batches of 500, a user has to be present to keep clicking on the Print Dialog box OK Button for printing to continue.  I need to send a piece of code to automatically begin printing.  Is there a way to send a key to MS Word eg) Enter Key

Thank you for your assistance in advance

Regards
Tazi
0
Comment
Question by:TAZI
[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
9 Comments
 
LVL 5

Expert Comment

by:TheNeil
ID: 2531410
Try this. It's really old, written for Delphi 2, and I've never tried it but it might do the trick...

procedure keybd_Event; external 'USER' index 289;

procedure PostVKey(bVirtKey: byte; Up: Boolean);
var    
  AXReg,BXReg : Word;
  AXHigh, AXLow, BXHigh, BXLow : Byte;

  function MakeWord(L,H: Byte): Word;
  begin
    MakeWord := (H shl 8) + L;
  end;

begin
  AXLow := bVirtKey;
  if up then AXHigh := $80 else AXHigh := $0;
  AXreg := MakeWord(AXLow,AXHigh);
  BXLow := VkKeyScan(bVirtKey);
  BXHigh := 0;
  BXReg := MakeWord(BXLow,BXHigh);
  asm
    mov bx,BXreg;
    mov ax,AXReg;
  end;
  Keybd_Event;
end;

Then to simulate Shift+Ins you need to do

PostVKey(VK_Shift,false);
PostVKey(VK_Insert,false);
PostVKey(VK_Insert,True);
PostVKey(VK_Shift,True);

The Neil
0
 
LVL 8

Accepted Solution

by:
ZifNab earned 200 total points
ID: 2531422
It should be possible,

first we've to find the handle of the dialog window, then the handle of the button and then so a click. You can use winsight for some debugging.

Also here is a code which explains it in more detail

http://www.delphipages.com/edit/count.cfm?comID=453&Link=uploads%2FMiscellaneous%2FMUMacro1%2Ezip 

Another example is :

From: "David Zajac" <dzajac@HiWAAY.net> Hope this helps:
                      --------------------------------------------------------------------------------
                       
                      unit Unit1;

                      interface

                      uses
                        SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
                        Forms, Dialogs, StdCtrls;

                      type
                        TForm1 = class(TForm)
                          Button1: TButton;
                          Button2: TButton;
                          procedure Button1Click(Sender: TObject);
                          procedure Button2Click(Sender: TObject);
                          procedure FormKeyPress(Sender: TObject; var Key: Char);
                        private
                          AppInst: THandle;
                          AppWind: THandle;
                        public
                          { Public declarations }
                        end;

                      var
                        Form1: TForm1;

                      implementation

                      {$R *.DFM}

                      uses ShellAPI;
                       

                      procedure SendShift(H: HWnd; Down: Boolean);
                      var vKey, ScanCode, wParam: Word;
                          lParam: longint;
                      begin
                        vKey:= $10;
                        ScanCode:= MapVirtualKey(vKey, 0);
                        wParam:= vKey or ScanCode shl 8;
                        lParam:= longint(ScanCode) shl 16 or 1;
                        if not(Down) then lParam:= lParam or $C0000000;
                        SendMessage(H, WM_KEYDOWN, vKey, lParam);
                      end;

                      procedure SendCtrl(H: HWnd; Down: Boolean);
                      var vKey, ScanCode, wParam: Word;
                          lParam: longint;
                      begin
                        vKey:= $11;
                        ScanCode:= MapVirtualKey(vKey, 0);
                        wParam:= vKey or ScanCode shl 8;
                        lParam:= longint(ScanCode) shl 16 or 1;
                        if not(Down) then lParam:= lParam or $C0000000;
                        SendMessage(H, WM_KEYDOWN, vKey, lParam);
                      end;

                      procedure SendKey(H: Hwnd; Key: char);
                      var vKey, ScanCode, wParam: Word;
                          lParam, ConvKey: longint;
                          Shift, Ctrl: boolean;
                      begin
                        ConvKey:= OemKeyScan(ord(Key));
                        Shift:= (ConvKey and $00020000) <> 0;
                        Ctrl:= (ConvKey and $00040000) <> 0;
                        ScanCode:= ConvKey and $000000FF or $FF00;
                        vKey:= ord(Key);
                        wParam:= vKey;
                        lParam:= longint(ScanCode) shl 16 or 1;
                        if Shift then SendShift(H, true);
                        if Ctrl then SendCtrl(H, true);
                        SendMessage(H, WM_KEYDOWN, vKey, lParam);
                        SendMessage(H, WM_CHAR, vKey, lParam);
                        lParam:= lParam or $C0000000;
                        SendMessage(H, WM_KEYUP, vKey, lParam);
                        if Shift then SendShift(H, false);
                        if Ctrl then SendCtrl(H, false);
                      end;

                      function EnumFunc(Handle: HWnd; TF: TForm1): Bool; Far;
                      begin
                        TF.AppWind:= 0;
                        if GetWindowWord(Handle, GWW_HINSTANCE) = TF.AppInst then
                          TF.AppWind:= Handle;
                        result:= (TF.AppWind = 0);
                      end;

                      procedure TForm1.Button1Click(Sender: TObject);
                      var Text: Array[0..255] of char;
                      begin
                        AppInst:= ShellExecute(Handle, 'open', 'notepad.exe', nil, '', SW_NORMAL);
                        EnumWindows(@EnumFunc, longint(self));
                        AppWind:= GetWindow(AppWind, GW_CHILD);
                      end;


                      procedure TForm1.Button2Click(Sender: TObject);
                      begin
                        SendKey(AppWind, 'T');
                        SendKey(AppWind, 'e');
                        SendKey(AppWind, 's');
                        SendKey(AppWind, 't');
                      end;

                      procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
                      begin
                        if AppWind <> 0 then SendKey(AppWind, Key);
                      end;

                      end.

Regards, Zif.
0
 
LVL 8

Expert Comment

by:ZifNab
ID: 2531428
ah, by the way. The component I gave you information of can in fact be used as some sort of macro :-)
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 8

Expert Comment

by:ZifNab
ID: 2534189
TAZI,

do you need help?

Zif.
0
 
LVL 6

Expert Comment

by:Jaymol
ID: 2534284
Tazi,

I gave you this advice in your previous question.  If you wanted the code, you should have asked me for it!

Here's what I use...

//  This procedure sends keypresses (sText) to the object with focus
procedure SendKeys(sText: String);
var
  i             : Integer;
  shift         : Boolean;
  vk, scancode      : Word;
  ch            : Char;
  c, s          : Byte;
const
  vk_keys       : Array[0..9] of Byte=(VK_HOME, VK_END, VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT, VK_PRIOR, VK_NEXT, VK_INSERT, VK_DELETE);
  vk_shft       : Array[0..2] of Byte=(VK_SHIFT, VK_CONTROL, VK_MENU);
  flags         : Array[FALSE..TRUE] of Integer = (KEYEVENTF_KEYUP, 0);
begin
  shift:=FALSE;
  for i:=1 to Length(sText) do begin
    ch:=sText[i];
    if (ch>=#250)then begin
      s:=Ord(ch)-250;
      shift:=NOT Odd(s);
      c:=vk_shft[s shr 1];
      scancode:=MapVirtualKey(c, 0);
      Keybd_Event(c, scancode, flags[shift], 0);
    end else begin
      vk:=0;
      if (ch>=#240) then
        c:=vk_keys[Ord(ch)-240]
      else if (ch>=#228) then
        c:=Ord(ch)-116
      else if (ch<#32) then
        c:=Ord(ch)
      else begin
        vk:=VkKeyScan(ch);
        c:=LoByte(vk);
      end;
      scancode:=MapVirtualKey(c, 0);
      if (NOT shift AND (Hi(vk)>0)) then
        Keybd_Event(VK_SHIFT, $2A, 0, 0 );
      Keybd_Event( c, scancode, 0, 0 );
      Keybd_Event( c, scancode, KEYEVENTF_KEYUP, 0 );
      if (NOT shift AND (Hi(vk)>0)) then
        Keybd_Event(VK_SHIFT, $2A, KEYEVENTF_KEYUP, 0);
    end;
    Application.ProcessMessages;
  end;
end;

That's what I use in Delphi 4.  Just make sure (like it says) that Word is the focused window and you'll have no problem!  (Use char-codes to send system keys such as tab, enter, arrow keys etc..)

John.
0
 
LVL 6

Expert Comment

by:Jaymol
ID: 2534299
Sorry mate.....I only just read the old question.  You did ask didn't you!  (Too many fingers in too many pies!)
0
 
LVL 1

Author Comment

by:TAZI
ID: 2534625
Hi All, thanks for all your input.

Zifnab, thanks for pointing me to Winsight for debugging.  I was aware that I had to get the handle of the Printdialog box, but this dialog only becomes visible once the Execute Method is called - the program looses control after that.  In any event, I used Winsight found the Handle, created a thread - looping till the handle of the print dialog is greater that zero and then I make use of the SendKey procedure.
  If hndl <> 0 then
     SendKey(hndl, #13);

I did have the procedure Sendkey which you've made available above, I've modified it according to what I needed.  I've finally solved this problem with the thread that I created.  I however will award these points to you because without Winsight, I would not have been able to get the handle of the Print Dialog box :

hndl := FindWindow(PChar('bosa_sdm_Microsoft Word 8.0'), nil);

Thanks for your help, Zifnab

TO ALL WHO HAVE PROVIDED INPUT....YOUR EFFORTS ARE GREATLY APPRECIATED

Regards,
Tazi


0
 
LVL 8

Expert Comment

by:ZifNab
ID: 2534642
thanks for sharing the solution you've finally used.

Zif.
0
 

Expert Comment

by:jasonleicester
ID: 8494485
Well I don't mean to be clever but if you had instead set the following line to output to new document instead of the printer;

  WordApp.ActiveDocument.MailMerge.Destination := wdSendToNewDocument;

and then after

  WordApp.ActiveDocument.MailMerge.Execute;


used
 
  active document.printout

you didn't need to send any keys at all.

Jason
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

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

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…
How to fix incompatible JVM issue while installing Eclipse While installing Eclipse in windows, got one error like above and unable to proceed with the installation. This video describes how to successfully install Eclipse. How to solve incompa…
Suggested Courses

721 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