Solved

SendKey to External Application Via Delphi

Posted on 2000-02-17
9
591 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 100 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

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

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…
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
If you're a developer or IT admin, you’re probably tasked with managing multiple websites, servers, applications, and levels of security on a daily basis. While this can be extremely time consuming, it can also be frustrating when systems aren't wor…
Monitoring a network: why having a policy is the best policy? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the enormous benefits of having a policy-based approach when monitoring medium and large networks. Software utilized in this v…

707 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