[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 621
  • Last Modified:

SendKey to External Application Via Delphi

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
TAZI
Asked:
TAZI
1 Solution
 
TheNeilCommented:
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
 
ZifNabCommented:
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
 
ZifNabCommented:
ah, by the way. The component I gave you information of can in fact be used as some sort of macro :-)
0
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

 
ZifNabCommented:
TAZI,

do you need help?

Zif.
0
 
JaymolCommented:
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
 
JaymolCommented:
Sorry mate.....I only just read the old question.  You did ask didn't you!  (Too many fingers in too many pies!)
0
 
TAZIAuthor Commented:
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
 
ZifNabCommented:
thanks for sharing the solution you've finally used.

Zif.
0
 
jasonleicesterCommented:
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

Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now