I'm trying to get text from terminal window.
https://www.attachmate.com/products/extra/
it looks like below:
I'm using WM_GETTEXT to get text from this terminal window. As you can see above, the window has text (in green) but i'm not able to get anything, even after trying out all windows and child windows under this applications.
the code i use is:
function TForm1.fn_get_text(): string;
var
NpWnd, NpEdit: HWnd;
Buffer: string;
BufLen: Integer;
begin
Memo1.Clear;
NpWnd := FindWindow('#32769', nil);
if NpWnd <> 0 then
begin
//NpEdit := FindWindowEx(NpWnd, 0, 'Afx:400000:202b:10003:6:0', nil);
//if NpEdit <> 0 then
//begin
BufLen := SendMessage(NpWnd, WM_GETTEXTLENGTH, 0, 0);
SetLength(Buffer, BufLen + 1);
SendMessage(NpWnd, WM_GETTEXT, BufLen, LParam(PChar(Buffer)));
Memo1.Lines.Text := Buffer;
//end;
end;
end;
I used Winspy++ to get all window classes. In Win spy++, different window classes look like below:
I tried all window classes under Extra.exe . But nothing seems to be able to get me the text from terminal window. Could anyone please provide me some tips to identify the issue?
Related
I've a problem with using DirectX (DirectSound) on Windows 10. I'me changing some legacy code that used DirectX (DirectX 9 I think) and run on Windows XP.
Everything is still working great on Windows XP but I can't get a sound on Windows 10.
The application uses these files: DXUTIL.PAS (Original ObjectPascal conversion made by: Boris V.), lzexpand.pas (Author: Vadim Bodrov) and DirectSound.pas (DirectX 9.0 Delphi / FreePascal adaptation by Alexey Barkovoy).
procedure TForm1.Button1Click(Sender: TObject);
var
sndgwait : PSound;
begin
InitSB(Handle);
LoadWave(sndgwait, 'D:\game\EXP01.wav', 1);
StartSound(sndgwait, false);
end;
function LoadWave(var Sound: PSound; fn : string; conc : integer) : boolean;
var
cbData, cbdata1 : DWORD;
pd1 : pointer;
hfile : longint;
vreopenbuff : TOFStruct;
begin
hfile := LZOpenFile(PAnsiChar(fn), vreopenbuff, OF_READ);
if hfile < 0 then begin result := false; exit; end;
cbdata := LZSeek(hfile, 0, 2); // file size
LZSeek(hfile, 0, 0); //back to the start of the wav
getmem(pd1, cbdata);
LZRead(hfile, pd1, cbdata);
LZClose(hfile);
if conc < 1 then conc := 1;
result := ParseWaveData(Sound, conc, cbdata, pd1);
end;
function ParseWaveData(var Sound : PSound; conc : integer; cbdata : dword; pd1 : pointer) : boolean;
var
pWaveHeader: PWAVEFORMATEX;
pDSB: IDirectSoundBuffer;
dsBD: TDSBUFFERDESC;
rr : longint;
begin
if lpDS = nil then begin
result := false;
exit;
end;
Sound := PSNDOBJ(LocalAlloc(LPTR, SizeOf(TSNDOBJ) + (conc-1) * SizeOf(IDirectSoundBuffer)));
Sound^.iAlloc := conc;
Sound^.cbWaveSize := 0;
Sound^.pbWaveData := nil;
pwaveHeader := nil;
Sound^.pbData := pd1;
Sound^.cbSize := cbdata;
if DSParseWaveResource(pd1, pWaveHeader, Sound^.pbWaveData, Sound^.cbWaveSize) then begin
ZeroMemory(#dsBD, SizeOf(dsBD));
dsBD.dwSize := SizeOf(dsBD);
dsBD.dwFlags := DSBCAPS_STATIC or DSBCAPS_GETCURRENTPOSITION2 or DSBCAPS_CTRLFREQUENCY orDSBCAPS_CTRLPAN or DSBCAPS_CTRLVOLUME;//DSBCAPS_CTRLDEFAULT or
dsBD.lpwfxFormat := pWaveHeader;
dsBD.dwBufferBytes := Sound^.cbWaveSize;
if lpDS.CreateSoundBuffer(dsBD, pDSB, nil) = DS_OK then begin
if not DSFillSoundBuffer(pDSB, Sound^.pbWaveData, dsBD.dwBufferBytes) then begin
pDSB._Release;
pDSB := nil;
end;
Sound^.Buffers[0] := pDSB;
for rr := 1 to conc - 1 do begin
lpDS.DuplicateSoundBuffer(Sound^.Buffers[0], Sound^.Buffers[rr]);
end;
end else begin
pDSB := nil;
SndObjDestroy(Sound);
Sound := nil;
end;
end;
Result := Sound <> nil;
end;
function StartSound(Sound: PSound; Loop: boolean = false; waitforend: boolean = false): boolean;
begin
if Loop then
StartSound := SndObjPlay(Sound, DSBPLAY_LOOPING)
else
StartSound := SndObjPlay(Sound, 0);
if waitforend and not loop then
while SoundPlaying(Sound) do Application.ProcessMessages;
end;
function SndObjPlay(pSO: PSNDOBJ; dwPlayFlags: DWORD): Boolean;
var
pDSB: IDirectSoundBuffer;
begin
Result := FALSE;
if pSO = nil then
begin
exit;
end;
if ((dwPlayFlags and DSBPLAY_LOOPING) = 0) or (pSO^.iAlloc = 1) then
begin
pDSB := SndObjGetFreeBuffer(pSO);
if (pDSB <> nil) then
Result := SUCCEEDED(pDSB.Play(0, 0, dwPlayFlags));
end else
Result:= FALSE;
end;
All values in ParseWaveData call are correct I think (no nil values).
I'm not gething any errors. Just there is no sound.
What can be a problem here?
Or are there other ways to use DirectX for sound in this old app on windows 10? Any example would be great.
Thanks....
While I cannot guarantee this is the fix, I also cannot just comment because I don't have 50 rep, it is worth a try. I had a lot of issues with Windows 10 sound, often it seemed at random! Switching apps disabled sound from background apps, game programming wouldn't make a peep, even playing music to see if I had the right track with CD burning software was broken, Netflix breaking sound until I rebooted, wireless headphones not working or volume way too low. Infuriating. You might not be wrestling control from whatever has current priority because of an W10 April 2018 change and just not had the issues I've had.
Anyway, this is worth a try:
Right-click the Sound Icon in the bottom right of task bar. Click
Playback or Audio Devices. Right-click the speaker icon that appears
in the settings screen. Click Properties from the pop-up menu. Click
the Advanced tab on the Speakers Properties screen. Uncheck the boxes
for Allow applications to take exclusive control and Give exclusive
mode applications priority.
I've solved this. At the end it wasn't anything with DirectX.
hfile := LZOpenFile(PAnsiChar(fn), vreopenbuff, OF_READ);
Parameter "fn" (string) that was input to the procedure was wrong. Something messes up. The file name was incorrect, so file that should be played was empty. Nothing to do with DirectX. I've replaced above command with:
hfile := LZOpenFile(PAnsiChar(AnsiString(fn)), vreopenbuff, OF_READ);
Now it is working.
Thanks...
Good afternoon to all.
I want see a window that is open inside of a "new desktop environment", from of my remote assistance tool, but I'm not able to see this window using conventional functions like this below:
function RandomPassword(PLen: Integer): string;
var
str: string;
begin
Randomize;
str := 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
Result := '';
repeat
Result := Result + str[Random(Length(str)) + 1];
until (Length(Result) = PLen)
end;
procedure Printscreen;
var
DCDesk: HDC;
bmp: TBitmap;
hmod, hmod2 : HMODULE;
BitBltAPI: function(DestDC: HDC; X, Y, Width, Height: Integer; SrcDC: HDC; XSrc, YSrc: Integer; Rop: DWORD): BOOL; stdcall;
GetWindowDCAPI: function(hWnd: HWND): HDC; stdcall;
begin
hmod := GetModuleHandle('Gdi32.dll');
hmod2:= GetModuleHandle('User32.dll');
if (hmod <> 0) and (hmod2 <> 0) then begin
bmp := TBitmap.Create;
bmp.Height := Screen.Height;
bmp.Width := Screen.Width;
GetWindowDCAPI:= GetProcAddress(hmod2, 'GetWindowDC');
if (#GetWindowDCAPI <> nil) then begin
DCDesk := GetWindowDCAPI(GetDesktopWindow);
end;
BitBltAPI:= GetProcAddress(hmod, 'BitBlt');
if (#BitBltAPI <> nil) then begin
BitBltAPI(bmp.Canvas.Handle, 0, 0, Screen.Width, Screen.Height, DCDesk, 0, 0, SRCCOPY);
bmp.SaveToFile('ScreenShot_------_' + RandomPassword(8) + '.bmp');
end;
ReleaseDC(GetDesktopWindow, DCDesk);
bmp.Free;
FreeLibrary(hmod);
FreeLibrary(hmod2);
end;
end;
begin
while True do
begin
Printscreen;
Sleep(5000);
end;
end.
That produces this result
Already using Team View software for example, the window appears on screen capture normally and produces this result.
So, exist some way for see this window in screen capture like is possible from of Team View software?
All suggestions will be welcomed.
It seems that you are trying to get the screenshot of a secure desktop. If that is the case first you must read the documentation about this topic. Because this is not a trivial task (you must know about Sessions, Desktops and Windows Stations). Also your application must be a trusted process running from the Local SYSTEM Account.
From here now you must do this.
Select the proper Input WinStation (OpenWindowStation, GetProcessWindowStation, SetProcessWindowStation)
Switch to the active (secure) desktop (OpenInputDesktop, GetThreadDesktop, SetThreadDesktop)
Finally use the BitBlt to capture the screen.
Recommended Lecture
Sessions, Desktops and Windows Stations
MSDN Desktops reference.
i have thread in my application shows messageboxs in another application with title 'Test' on every event the thread create it,by the end of this thread i wanna close all of this messages.
i tried to create loop like this
while FindWindow(Nil,PChar('Test')) <> 0 do
begin
Sleep(5); //if i remove the sleep the application will hanging and froze.
SendMessage(FindWindow(Nil,PChar('Test')), WM_CLOSE, 0, 0); // close the window message
end;
but this loop works only if i close the last message manually
Note: the messageboxs comes from another applaction not in the same application have this thread.
Try this instead:
var
Wnd: HWND;
begin
Wnd := FindWindow(Nil, 'Test');
while Wnd <> 0 do
begin
PostMessage(Wnd, WM_CLOSE, 0, 0);
Wnd := FindWindowEx(0, Wnd, Nil, 'Test');
end;
end;
Or:
function CloseTestWnd(Wnd: HWND; Param: LPARAM): BOOL; stdcall;
var
szText: array[0..5] of Char;
begin
if GetWindowText(Wnd, szText, Length(szText)) > 0 then
if StrComp(szText, 'Test') = 0 then
PostMessage(Wnd, WM_CLOSE, 0, 0);
Result := True;
end;
begin
EnumWindows(#CloseTestWnd, 0);
end;
Your logic seems to be somewhat... off. :-) You may or may not be sending the WM_CLOSE to the same window, since you're using one FindWindow to see if it exists and a different call to FindWindow to send the message.
I'd suggest doing it more like this:
var
Wnd: HWnd;
begin
Wnd := FindWindow(nil, 'Test'); // Find the first window (if any)
while Wnd <> 0 do
begin
SendMessage(Wnd, WM_CLOSE, 0, 0); // Send the message
Sleep(5); // Allow time to close
Wnd := FindWindow(nil, 'Test'); // See if there's another one
end;
end;
Depending on what the other application is doing, you may need to increase the Sleep time in order to allow the window time to receive and process the WM_CLOSE message; otherwise, you'll be simply sending it multiple times to the same window. (I'm suspecting that 5 ms is far too little time.)
Below is the complete routine I'm using to send the key Ctrl + Shift + S to a PDF document. It should show the save dialog but fails to do so.
The procedure opens a pdf document residing in sFolder using GetFiles. There is only one pdf doc in sFolder.
As you can see from the commented out lines, I also tried the sndkey32 without success.
procedure TForm1.Button1Click(Sender: TObject);
var
oBrowser: TBrowseForFolder;
oList: TStringDynArray;
sFile: string;
sFolder: string;
oShellExecuteInfo: TShellExecuteInfo;
begin
oBrowser := TBrowseForFolder.Create(self);
oBrowser.Execute;
sFolder := oBrowser.Folder;
oBrowser.Free;
if DirectoryExists(sFolder) then begin
oList := TDirectory.GetFiles(sFolder, '*.pdf', TSearchOption.soAllDirectories);
if Length(oList) > 0 then begin
for sFile in oList do begin
FillChar(oShellExecuteInfo, SizeOf(oShellExecuteInfo), 0);
oShellExecuteInfo.cbSize := SizeOf(TShellExecuteInfo);
with oShellExecuteInfo do begin
fMask := SEE_MASK_NOCLOSEPROCESS;
Wnd := Application.Handle;
lpFile := PChar(sFile);
nShow := SW_SHOWNORMAL;
end;
if ShellExecuteEx(#oShellExecuteInfo) then begin
ShowWindow(oShellExecuteInfo.Wnd, 1);
SetForegroundWindow(oShellExecuteInfo.Wnd);
Winapi.Windows.SetFocus(oShellExecuteInfo.Wnd);
SendKey(Ord('s'), [ssCtrl, ssShift], False);
// if sndkey32.AppActivate('adobe') then
// sndkey32.SendKeys('^+S', False);
end;
end;
end;
end;
end;
procedure TForm1.SendKey(key: Word; const shift: TShiftState; specialkey: Boolean);
type
TShiftKeyInfo = record
shift: Byte;
vkey: Byte;
end;
ByteSet = set of 0 .. 7;
const
shiftkeys: array [1 .. 3] of TShiftKeyInfo = ((shift: Ord(ssCtrl); vkey: VK_CONTROL), (shift: Ord(ssShift); vkey: VK_SHIFT), (shift: Ord(ssAlt); vkey: VK_MENU));
var
flag: DWORD;
bShift: ByteSet absolute shift;
j: Integer;
begin
for j := 1 to 3 do begin
if shiftkeys[j].shift in bShift then keybd_event(shiftkeys[j].vkey, MapVirtualKey(shiftkeys[j].vkey, 0), 0, 0);
end;
if specialkey then flag := KEYEVENTF_EXTENDEDKEY
else flag := 0;
keybd_event(key, MapVirtualKey(key, 0), flag, 0);
flag := flag or KEYEVENTF_KEYUP;
keybd_event(key, MapVirtualKey(key, 0), flag, 0);
for j := 3 downto 1 do begin
if shiftkeys[j].shift in bShift then keybd_event(shiftkeys[j].vkey, MapVirtualKey(shiftkeys[j].vkey, 0), KEYEVENTF_KEYUP, 0);
end;
end;
The window oShellExecuteInfo.Wnd is a window in your Delphi process. You assign it as Application.Handle. You seem to be hoping that it will be the main window of the PDF viewer but that's not the case.
So you need to find the main window of the PDF viewer. That involves a call to EnumerateWindows to get all top level windows. Then, for each one, use GetWindowThreadProcessId to test whether or not the window is owned by the PDF viewer process.
Some other comments:
You neglect error checking when calling API functions.
You should use SendInput rather than keybd_event.
You leak the process handle returned by ShellExecuteEx.
It is possible that ShellExecuteEx does not return a process handle at all. That depends on how the file association is setup, and whether or not Acrobat was already running.
You may need to wait until the new process has finished starting up before you send input.
Your program seems to assume that the installed PDF viewer is Acrobat. What if it is not?
Good afternoon :-), in my application I use OleContainer to view presentation from Microsoft Powerpoint.
This code I use to load and run presentation file:
with oleContainer do begin
Parent := mediaPanel; Left := 0; Top := 0;
Width := mediaPanel.Width; Height := mediaPanel.Height;
CreateObjectFromFile('C:\Users\Nanik\Desktop\Present.ppt', false);
Iconic := false; Visible := true; Run;
end;
The presentation was created as autoplay slideshow (in Microsoft PowerPoint working), but in my application presentation was still on first slide. Run command isn't right?
You do not need a OleContainer to run the presentation inside a container in your application. Put a panel container to run the presentation in your form and try this routine:
procedure TForm2.Button3Click(Sender: TObject);
const
ppShowTypeSpeaker = 1;
ppShowTypeInWindow = 1000;
SHOW_FILE = 'C:\Users\jcastillo\Documents\test.pps';
var
oPPTApp: OleVariant;
oPPTPres: OleVariant;
screenClasshWnd: HWND;
pWidth, pHeight: Integer;
function PixelsToPoints(Val: Integer; Vert: Boolean): Integer;
begin
if Vert then
Result := Trunc(Val * 0.75)
else
Result := Trunc(Val * 0.75);
end;
begin
oPPTApp := CreateOleObject('PowerPoint.Application');
oPPTPres := oPPTApp.Presentations.Open(SHOW_FILE, True, True, False);
pWidth := PixelsToPoints(Panel1.Width, False);
pHeight := PixelsToPoints(Panel1.Height, True);
oPPTPres.SlideShowSettings.ShowType := ppShowTypeSpeaker;
oPPTPres.SlideShowSettings.Run.Width := pWidth;
oPPTPres.SlideShowSettings.Run.Height := pHeight;
screenClasshWnd := FindWindow('screenClass', nil);
Windows.SetParent(screenClasshWnd, Panel1.Handle);
end;
I do not have documentation at hand, but my thought is Run.Width and Run.Height must be provided in points, not in pixels. My poor man solution to convert pixels to points is here, and it works for me in my tests here... to find the correct way to convert in your environment is up to you.
Is supposed you can get the Handle of the presentation window from the oPPTPres.SlideShowSettings.Run.HWND property, but that does not work here for me, hence the FindWindow call.
Run is a method of TOleContainer, it is not a method specific to any kind of OLE object, say, a power point presentation or a bitmap image.. Documentation states "Call Run to ensure that the server application is running..".
You need to call object specific methods to operate on them, see PowerPoint Object Model Reference. Sample code:
procedure TForm1.Button1Click(Sender: TObject);
const
ppAdvanceOnTime = $00000002;
var
P: OleVariant;
S: OleVariant;
i: Integer;
begin
P := OleContainer1.OleObject.Application.Presentations.Item(1);
// below block would not be necessary for a slide show (i.e. a *.pps)
for i := 1 to P.Slides.Count do begin
P.Slides.Item(i).SlideShowTransition.AdvanceOnTime := True;
P.Slides.Item(i).SlideShowTransition.AdvanceTime := 1;
end;
S := P.SlideShowSettings;
S.AdvanceMode := ppAdvanceOnTime;
S.Run;
end;
Though the above will run the presentation as a slide show, it is probably not what you'd want because it runs in full screen. I have no idea how to run it in the container window..