Saturday, December 03, 2011

Blog discontinued

As you may have noticed this blog has had no new post for a long time.
I started it couple of years ago while being a student.
These couple of posts here reflected my knowledge, what I was doing and my state of personal growth at that moment.

Recently, the idea crossed my mind that I can blog something again, but I decided there is to much distance between then and now. Therefore, I am closing this blog
and opening the new one.

Thursday, September 20, 2007

Developing Hybrid Gadgets for Google Desktop

If you are interested in developing gadgets for Google Desktop you may have heard of so-called hybrid gadget. It is a way to enhance your gadget with functionality that cannot be achieved in pure script and GD's API. Namely, you may write the part of the functionality, natively, as an ActiveX object and use it from the script without a need of having the typelib registered, etc.

If you would like to learn about this technique, I encourage you to read my article I have written for Google Developer Knowledge Base which is called Going Beyond Script: Developing Hybrid Gadgets. I hope you will enjoy it and that the article will prove useful. Feel free to leave here comments regarding the article.

Tuesday, August 28, 2007

Ajax not only for Web: Using XmlHTTPRequest in the standalone application.

If the term AJAX is familiar to you, for sure, you know that the heart of this technology is the XMLHttpRequest object. It may be used in, practically, all the modern browsers that support javascript. Although you would instantiate it in Firefox and new versions of Internet Explorer with the instruction:

var d = new XMLHttpRequest();

originally in Internet Explorer it was not a built-in JavaScript object.
In fact, the command to get XMLHttpRequest was:

var d = new ActiveXObject("MSXML2.XMLHTTP");

what reveals the fact that it was realized as an ActiveX object. Indeed, it was implemented in library called Microsoft XML which exposed COM object MSXML2.XMLHTTP. Its type library is present in msxml3.dll file in windows system folder.
So, if it is nothing more than normal ActiveX class, why not to use it in standalone application, for instance written in Delphi, to transfer data between the application and some web server.
In ActiveX-enabled languages that offer dynamic binding (like pascal) it is not more difficult that javascript code embedded in HTML. Here comes an example in Delphi, which fills a memo control with the code of the website http://www.somewhere.com:

procedure TForm1.Button1Click(Sender: TObject);
var
d: OleVariant;
begin
d := CreateOleObject('MSXML2.XMLHttp');
d.open('get', 'http://www.somewhere.com', false, EmptyParam, EmptyParam);
d.send('');
if (d.readyState = 4) and (d.status = 200) then
Memo1.Lines.Text := d.responseText;
end;

Simple, isn't it?
If you prefer static binding (for example, to take advantage of code completion) you may import ActiveX type library Microsoft XML 3.0. Then, your code would look like:

uses msxml2_tlb;

procedure TForm1.Button1Click(Sender: TObject);
var
d: IXMLHTTPRequest;
begin
d := CoXMLHTTP40.Create;
d.open('get', 'http://www.somewhere.com', false, EmptyParam, EmptyParam);
d.send('');
if (d.readyState = 4) and (d.status = 200) then
Memo1.Lines.Text := d.responseText;
end;

You may now be thinking "Wait!, but A in Ajax stands for asynchronous, and here your are blocking program, using XMLHttpRequest synchronously". Yes, we may do it also asynchronously, but one problem arouses here - handling onreadystatechange event. In reality, it is not an event as understood in ActiveX. You may know that, in fact, JScript is incapable of sinking ActiveX events. Thus, Microsoft architects made onreadystatechange to be a property you may assign JScript function to. Therefore, what we have to assign must be, at least, the imitation of JScript routine. As you may have realized, everything in JScript is an object - internally represented by a pointer to IDispatch interface. So are functions. To execute the function you call Invoke with DISPID equal to 0 on its IDispatch.
In Delphi, therefore, JScript's function may be imitated by an object of the class derived from TInterfacedObject and implementing IDispatch interface (providing implementation for Invoke method is enough).

The full example of asynchronous HTTP request follows here:

uses comobj, msxml2_tlb;

type
TAjaxEvenFunc = procedure (d: Variant) of object;
TAjaxEvent = class(TInterfacedObject, IDispatch)
private
d: Variant;
func: TAjaxEvenFunc;
public
constructor Create(const d: Variant; const func: TAjaxEvenFunc);
function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
Flags: Word; var Params; VarResult: Pointer; ExcepInfo: Pointer;
ArgErr: Pointer): HRESULT; stdcall;
function GetIDsOfNames(const IID: TGUID; Names: Pointer; NameCount: Integer;
LocaleID: Integer; DispIDs: Pointer): HRESULT; stdcall;
function GetTypeInfo(Index: Integer; LocaleID: Integer;
out TypeInfo): HRESULT; stdcall;
function GetTypeInfoCount(out Count: Integer): HRESULT; stdcall;
destructor Destroy; override;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
d: IXMLHTTPRequest;
begin
d := CreateOleObject('MSXML2.XMLHttp.3.0') as IXMLHTTPRequest;
d.open('get', 'http://www.onet.pl', true, EmptyParam, EmptyParam);
d.onreadystatechange := TAjaxEvent.Create(d, EventHandl) as IDispatch;
d.send('');
d := nil;
end;

procedure TForm1.EventHandl(d: Variant);
begin
if (d.readyState = 4) and (d.status = 200) then
Memo1.Lines.Text := d.responseText;
end;

{ TAjaxEvent }

constructor TAjaxEvent.Create(const d: Variant;
const func: TAjaxEvenFunc);
begin
inherited Create;
self.d := d;
self.func := func;
end;

destructor TAjaxEvent.Destroy;
begin
func := nil;
d := Null;
inherited;
end;

function TAjaxEvent.GetIDsOfNames(const IID: TGUID; Names: Pointer; NameCount,
LocaleID: Integer; DispIDs: Pointer): HRESULT;
begin
Result := E_NOTIMPL;
end;

function TAjaxEvent.GetTypeInfo(Index, LocaleID: Integer;
out TypeInfo): HRESULT;
begin
Result := E_NOTIMPL;
end;

function TAjaxEvent.GetTypeInfoCount(out Count: Integer): HRESULT;
begin
Result := E_NOTIMPL;
end;

function TAjaxEvent.Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HRESULT;
begin
if DispID <> 0 then
begin
Result := E_INVALIDARG;
exit;
end;
if Assigned(func) and not VarIsNull(d) then
func(d);
end;

There were visits to this blog since 20.08.2007.