Getting Page Number of PDF document from Adobe Reader's ActiveX control - delphi

I'm successfully using Delph 7 and the ActiveX control of Adobe Reader version 7 to extract the page number from an open PDF document housed in the ActiveX component (TAcroPDF). I am interested in upgrading to the latest Adobe reader but something changed in Adobe Reader 8 (and 9) that prevented me from upgrading (I have not tested Adobe 10/X). With Adobe 7, I use the Windows SDK function EnumChildWindows to gather the child windows of my form containing the TAcroPDF component and find a control with the name AVPageNumView, then FindWindowEx to get its handle. Then I call SendMessage to get the text of that control which has the page number information. With Adobe 8 and 9, window/control AVPageNumView is no longer there it seems. Thus I am stuck in Adobe 7 and still looking for a way to get the page number, preferably Adobe 9 or 10/X. The goal would be to not have to do a complete rewrite with another technology, but I am open to that if its the only solution.
Thanks,
Michael

You're using a wndclass name (AVPageNumView). Obviously, the class name has changed in the new version. You can use something like WinDowse to investigate the windows in the newer version of Reader to find out the new class names. Update your code to first check for the old wndclass; if it's not found, try and find the new one.

function EnumWindowProc(pHwnd: THandle; Edit: Integer): LongBool; stdcall;
function GetWindowTxt(gwtHwnd: THandle): string;
var dWTextBuf: PChar;
TextLen: Integer;
begin
TextLen := SendMessage(gwtHwnd, WM_GetTextLength, 0, 0);;
dWTextBuf := StrAlloc(TextLen + 1);
SendMessage(gwtHwnd, WM_GetText, TextLen + 1, Integer(dWTextBuf));
Result := dWTextBuf;
StrDispose(dWTextBuf);
end;
function GetClassNameTxt(gcnHwnd: THandle): string;
var dWClassBuf: PChar;
begin
dWClassBuf := StrAlloc(1024);
GetClassName(gcnHwnd, dWClassBuf, 1024);
Result := dWClassBuf;
StrDispose(dWClassBuf);
end;
begin
Result := LongBool(True);
if (GetClassNameTxt(pHwnd) = 'AVL_AVView') and (GetWindowTxt(pHwnd) = 'AVPageView') then
begin
TEdit(Edit).Text := GetWindowTxt(FindWindowEx(pHwnd, 0, 'RICHEDIT50W', nil));
Result := LongBool(False);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
EnumChildWindows(AcroPDF1.Handle, #EnumWindowProc, LongInt(Edit1));
end;

Related

How to adjust the balance L/R of sound with Delphi FMX TMediaPlayer

I currently use both Delphi XE6 and Delphi Seattle:
I am busy putting together a little app on Firemonkey that needs to play sound files (mp3, wav etc.). Adjusting the master volume is straight forward, but it seems that adjusting the left-to-right balance of a sound file playing is not.
This is the code that I have for achieving this feat, except, it will not be supported in FMX, as it calls mostly Windows API functions. Can anyone help with the API functions to call on the FMX platform instead? At this point I am hoping to support at least Android devices. If there is additional/alternative code (or compiler directive settings with alternative code) to cover for iOS devices as well, that would be greatly appreciated.
Thank you very much in advance!
Here is what I have so far...
function GetWaveVolume(var LVol: DWORD; var RVol: DWORD): Boolean;
var
WaveOutCaps: TWAVEOUTCAPS;
Volume: DWORD;
begin
Result := False;
if WaveOutGetDevCaps(WAVE_MAPPER, #WaveOutCaps, SizeOf(WaveOutCaps)) = MMSYSERR_NOERROR then
if WaveOutCaps.dwSupport and WAVECAPS_VOLUME = WAVECAPS_VOLUME then
begin
Result := WaveOutGetVolume(WAVE_MAPPER, #Volume) = MMSYSERR_NOERROR;
LVol := LoWord(Volume);
RVol := HiWord(Volume);
end;
end;
function SetWaveVolume(const AVolume: DWORD): Boolean;
var
WaveOutCaps: TWAVEOUTCAPS;
begin
Result := False;
if WaveOutGetDevCaps(WAVE_MAPPER, #WaveOutCaps, SizeOf(WaveOutCaps)) = MMSYSERR_NOERROR then
if WaveOutCaps.dwSupport and WAVECAPS_VOLUME = WAVECAPS_VOLUME then
Result := WaveOutSetVolume(WAVE_MAPPER, AVolume) = MMSYSERR_NOERROR;
end;

Delphi Console XE7 Clearscreen

How I can clear the console screen in a delphi console application (delphi xe6 or higher) I have searched the internet and the help file but cannot seem to find it?
I am trying to find out if there is a function already provided in the delphi units to provide this functionality.
There is no such function provided by the Delphi runtime library. You will need to write your own function using the operating system services. This article on MSDN explains how to do it: https://support.microsoft.com/en-us/kb/99261
Translate that like so:
procedure ClearScreen;
var
stdout: THandle;
csbi: TConsoleScreenBufferInfo;
ConsoleSize: DWORD;
NumWritten: DWORD;
Origin: TCoord;
begin
stdout := GetStdHandle(STD_OUTPUT_HANDLE);
Win32Check(stdout<>INVALID_HANDLE_VALUE);
Win32Check(GetConsoleScreenBufferInfo(stdout, csbi));
ConsoleSize := csbi.dwSize.X * csbi.dwSize.Y;
Origin.X := 0;
Origin.Y := 0;
Win32Check(FillConsoleOutputCharacter(stdout, ' ', ConsoleSize, Origin,
NumWritten));
Win32Check(FillConsoleOutputAttribute(stdout, csbi.wAttributes, ConsoleSize, Origin,
NumWritten));
Win32Check(SetConsoleCursorPosition(stdout, Origin));
end;

Detect Chrome as browser associated with html files in Windows

We provide Flash tutorial videos that install on the local (Windows) hard disk with our application. Our app uses ShellExecute to open the html file (in whatever browser is associated with html files) in which they are embedded.
Apparently there's a bug in Chrome's more recent Flash players that fails to play local files (but files over the web are fine.)
(Frankly, I'm astonished that this bug hasn't been fixed by Google. Seems like a big one to me... but maybe not many people play Flash from locations other than the web?)
There's a work-around on the about:plugins screen in Chrome, but we can't ask our users to do that. Here's a discussion of the work-around: http://techsmith.custhelp.com/app/answers/detail/a_id/3518
I want to provide my users with an option to open our html files IE. If Chrome is their default browser, then I'd show a checkbox that says something embarrassing like "If our tutorial videos fail to play, check this box to try them in IE."
Is this XE2 code (from two years ago on SO: link) still reasonable?
if pos('CHROME', UpperCase(GetAssociation('C:\Path\File.html')) > 0 then
// Chrome is the default browser
function GetAssociation(const DocFileName: string): string;
var
FileClass: string;
Reg: TRegistry;
begin
Result := '';
Reg := TRegistry.Create(KEY_EXECUTE);
Reg.RootKey := HKEY_CLASSES_ROOT;
FileClass := '';
if Reg.OpenKeyReadOnly(ExtractFileExt(DocFileName)) then
begin
FileClass := Reg.ReadString('');
Reg.CloseKey;
end;
if FileClass <> '' then begin
if Reg.OpenKeyReadOnly(FileClass + '\Shell\Open\Command') then
begin
Result := Reg.ReadString('');
Reg.CloseKey;
end;
end;
Reg.Free;
end;
If you have an actual full path to an existing file on disk, you can use FindExecutable instead. It's easier, and doesn't require access to the registry, but it does require that an actual file exists.
Here's a console app for XE2 that demonstrates use:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, ShellAPI, Windows;
var
Buffer: array[0..MAX_PATH] of Char;
Res: Integer;
begin
FillChar(Buffer, SizeOf(Buffer), #0);
Res := FindExecutable(PChar('C:\Path\File.html'), nil, Buffer);
if Res > 32 then
Writeln('Executable is ' + Buffer)
else
WriteLn(SysErrorMessage(Res));
Readln;
end.
The method you show will work, but FindExecutable is easier (less code) and works on XP and above.

How can I get the tooltips of notification-area icons?

I can enumerate the applications (handle,pid,path) with icons in the notification area, and I can control the position of the icons, but I can't get the tooltip.
How can I enumerate systray icons including the tooltips?
The shell provides no facility for inspecting notification icons that don't belong to your program. (And it provides no way of enumerating even the icons that do belong to your program; you're expected to already know about those.)
I used to use a program that hijacked some or all of the icons and optionally displayed them in its own window instead of in the area near the clock, so it must have been able to get a list of all the icons. It was TraySaver, by Mike Lin. The source is available if you wish to see how his hack worked.
You can also take a look at the answers to a previous question that asked about controlling the position of icons in the notification area.
You should take a look at the madKernal package of madshis component collection. It has some interfaces for working with trayicons. Beware, though:
With madKernel you can manage tray icons (see API "Shell_NotifyIcon") of any application. This kind of functionality is totally undocumented, but works well from win95 to winXP.
The ITrayIcon-interface has properties for hint, icon, position and more.
Here is my method tested with windows xp and delphi 2010 if you are using a version of delphi wich doesn't support unicode make shure you convert the strings read to ansi
uses CommCtrl;
function TForm1.GetIconsCount: Integer;
begin
Result := SendMessage(FindTrayToolbar, TB_BUTTONCOUNT, 0, 0);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ListTips;
end;
function TForm1.FindTrayToolbar: HWND;
begin
Result := FindWindow('Shell_TrayWND', nil);
Result := FindWindowEx(Result, 0, 'TrayNotifyWnd', nil);
Result := FindWindowEx(Result, 0, 'SysPager', nil);
Result := FindWindowEx(Result, 0, 'ToolbarWindow32', nil);
end;
procedure TForm1.ListTips;
var
dwTray: DWORD;
wndTray: HWND;
hTray: THandle;
remoteTray: Pointer;
tdata: TTBBUTTON;
i: Integer;
btsread:DWORD;
str:Pchar;
begin
wndTray := FindTrayToolbar;
GetWindowThreadProcessId(wndTray, #dwTray);
hTray := OpenProcess(PROCESS_ALL_ACCESS, false, dwTray);
if hTray <> 0 then
begin
remoteTray := VirtualAllocEx(hTray, nil, Sizeof(tdata), MEM_COMMIT,
PAGE_READWRITE);
for i := 0 to GetIconsCount - 1 do
begin
SendMessage(FindTrayToolbar,TB_GETBUTTON,wparam(i),lparam(remotetray));
ReadProcessMemory(hTray,remotetray,#tdata,sizeof(tdata),btsread);
GetMem(str,255);
ReadProcessMemory(hTray,Ptr(tdata.iString),str,255,btsread);
ListBox1.Items.Add(str);
end;
end
else ShowMessage('Could not locate tray icons');
end;
end.

How to get Firefox bookmarks from a Delphi application?

I know how to get the favourites from IE, but how can I access Firefox's bookmarks?
Here's the code I have for retrieving the IE favourites:
uses
ShlObj, ActiveX;
function GetIEFavourites(const favpath: string): TStrings;
var
searchrec: TSearchRec;
str: TStrings;
path, dir, FileName: string;
Buffer: array[0..2047] of Char;
found: Integer;
begin
str := TStringList.Create;
// Get all file names in the favourites path
path := FavPath + '\*.url';
dir := ExtractFilepath(path);
found := FindFirst(path, faAnyFile, searchrec);
while found = 0 do
begin
// Get now URLs from files in variable files
Setstring(FileName, Buffer, GetPrivateProfilestring('InternetShortcut',
PChar('URL'), nil, Buffer, SizeOf(Buffer), PChar(dir + searchrec.Name)));
str.Add(FileName);
found := FindNext(searchrec);
end;
// find Subfolders
found := FindFirst(dir + '\*.*', faAnyFile, searchrec);
while found = 0 do
begin
if ((searchrec.Attr and faDirectory) > 0) and (searchrec.Name[1] <> '.') then
str.Addstrings(GetIEFavourites(dir + '\' + searchrec.Name));
found := FindNext(searchrec);
end;
FindClose(searchrec);
Result := str;
end;
procedure FreePidl(pidl: PItemIDList);
var
allocator: IMalloc;
begin
if Succeeded(SHGetMalloc(allocator)) then
begin
allocator.Free(pidl);
{$IFDEF VER100}
allocator.Release;
{$ENDIF}
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
pidl: PItemIDList;
FavPath: array[0..MAX_PATH] of Char;
begin
if Succeeded(ShGetSpecialFolderLocation(Handle, CSIDL_FAVORITES, pidl)) then
begin
if ShGetPathfromIDList(pidl, FavPath) then
ListBox1.Items := GetIEFavourites(StrPas(FavPath));
// The calling application is responsible for freeing the PItemIDList-pointer
// with the Shell's IMalloc interface
FreePIDL(pidl);
end;
end;
Thanks.
The favorites are saved in 'places.sqlite' in the profile folder. They are in table moz_bookmarks. They refer to entries in table moz_places with their field fk. Get sqlite as dll and a delphi binding like this one.
Open the database with SQLite3_Open and use SQLite3_Exec to send ordinary sql statements to access the data, like
SELECT * FROM moz_bookmarks;
Unfortunately firefox locks places.sqlite, which means you have to copy it first (normal file copy). After you have worked on the copy you can delete it.
TBookmarks component from MetaProduct... it's $75.00 though:
http://www.metaproducts.com/mp/TBookmarks_component.htm
quote from their site:
For Borland Delphi 2, 3, 4, 5, 6, 7, 2005, 2006, 2007, 2009.
New! FireFox 3, Safari and Google Chrome Bookmarks are supported!
MetaProducts TBookmarks is a Delphi 2 - 7, 2005-2009 component that helps you to display MS Internet Explorer Favorites (4.0 - 8.0,) MSN Explorer, Opera Hotlists (3.0 - 9.0) and Netscape, Safari, Chrome, FireFox and Mozilla Bookmarks (2.0 - 8.0) in a menu.
Simply drop the TBookmarks component on the form and assign its Menu property and OnURL event. Set Enabled to True to collect all bookmark information in the specified TMenuItem.
You can also use TTreeView component to make TBookmarks populate the entries there automatically.
Well, Firefox bookmarks are a HTML file stored in
<WindowsUserPath>\Application Data\Mozilla\Firefox\Profiles\
<aRamdonProfileName>\bookmark.htm as Sinan Ünür said.
So you need to get the mozilla profiles dir and retrie the folder
name in there.
After that you need to parse the html file.....
So AFAIK, no, there's no API to directly get the FF bookmarks.

Resources