Solved

SendKey to External Application Via Delphi

Posted on 2000-02-17
9
558 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
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
 
LVL 8

Expert Comment

by:ZifNab
ID: 2534189
TAZI,

do you need help?

Zif.
0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 
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

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

708 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now