Sunday, 18 September 2011

Get Chrome active tab URL using Delphi

After developing my first Chrome extension to retrieve all URLs from Google chrome, I have been trying to reproduce the same behaviour using Delphi, but it was impossible. Chrome is still adding some new features and extending their extensions for developers. For example, others navigators such as Internet Explorer and Firefox they have a DDE extension to retrieve some of the properties but not available for Chrome.
The best way I found was using FindWindow and SendMessage windows functions to get the text from the tab and get tue URL. It's not a win solution but will help you to retrieve the URL of the active page without copy-paste action, just by switching to the next tab and retrieving data from the tool.

The basic code to achieve this is the following one:

function GetChromeActiveTabURL(Wnd: HWnd; Param: LParam): Bool; stdcall;
var
  urls: TStrings;
  hWndMainWindow, hWndTab: HWND;
  Buffer : array[0..255] of Char;
  res : boolean;
begin
  res := true;
  urls := TStrings(Param);
  SendMessage(Wnd, WM_GETTEXT, Length(Buffer), integer(@Buffer[0]));
  hWndMainWindow := FindWindow('Chrome_WidgetWin_0', Buffer);
  application.ProcessMessages;
  if hWndMainWindow <> 0 then
  begin
    hWndTab := FindWindowEx(hWndMainWindow, 0, 'Chrome_AutocompleteEditView', nil);
    if hWndTab <> 0 then
    begin
      SendMessage(hWndTab, WM_GETTEXT, Length(Buffer), integer(@Buffer));
      urls.Add(Buffer);
      res := false;
    end;
  end;
  Result := res;
end;

procedure TUrlChrome.GetUrl(Sender: TObject);
var
  Urls: TStringList;
begin
  Urls := TStringList.Create;
  try
    EnumWindows(@GetChromeActiveTabURL, LParam(Urls));
    Memo1.Lines.AddStrings(Urls);
  finally
    FreeAndNil(Urls);
  end;
end;

To get the class name window, we can use Winspector to inspect chrome and get the names for the main window and for the tabs:

Chrome_WidgetWin_0:

Chrome_AutocompleteEditView:

And you can get the tool from here: ThundaxChromeURL.


I'm not proud of this solution, but at least it will work for current versions of Chrome. I also recommend to give a go to my chrome extension (It's not been published into Chrome market, it turns out that you have to pay a $5.00 fee), that is much better than the tool as it's able to get all urls.

Related links:

Saturday, 17 September 2011

My first Google Chrome extension (Get all URLs from Google Chrome tabs)

As a good internet researcher I always have hundreds of tabs opened in my Chrome navigator and sometimes I find a bit of chore to copy and paste all the URL that I have done a research on and that any other day I would be using again. So, that's my extension about, to display in a pop up window all the url's from all tabs to then copy them without problems (the correct name would be [search purposes] -> Get all URLs from Google Chrome tabs).
I have been struggling to write a little tool using Delphi, but it only works with Internet explorer and Mozilla firefox, so I thought it could be great to give chrome extensions a try. 
It is quite easy to develop and debug using all the development tools available from the navigator itself. As in the following example, I have opened 3 new tabs with the www.google.es URL, and if we click the extension button, will get a pop up list with the URLs from all tabs:

The source code is as follows:

manifest.json:
{
  "name": "Get All URL's Extension by Jordi Corbilla",
  "version": "1.0",
  "description": "Extension to display all the URL's from all TABs.",
  "browser_action": {
    "default_icon": "icon.ico",
    "popup": "urlList.html"
  },
  "permissions": [
    "tabs"
  ],
  "icons" : {

    "48" : "icon.ico",


    "128" : "icon.ico"


  }
}

urlList.html:
<!DOCTYPE>
<!--
 * Copyright (c) 2011 Jordi Corbilla. All rights reserved.  
-->
<html>
  <head>
    <script>
      chrome.tabs.getAllInWindow(null, function(tabs) {
        tabs.forEach(function(tab){
          myFunction(tab.url);	
        });
      });

      function myFunction(tablink) {
        console.log(tablink);
        var oNewNode = document.createElement("LI");
        urlList.appendChild(oNewNode);
        oNewNode.innerText=tablink;  
      }
</script>
</head>
  <body>
    <div>URL List</div>
    <ul ID = urlList>
    </ul>
  </body>
</html>

You can download the extension from here: URLJCExtension.zip. To install, you only need to unzip the file and then go to chrome://extensions/, expand developer mode and load my extension (from the unzipped folder):

As the extension uses the console log method, you can see all the links in the console (just for debug purposes, but it's really good to have a go on it).

Just right click on the extension icon and then "Inspect Pop-up" and you'll see the following window with the current list of urls:



Enjoy the extension!.

Related links:

Friday, 26 August 2011

Fluent Interfaces example using Delphi part I

I was introduced to Fluent interfaces when I was developing with Java using Dependency Injection and somebody told me that it could be really interesting if I post an example using Delphi and chaining method, and here I am!. I have developed a simple example that uses chaining methods to populate a THouse object with TDoors and TWindows objects with the hope it will make it easy to understand the concept. There are several examples on the net, but I couldn't find any interesting enough. So this simple example will try to introduce you to "how to develop fluent interfaces using method chaining" with the aim of writing more readable code. The overview of the architecture is the following one, using UML notation:


The Fluent Interface unit example is as follows (uFI.pas) using generics and interfaces:

// ***********************************************
// @author  jordi corbilla
// @comment Fluent interface composition example
//
// ***********************************************

unit uFI;

interface

uses
    Graphics, Contnrs, Generics.Collections, Classes;

type
    TWindow = class;

    IWindow = interface
        function SetColor(color: TColor): TWindow;
        function ToString(): string;
    end;

    TWindow = class(TInterfacedObject, IWindow)
    private
        FColor: TColor;
    public
        function SetColor(color: TColor): TWindow;
        function ToString(): string; override;
        class function New: TWindow;
    end;

    TDoor = class;

    IDoor = interface
        function SetColor(color: TColor): TDoor;
        function ToString(): string;
    end;

    TDoor = class(TInterfacedObject, IDoor)
    private
        FColor: TColor;
    public
        function SetColor(color: TColor): TDoor;
        function ToString(): string; override;
        class function New: TDoor;

    end;

    IHouse = interface
        function AddWindow(window: TWindow): IHouse;
        function AddDoor(door: TDoor): IHouse;
        function ToString(): String;
    end;

    THouseItemsList<T> = class(TObjectList)
        function ToString(): string; override;
    end;

    TDoorList = class(THouseItemsList<IDoor>)
        function ToString(): string; override;
    public

    end;

    TWindowList = class(THouseItemsList<IWindow>)
        function ToString(): string; override;
    end;

    THouse = class(TInterfacedObject, IHouse)
    private
        FDoorList: TDoorList;
        FWindowList: TWindowList;
    protected
        function AddWindow(window: TWindow): IHouse;
        function AddDoor(door: TDoor): IHouse;
    public
        property WindowList: TWindowList read FWindowList;
        property DoorList: TDoorList read FDoorList;
        class function New: IHouse;
        function ToString(): String; override;
        constructor Create();
        destructor Destroy(); override;
    end;

implementation

uses
    SysUtils;

{ THouse }

function THouse.AddDoor(door: TDoor): IHouse;
begin
    Self.FDoorList.Add(door);
    result := Self;
end;

function THouse.AddWindow(window: TWindow): IHouse;
begin
    Self.FWindowList.Add(window);
    result := Self;
end;

constructor THouse.Create;
begin
    FDoorList := TDoorList.Create;
    FWindowList := TWindowList.Create;
end;

destructor THouse.Destroy;
begin
    FreeAndNil(FDoorList);
    FreeAndNil(FWindowList);
    inherited;
end;

class function THouse.New: IHouse;
begin
    result := Create;
end;

function THouse.ToString: String;
var
    description: TStringList;
begin
    description := TStringList.Create;
    try
        description.Add(Self.FDoorList.ToString);
        description.Add(Self.FWindowList.ToString);
    finally
        result := description.Text;
        description.Free;
    end;
end;

{ TWindow }

class function TWindow.New: TWindow;
begin
    result := Create;
end;

function TWindow.SetColor(color: TColor): TWindow;
begin
    Self.FColor := color;
    result := Self;
end;

function TWindow.ToString: string;
begin
    result := 'Window color ' + ColorToString(FColor) + sLineBreak;
end;

{ TDoor }

class function TDoor.New: TDoor;
begin
    result := Create;
end;

function TDoor.SetColor(color: TColor): TDoor;
begin
    Self.FColor := color;
    result := Self;
end;

function TDoor.ToString: string;
begin
    result := 'Door color ' + ColorToString(FColor) + sLineBreak;
end;

{ THouseItemsList }

function THouseItemsList<T>.ToString: string;
var
    i: Integer;
    description: String;
begin
    for i := 0 to Self.count - 1 do
        description := description + ' ' + Self[i].ToString;
    result := description;
end;

{ TDoorList }

function TDoorList.ToString: string;
var
    description: TStringList;
begin
    description := TStringList.Create;
    try
        description.Add('Number of doors: ' + inttostr(Self.count));
        description.Add('Descriptions: ');
        description.Add( inherited ToString);
    finally
        result := description.Text;
        FreeAndNil(description);
    end;
end;

{ TWindowList }

function TWindowList.ToString: string;
var
    description: TStringList;
begin
    description := TStringList.Create;
    try
        description.Add('Number of Windows: ' + inttostr(Self.count));
        description.Add('Descriptions: ');
        description.Add( inherited ToString);
    finally
        result := description.Text;
        FreeAndNil(description);
    end;
end;

end.

Now it comes when we can use the object using FI notation in a more readable way:

var
    House: IHouse;
begin
    House := THouse.New.AddWindow(TWindow.New.SetColor(clFuchsia)).AddDoor(TDoor.New.SetColor(clWhite))
        .AddWindow(TWindow.New.SetColor(clRed)).AddDoor(TDoor.New.SetColor(clGreen));
    Memo1.Lines.Add(House.ToString);
    House := nil;

    House := THouse.New;
    House.AddWindow(TWindow.New.SetColor(clRed)).AddWindow(TWindow.New.SetColor(clBlue)).AddWindow(TWindow.New.SetColor(clGreen));
    House.AddDoor(TDoor.New.SetColor(clRed)).AddDoor(TDoor.New.SetColor(clBlue)).AddDoor(TDoor.New.SetColor(clGreen));
    Memo1.Lines.Add(House.ToString);
    House := nil;

Notice that now, we can chain our objects, composing the structure of the House by using the AddWindow and AddDoor method. To display the result I'm using the ToString method that will do the job for my purpose.

And the result of the previous execution:


Number of doors: 2
Descriptions: 
 Door color clWhite
 Door color clGreen


Number of Windows: 2
Descriptions: 
 Window color clFuchsia
 Window color clRed


Number of doors: 3
Descriptions: 
 Door color clRed
 Door color clBlue
 Door color clGreen


Number of Windows: 3
Descriptions: 
 Window color clRed
 Window color clBlue
 Window color clGreen


Just play with it and you'll experience the powerfulness of this method. I hope you like it.

I'm looking forward to your comments.
Jordi

Monday, 22 August 2011

Building my own Delphi Physics Engine part IX

I'm quite familiar with GDI, the graphics provided under Microsoft and which is widely used in Windows applications. TDPE is now ready to use Direct2D as now it's fully supported by Delphi 2010 and XE. According to MSDN, Direct2D is: a hardware-accelerated, immediate-mode, 2-D graphics API that provides high performance and high quality rendering for 2-D geometry, bitmaps, and text. The Direct2D API is designed to interoperate well with GDI, GDI+, and Direct3D.
As I'm testing this under Windows Vista, I've had to upgrade my windows version to Service Pack 2 and then I've installed the following update (KB971512 - The Windows Graphics, Imaging, and XPS Library contain the latest advancements in modern graphics technologies for gaming, multimedia, imaging and printing applications.). Direct2D is already installed in Windows 7.

We can use the same methods from TCanvas for our TDirect2DCanvas as they derive from the same ancestor TCustomCanvas. But you need to check the documentation for differences in the way they work.

A simple way to use Direct2D is as follows:

uses
    Direct2D, D2D1;

procedure Paint();
begin
    if TDirect2DCanvas.Supported then
    begin
        d2dCanvas := TDirect2DCanvas.Create(Canvas, ClientRect);
        try
            d2dCanvas.RenderTarget.beginDraw;
            d2dCanvas.RenderTarget.Clear(D2D1ColorF(clBlack));
            d2dCanvas.RenderTarget.SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
            // drawing goes here
            Paint(d2dCanvas);
            d2dCanvas.RenderTarget.EndDraw;
        finally
            FreeAndNil(d2dCanvas);
        end;
    end;
end;

Here is the result of the Physics Engine using a Direct2D Render and a GDI Render:





You will see the difference when switching from GDI to Direct2D as the performance is quite different. When it comes to Direct2D, my computer is getting quite slower as my graphic card is not powerful at all and we can see that it takes a while to render the image.


GDI uses Pixel graphics but Direct2D can supports vector graphics as well, in which mathematical formulas are used to draw the lines and curves. Vector graphics provides high quality rendering independent of resolution of the device, while the pixelated graphics has dependency with resolution which may results in choppy graphics.

Most of the GDI APIs are not using anti-aliasing and transparency. Ofcrouse there are functions to do so but always there’s programming cost for taking advantage of these features. Also if we apply transparency and anti-aliasing, the computations are done using CPU. Direct2D can take advantage of graphics hardware and delegate the computationally intensive tasks to GPU


Get the latest version here: ThundaxBallDemo v1.584.
Interaction:
'd' will drop a box with a random colour and a constant angular velocity.
'f' will drop a circle with a random colour and a constant angular velocity.
'mouse interaction' mouse is able to grab items.
'q' Enable/Disable GDI or Direct2D rendering.

Note: You need to have installed Direct2D to run the app using Direct2D, otherwise GDI will be used.

Related links:

Wednesday, 10 August 2011

Building my own Delphi Physics Engine part VIII

TDPE is almost ready and it will not take long to release the first stable library!. I am eager to continue working on the project trying to sort out different physic scenarios  to make my dynamic engine even more realistic. Do not hesitate to give it a try as you will find the experience quite interesting. I am still working on the n-edge object and the cutting tool and trying to refactor all the code to cope with a layer architecture. Using this concept, I want to structure my system in a way that every component works using a certain level of abstraction. As you see in the next figure, every object is allocated in the screen while there is another layer which is responsible for the collision detection and another one for the forces interaction. You will notice in the video that there are still little issues to tackle regarding the object interaction as sometimes we can experience overlapping.


In the figure above, you can see that now the items are not rigid and they interact with each other as they were real items. Notice that the square item will go through the round shape of the circle.



Enjoy the video!.

Get the latest executable here: ThundaxBallDemo v1.504.
Interaction:
'd' will drop a box with a random color and a constant angular velocity
'f' will drop a circle with a random color and a constant angular velocity
'mouse interaction' mouse is able to grab items

Related links: