how can i retrieve text from a web sites text boxes in delphi for example suppose i type
''tiger'' in google's search box how do i retrieve text from that search box would wm_gettext or getwindowtext work?
i am using delphi 7
try this code.
Only works with internet explorer. tested in Windows Vista,IE8 y Delphi 2007.
Uses
SHDocVw,
mshtml;
procedure GetTextFromEditIExplorer(ListStr: TStringList);
var
ShellWindow : IShellWindows;
Web_Browser : IWebbrowser2;
reg_Shell_window : IDispatch;
Dummy : IHTMLDocument2;
ovElements : OleVariant;
Document : Variant;
WindowsCount : Integer;
ElementsCount : Integer;
FormsCount : Integer;
begin
ShellWindow := CoShellWindows.Create; //Provides access to the collection of open Shell windows
for WindowsCount := 0 to ShellWindow.Count do //iterate through number of windows in the Shell windows collection
begin
reg_Shell_window := ShellWindow.Item(WindowsCount); //Returns the registered Shell window for a specified index.
if reg_Shell_window = nil then Continue; //go to next reg window
reg_Shell_window.QueryInterface(iWebBrowser2, Web_Browser); // determines if an interface can be used with an object
if Web_Browser <> nil then
begin
Web_Browser.Document.QueryInterface(IHTMLDocument2, Dummy);
if Dummy <> nil then
begin
Web_Browser := ShellWindow.Item(WindowsCount) as IWebbrowser2;
Document := Web_Browser;
for FormsCount := 0 to Document.forms.Length - 1 do
begin
ovElements := Document.forms.Item(FormsCount).elements;
for ElementsCount := 0 to ovElements.Length - 1 do
begin
try
if (CompareText(ovElements.item(ElementsCount).tagName, 'INPUT') = 0) and (CompareText(ovElements.item(ElementsCount).type, 'text') = 0) then
ListStr.Add('Control Name ['+ovElements.item(ElementsCount).Name+']'+' Type -> '+ovElements.item(ElementsCount).Type+' -> Value ['+ovElements.item(ElementsCount).Value+']');
except
ListStr.Add('Error Reading element n° '+IntToStr(ElementsCount));
end;
end;
end;
end;
end;
end;
end;
procedure TForm1.btn1Click(Sender: TObject);
var
List : TStringList;
begin
List:=TStringList.Create;
GetTextFromEditIExplorer(List);
ShowMessage(List.Text);
end;
Edit :
Omar unfortunately there is no simple solution to your problem. This is because each browser uses a different interface to interact with the information.
Here are a couple of suggestions
Firefox uses XPCOM, you can research about that.
Try using DDE (dynamic data exchange).
You can use WatiN, is a .net library wich work with firefox and iexplorer. you can see this article to learn how interact with a .net Assembly in delphi win32.
Bye.
The simplest way would be by using a regular expression on the original HTML code from the page.
Related
I am trying to retrieve the <table><tbody> section of this page:
http://www.mfinante.ro/infocodfiscal.html?captcha=null&cod=18505138
I am using Delphi XE7.
I tried using IXMLHttpRequest, WinInet (InternetOpenURL(), InternetReadFile()), TRestClient/TRestRequest/TRestResponse, TIdHTTP.Get(), but all they retrieve is some gibberish, like this:
<html><head><meta http-equiv="Pragma" content="no-cache"/>'#$D#$A'<meta http-equiv="Expires" content="-1"/>'#$D#$A'<meta http-equiv="CacheControl" content="no-cache"/>'#$D#$A'<script>'#$D#$A'(function(){p={g:"0119a4477bb90c7a81666ed6496cf13b5aad18374e35ca73f205151217be1217a93610c5877ece5575231e088ff52583c46a8e8807483e7185307ed65e",v:"87696d3d40d846a7c63fa2d10957202e",u:"1",e:"1",d:"1",a:"challenge etc.
Look at this code for example:
program htttpget;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, HTTPApp, IdHTTP, ActiveX;
var
CoResult: Integer;
HTTP: TIdHTTP;
Query: String;
Buffer: String;
begin
try
CoResult := CoInitializeEx(nil, COINIT_MULTITHREADED);
if not((CoResult = S_OK) or (CoResult = S_FALSE)) then
begin
Writeln('Failed to initialize COM library.');
Exit;
end;
HTTP := TIdHTTP.Create;
Query := 'http://www.mfinante.ro/infocodfiscal.html?captcha=null' +
'&cod=18505138';
Buffer := HTTP.Get(Query);
writeln(Buffer);
HTTP.Destroy;
except
end;
end.
What is wrong with this page? I haven not done very many "get" functions in my life, but other websites return normal responses. Can someone at least clarify to me why this isn't working?
Are there other ways to get the content of this web page? Are there other programming languages (Java, scripting, etc) that can do this without third party software (like using Firefox source code to emulate a browser, fetch the page, without showing the window, and then copy the content).
You can use TWebBrowser for this.
See this post: How can I get HTML source code from TWebBrowser
The answer by RRUZ, which you can find in many places on the internet, is not what you are looking for. This gives you are original html source, as would IdHttp.Get().
However, the answer by Mehmet Fide will give you the HTML source of the DOM, which is what you are looking for.
I offer a variation here. (It includes some hacks that were required at the time to get full DOCTYPE. Not sure if they are still needed...)
function EndStr(const S: String; const Count: Integer): String;
var
I: Integer;
Index: Integer;
begin
Result := '';
for I := 1 to Count do
begin
Index := Length(S)-I+1;
if Index > 0 then
Result := S[Index] + Result;
end;
end;
function GetHTMLDocumentSource(WebBrowser: TWebBrowser; var Charset: String):
String;
var
Element: IHTMLElement;
Node: IHTMLDomNode;
Document: IHTMLDocument2;
I: Integer;
S: String;
begin
Result := '';
Document := WebBrowser.Document as IHTMLDocument2;
For I := 0 to Document.all.length -1 do
begin
Element := Document.all.item(I, 0) as IHTMLElement;
If Element.tagName = '!' Then
begin
Node := Element as IHTMLDomNode;
If (Node <> nil) and (Pos('CTYPE', UpperCase(Node.nodeValue)) > 0) Then
begin
S := VarToStr(Node.nodeValue); { don't change case of result }
if Copy(Uppercase(S), 1, 5) = 'CTYPE' then
S := 'DO' + S;
if Copy(Uppercase(S), 1, 7) = 'DOCTYPE' then
S := '<!' + S;
if Uppercase(S) = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 TRANSITIONAL//E' then
S := S +'N">';
if EndStr(Lowercase(S), 3) = '.dt' then
S := S + 'd"';
if EndStr(Lowercase(S), 5) = '.dtd"' then
S := S + '>';
Result := Result + S;
end;
end
Else
Result := Result + Element.outerHTML;
If Element.tagName = 'HTML' Then
Break;
end;
Charset := Document.charset;
end;
So call WebBrowser.Navigate(URL), then in OnDocumentComplete event retrieve the Html Source.
However, with your URL you will see the OnDocumentComplete event fires twice :(, so you need to get the Html from the last fire.
You can refer to this post How do I avoid the OnDocumentComplete event for embedded iframe elements? for info on how to get the final OnDocumentComplete event. However, I tried it and it was not working for me. You may need to use some other strategy to get the last event.
Not sure of your needs, but you may also optimize this process by disabling WebBrowser from downloading images. I believe that is possible.
This is normal, you have indeed retrieved the content correctly. What happens in your browser is that the script is executed and the page gets built client side. If you wish to replicate that in your code, then you will need to do the same. Execute the script exactly as the browser would.
What you are really looking for here is what is known as a headless browser. Integrate one of those into your program. Then get the headless browser to process the request, including executing scripts. When it has done executing scripts, read the modified content of the page.
I have been trying to get a list of menu sub-items from a standard Windows application using the UIAutomationCore library imported as a TLB into Delphi - i.e.
File -> New | Exit
Help -> About
I can get the application menu, and then the top-level items into a list (i.e. in the example above, 'File' and 'Help', but I cannot get a list of ANY controls that are under these menuitems. My code is as below - the FElement represents the actual menuitem I am checking.
The length of the collection returned by FindAll is always 0. I have tried expanding the menuitem prior to this code, but it seems to have no effect.
UIAuto.CreateTrueCondition(condition);
FItems := TObjectList<TAutomationMenuItem>.create;
self.Expand;
sleep(3000);
// Find the elements
self.FElement.FindAll(TreeScope_Descendants, condition, collection);
collection.Get_Length(length);
for count := 0 to length -1 do
begin
collection.GetElement(count, itemElement);
itemElement.Get_CurrentControlType(retVal);
if (retVal = UIA_MenuItemControlTypeId) then
begin
item := TAutomationMenuItem.Create(itemElement);
FItems.Add(item);
end;
end;
I can see examples of this in C#, and they are not really doing anything different from the code above (as far as I can see)
Thanks in advance
Update : It looks very similar to this question
Update2 : In this example it is trying to do this for another Delphi application. However, if I try the same thing on notepad (for example), the same issue occurs.
Update3 : Using Inspect (and then using UI Automation), I have the following structure ...
Name = Exit
Ancestors = File (menu) Form1 (pane)
I have also tried this after expanding the menu (file), and the same thing is happening (or not happening).
I think you have the following two issues:
The menus will not list the sub menu items unless the menu is expanded
If you're trying to automate your own application, you have to do it in a thread.
The following works for me:
// Careful: the code might not be 100% threadsafe, but should work for the purpose of demonstration
const
UIA_MenuItemControlTypeId = 50011;
UIA_ControlTypePropertyId = 30003;
UIA_NamePropertyId = 30005;
UIA_ExpandCollapsePatternId = 10005;
procedure TForm1.Button1Click(Sender: TObject);
begin
TThread.CreateAnonymousThread(procedure begin CoInitializeEx(nil, 2); FindItems(true); CoUninitialize; end).Start;
end;
procedure TForm1.FindItems(Recurse: Boolean);
var
UIAuto: TCUIAutomation;
condition: IUIAutomationCondition;
collection: IUIAutomationElementArray;
Length: Integer;
Count: Integer;
itemElement: IUIAutomationElement;
retVal: Integer;
val: WideString;
ExpandCollapsePattern: IUIAutomationExpandCollapsePattern;
FElement: IUIAutomationElement;
begin
UIAuto := TCUIAutomation.Create(nil);
UIAuto.CreateTrueCondition(condition);
// Find the elements
UIAuto.ElementFromHandle(Pointer(Handle), FElement);
FElement.FindAll(TreeScope_Descendants, condition, collection);
collection.Get_Length(length);
for Count := 0 to length - 1 do
begin
collection.GetElement(Count, itemElement);
itemElement.Get_CurrentControlType(retVal);
if (retVal = UIA_MenuItemControlTypeId) then
begin
ItemElement.Get_CurrentName(val);
TThread.Synchronize(nil,
procedure
begin
memo1.lines.Add(val);
end);
itemElement.GetCurrentPattern(UIA_ExpandCollapsePatternId, IInterface(ExpandCollapsePattern));
if Assigned(ExpandCollapsePattern) then
begin
ExpandCollapsePattern.Expand;
if Recurse = True then
FindItems(False);
end;
end;
end;
UIAuto.Free;
end;
Assuming I have the Delphi IDE open, how can I open a .pas file selected in another app and open it in the Delphi IDE, as well as positioning it to a specific line number?
I've seen some editing tools do this.
I'm not sure if it's just an option to a normal file open (eg., using default file association), or a command-line option, or you need DDE or COM or something entirely different.
Note that I don't want to close the project and reopen a new or fake project.
Also, I don't want the file added to the project. I just want to open it.
For example, When you <ctrl>-click on a varible or type, the IDE will open the file containing that symbol and go to the line where that symbol is declared. That's all I want to do -- but from an external app. (I'm not looking for a symbol, just a line.)
I'm using Delphi XE5 at the moment, so I'm interested in newer Delphi versions, not pre-XE2 or so.
(Part of the question is, how do I ensure that if the IDE is already open, the the file is opened in anew tab inside of the current IDE rather than in another instance of the IDE?)
The code below (for D7) shows how this can be done by way of an IDE add-in .Dpk compiled
into a Bpl. It started as just a "proof of concept", but it does actually work.
It comprises a "sender" application which uses WM_COPYDATA to send the FileName, LineNo & Column to a receiver hosted in the .Bpl file.
The sender sends the receiver a string like
Filename=d:\aaad7\ota\dskfilesu.pas
Line=8
Col=12
Comment=(* some comment or other*)
The Comment line is optional.
In the .Bpl, the receiver uses OTA services to open the requested file and positions the editor caret, then inserts the comment, if any.
The trickiest thing was to find out how to handle one particular complication, the case where the named file to be opened is one with an associated form. If so, in D7 (and, I assume, other IDE versions with the floating designer option enabled) when the IDE
opens the .Pas file, it also opens the .Dfm, and left to its own devices, that would leave the form editor in front of the code editor. Calling the IOTASourceEditor.Show for the .Pas file at least puts the IDE code editor in front of the .Dfm form, but that didn't satisfy me, because by now my curiosity was piqued - how do you get a form the IDE is displaying off the screen?
I spent a lot of time exploring various blind alleys, because the OTA + NTA services don't seem to provide any way to explicitly close an IOTAEditor or any of its descendants. In the end it turned out that the thing to do is simply get a reference to the form and just send it a WM_CLOSE(!) - see comments in the code.
Fwiw, being a novice at OTA, at first (before I found out how IOTAModules work) I found that far and away the most difficult part of this was discovering how to get hold of the IEditView interface needed to set the editor caret position, but as usual with these interfacey things, once you get the "magic spell" exactly right, it all works.
Good luck! And thanks for the fascinating challenge!
unit Receiveru;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ToolsAPI;
type
TOTAEditPosnForm = class(TForm)
Memo1: TMemo;
private
FEdLine: Integer;
FEdCol: Integer;
FEditorFileName: String;
FEditorInsert: String;
procedure WMCopyData(var Msg : TWMCopyData); message WM_COPYDATA;
procedure HandleCopyDataString(CopyDataStruct : PCopyDataStruct);
procedure OpenInIDEEditor;
property EditorFileName : String read FEditorFileName write FEditorFileName;
property EdLine : Integer read FEdLine write FEdLine;
property EdCol : Integer read FEdCol write FEdCol;
property EditorInsert : String read FEditorInsert write FEditorInsert;
end;
var
OTAEditPosnForm: TOTAEditPosnForm;
procedure Register;
implementation
{$R *.dfm}
procedure MonitorFiles;
begin
OTAEditPosnForm := TOTAEditPosnForm.Create(Nil);
OTAEditPosnForm.Show;
end;
procedure Register;
begin
MonitorFiles;
end;
procedure TOTAEditPosnForm.OpenInIDEEditor;
var
IServices : IOTAServices;
IActionServices : IOTAActionServices;
IModuleServices : IOTAModuleServices;
IEditorServices : IOTAEditorServices60;
IModule : IOTAModule;
i : Integer;
IEditor : IOTAEditor;
ISourceEditor : IOTASourceEditor;
IFormEditor : IOTAFormEditor;
IComponent : IOTAComponent;
INTAComp : INTAComponent;
AForm : TForm;
IEditView : IOTAEditView;
CursorPos : TOTAEditPos;
IEditWriter : IOTAEditWriter;
CharPos : TOTACharPos;
InsertPos : Longint;
FileName : String;
begin
IServices := BorlandIDEServices as IOTAServices;
Assert(Assigned(IServices), 'IOTAServices not available');
IServices.QueryInterface(IOTAACtionServices, IActionServices);
if IActionServices <> Nil then begin
IServices.QueryInterface(IOTAModuleServices, IModuleServices);
Assert(IModuleServices <> Nil);
// Close all files open in the IDE
IModuleServices.CloseAll;
if IActionServices.OpenFile(EditorFileName) then begin
// At this point, if the named file has an associated .DFM and
// we stopped here, the form designer would be in front of the
// code editor.
IModule := IModuleServices.Modules[0];
// IModule is the one holding our .Pas file and its .Dfm, if any
// So, iterate the IModule's editors until we find the one
// for the .Pas file and then call .Show on it. This will
// bring the code editor in front of the form editor.
ISourceEditor := Nil;
for i := 0 to IModule.ModuleFileCount - 1 do begin
IEditor := IModule.ModuleFileEditors[i];
FileName := IEditor.FileName;
Memo1.Lines.Add(Format('%d %s', [i, FileName]));
if CompareText(ExtractFileExt(IEditor.FileName), '.Pas') = 0 then begin
if ISourceEditor = Nil then begin
IEditor.QueryInterface(IOTASourceEditor, ISourceEditor);
IEditor.Show;
end
end
else begin
// Maybe the editor is a Form Editor. If it is
// close the form (the counterpart to the .Pas, that is}
IEditor.QueryInterface(IOTAFormEditor, IFormEditor);
if IFormEditor <> Nil then begin
IComponent := IFormEditor.GetRootComponent;
IComponent.QueryInterface(INTAComponent, INTAComp);
AForm := TForm(INTAComp.GetComponent);
//AForm.Close; < this does NOT close the on-screen form
// IActionServices.CloseFile(IEditor.FileName); <- neither does this
SendMessage(AForm.Handle, WM_Close, 0, 0); // But this does !
end;
end;
end;
// Next, place the editor caret where we want it ...
IServices.QueryInterface(IOTAEditorServices, IEditorServices);
Assert(IEditorServices <> Nil);
IEditView := IEditorServices.TopView;
Assert(IEditView <> Nil);
CursorPos.Line := edLine;
CursorPos.Col := edCol;
IEditView.SetCursorPos(CursorPos);
// and scroll the IEditView to the caret
IEditView.MoveViewToCursor;
// Finally, insert the comment, if any
if EditorInsert <> '' then begin
Assert(ISourceEditor <> Nil);
IEditView.ConvertPos(True, CursorPos, CharPos);
InsertPos := IEditView.CharPosToPos(CharPos);
IEditWriter := ISourceEditor.CreateUndoableWriter;
Assert(IEditWriter <> Nil, 'IEditWriter');
IEditWriter.CopyTo(InsertPos);
IEditWriter.Insert(PChar(EditorInsert));
IEditWriter := Nil;
end;
end;
end;
end;
procedure TOTAEditPosnForm.HandleCopyDataString(
CopyDataStruct: PCopyDataStruct);
begin
Memo1.Lines.Text := PChar(CopyDataStruct.lpData);
EditorFileName := Memo1.Lines.Values['FileName'];
edLine := StrToInt(Memo1.Lines.Values['Line']);
edCol := StrToInt(Memo1.Lines.Values['Col']);
EditorInsert := Trim(Memo1.Lines.Values['Comment']);
if EditorFileName <> '' then
OpenInIDEEditor;
end;
procedure TOTAEditPosnForm.WMCopyData(var Msg: TWMCopyData);
begin
HandleCopyDataString(Msg.CopyDataStruct);
msg.Result := Length(Memo1.Lines.Text);
end;
initialization
finalization
if Assigned(OTAEditPosnForm) then begin
OTAEditPosnForm.Close;
FreeAndNil(OTAEditPosnForm);
end;
end.
Code for sender:
procedure TSenderMainForm.btnSendClick(Sender: TObject);
begin
SendMemo;
end;
procedure TSenderMainForm.SendData(
CopyDataStruct: TCopyDataStruct);
var
HReceiver : THandle;
Res : integer;
begin
HReceiver := FindWindow(PChar('TOTAEditPosnForm'),PChar('OTAEditPosnForm'));
if HReceiver = 0 then begin
Caption := 'CopyData Receiver NOT found!';
end
else begin
Res := SendMessage(HReceiver, WM_COPYDATA, Integer(Handle), Integer(#CopyDataStruct));
if Res > 0 then
Caption := Format('Received %d characters', [Res]);
end;
end;
procedure TSenderMainForm.SendMemo;
var
MS : TMemoryStream;
CopyDataStruct : TCopyDataStruct;
S : String;
begin
MS := TMemoryStream.Create;
try
S := Memo1.Lines.Text + #0;
MS.Write(S[1], Length(S));
CopyDataStruct.dwData := 1;
CopyDataStruct.cbData := MS.Size;
CopyDataStruct.lpData := MS.Memory;
SendData(CopyDataStruct);
finally
MS.Free;
end;
end;
I am trying to extract URLs from Google search results. I use Indy IdHTTP to get HTML results from Google, and I use Achmad Z's code for getting the link hrefs from the page. How can I get the real link target for each URL instead of the one that goes through Google's redirector?
I tried that but I get an "Operand no applicable" error in this part of the code:
function ToUTF8Encode(str: string): string;
var
b: Byte;
begin
for b in BytesOf(UTF8Encode(str)) do
begin
Result := Format('%s%s%.2x', [Result, '%', b]);
end;
end;
I use Delphi 7 with Indy 9.00.10. Maybe indy update will help ?
If I get it right you are trying to fetch the Google search results using TIdHTTP.Get method. If so, thenyou should definitely focus on some Google Search API implementation because
it's impossible to fetch the results this way because you don't have any access to the document inside the iframe in which the search results are, so you won't get any search results by using HTTP GET in this case (or at least I haven't heard about the request which can do that)
it's against Google policies and you should use proper Google Search API instead, for instance Google SOAP Search API, there are available also several types of Google Search API's for various purposes
You can find e.g. here the Delphi wrapper with the demo code for Google Search API. I've tested it with Delphi 2009 on Windows 7/64 and it works fine for me.
In the previous post here I've tried to explain why you should use Google Search API, in this one I'll try to provide you an example with a hope it will work in your Delphi 7.
You need to have the SuperObject (JSON parser for Delphi), I've used this version (latest at this time). Then you need Indy; the best would be to upgrade to the latest version if possible. I've used the one shipped with Delphi 2009, but I think the TIdHTTP.Get method is so important that it must work fine also in your 9.00.10 version.
Now you need a list box and a button on your form, the following piece of code and a bit of luck (for compatibility :)
The URL request building you can see for instance in the DxGoogleSearchApi.pas mentioned before but the best is to follow the Google Web Search API reference. In DxGoogleSearchApi.pas you can take the inspiration e.g. how to fetch several pages.
So take this as an inspiration
uses
IdHTTP, IdURI, SuperObject;
const
GSA_Version = '1.0';
GSA_BaseURL = 'http://ajax.googleapis.com/ajax/services/search/';
procedure TForm1.GoogleSearch(const Text: string);
var
I: Integer;
RequestURL: string;
HTTPObject: TIdHTTP;
HTTPStream: TMemoryStream;
JSONResult: ISuperObject;
JSONResponse: ISuperObject;
begin
RequestURL := TIdURI.URLEncode(GSA_BaseURL + 'web?v=' + GSA_Version + '&q=' + Text);
HTTPObject := TIdHTTP.Create(nil);
HTTPStream := TMemoryStream.Create;
try
HTTPObject.Get(RequestURL, HTTPStream);
JSONResponse := TSuperObject.ParseStream(HTTPStream, True);
if JSONResponse.I['responseStatus'] = 200 then
begin
ListBox1.Items.Add('Search time: ' + JSONResponse.S['responseData.cursor.searchResultTime']);
ListBox1.Items.Add('Fetched count: ' + IntToStr(JSONResponse['responseData.results'].AsArray.Length));
ListBox1.Items.Add('Total count: ' + JSONResponse.S['responseData.cursor.resultCount']);
ListBox1.Items.Add('');
for I := 0 to JSONResponse['responseData.results'].AsArray.Length - 1 do
begin
JSONResult := JSONResponse['responseData.results'].AsArray[I];
ListBox1.Items.Add(JSONResult.S['unescapedUrl']);
end;
end;
finally
HTTPObject.Free;
HTTPStream.Free;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
GoogleSearch('Delphi');
end;
Answer to my question , maybe it can help someone:
Fetching web page :
memo1.Lines.Text := idhttp1.Get('http://ajax.googleapis.com/aja...tart=1&rsz=large&q=max');
extracting URL's :
function ExtractText(const Str, Delim1, Delim2: string; PosStart: integer; var PosEnd: integer): string;
var
pos1, pos2: integer;
begin
Result := '';
pos1 := PosEx(Delim1, Str, PosStart);
if pos1 > 0 then
begin
pos2 := PosEx(Delim2, Str, pos1 + Length(Delim1));
if pos2 > 0 then
begin
PosEnd := pos2 + Length(Delim2);
Result := Copy(Str, pos1 + Length(Delim1), pos2 - (pos1 + Length(Delim1)));
end;
end;
end;
And on Button1 just put :
procedure TForm1.Button1Click(Sender: TObject);
var Pos: integer;
sText: string;
begin
sText := ExtractText(Memo1.Lines.Text, '"url":"', '","visibleUrl"', 1, Pos);
while sText <> '' do
begin
Memo2.Lines.Add(sText);
sText := ExtractText(Memo1.Lines.Text, '"url":"', '","visibleUrl"', Pos, Pos);
end;
end;
www.delphi.about.com has nice documentation on string manipulation , Zarko Gajic does great job on that site :)
NOTE: if google changes it's source this will be useless.
I have a Delphi 2010 app which shows/hides the desktop icons under XP fine. However under my Window 7 test environment (happens to be 64 bit) the icons don't disappear.
Here is the critical code I am using (for the hide):
ShowWindow(FindWindow(nil, 'Program Manager'), SW_HIDE );
I have found I can set the registry:
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
"HideIcons"=dword:00000001
And that works fine if I restart windows (or kill explorer and restart it), however is there a way to get the old code to work and/or tell the desktop to reload using the new registry information without such radical methods.
Thank in advance.
Use SHGetSetSettings function. You're interested in fHideIcons field and corresponding SSF_HIDEICONS flag.
Alternatively, you can use corresponding group policy.
Ok, here is the revised hackish method (sorry Alexander!):
var
DeskHandle : HWND;
...
///////////////////////////////////////////////////////////////////////
// Callback function for EnumWindows
///////////////////////////////////////////////////////////////////////
function MyGetWindow (Handle: HWND; NotUsed: longint): bool; stdcall;
var
hChild : HWND;
begin
if handle <> 0 then
begin
hChild := FindWindowEx(handle, 0, 'SHELLDLL_DefView' ,nil);
if hChild <> 0 then
begin
hChild := FindWindowEx(hChild, 0, 'SysListView32' ,nil);
if hChild <> 0 then
begin
DeskHandle := hChild;
end;
end;
end;
result := TRUE;
end;
procedure ShowDesktopIcons(const Show : boolean) ;
begin
DeskHandle := 0;
EnumWindows(#MyGetWindow, 0);
if DeskHandle <> 0 then
begin
if Show then
begin
ShowWindow(DeskHandle, SW_SHOW );
end
else
begin
ShowWindow(DeskHandle, SW_HIDE );
end;
end;
end;
The issue arises because parent/child relationship between "Progman" and SysListView32 has changed from XP to Vista/Win7 (precisely why you shouldn't use a hack ;-). In addition, applying a theme with multiple pictures under Win7 (my test environment) changes this relationship even further. Therefore the new routine looks through all windows until it finds one with a "SHELLDLL_DefView" and "SysListView32" child set under one. It then returns the handle of SysListView32 in the global variable DeskHandle. Not elegant, not sure to work in future code, but works today.
If anyone can get a SHGetSetSettings version to work, that is definitely the correct way to go, not this junk.
Use 'ProgMan' instead of 'Program Manager'.
Works in Win 7 32 bits (don't have my 64 bits available here).
procedure ShowDesktopIcons(const Visible: Boolean);
var
h: THandle;
begin
h := FindWindow('ProgMan', nil);
if h = 0 then
RaiseLastOSError;
if Visible then
ShowWindow(h, SW_SHOW)
else
ShowWindow(h, SW_HIDE);
end;
procedure TForm1.btnHideClick(Sender: TObject);
begin
ShowDesktopIcons(False);
end;
procedure TForm1.btnShowClick(Sender: TObject);
begin
ShowDesktopIcons(True);
end;