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.
Thursday, September 20, 2007
Developing Hybrid Gadgets for Google Desktop
Labels:
ActiveX,
ATL,
C++,
delphi,
Google Desktop,
jscript
at
18:01
6
comments
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;
Labels:
ActiveX,
Ajax,
delphi
at
17:24
1 comments
Tuesday, August 21, 2007
JScript arrays and COM objects, part 3
I have promised in my previous post that I will present also how to deal with JScript arrays in C++ code with ATL. Below, there is a code of a function, I have come up with, in C++ that gets the JScript array of integers and calculates the sum:
#include <string>
#include <sstream>
#define _C(oleop) hr = oleop; \
if (!SUCCEEDED(hr)) \
return hr;
STDMETHODIMP CHelloWorld::JSArrSum(VARIANT js_arr, LONG* Sum)
{
HRESULT hr;
/* checking if argument is an object */
if (!(js_arr.vt & VT_DISPATCH))
return E_INVALIDARG;
/* retrieving IDispatch */
IDispatch *disp = js_arr.pdispVal;
if (js_arr.vt & VT_BYREF)
disp = *(js_arr.ppdispVal);
/* getting array's length */
DISPPARAMS params;
FillMemory(¶ms, sizeof(DISPPARAMS), 0);
VARIANT res;
DISPID dl;
LPOLESTR ln = L"length";
_C(disp->GetIDsOfNames(IID_NULL, &ln, 1, LOCALE_USER_DEFAULT, &dl));
_C(disp->Invoke(dl, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
¶ms, &res, NULL, NULL));
VARIANT len1;
VariantInit(&len1);
_C(VariantChangeType(&len1, &res, 0, VT_I4));
LONG len = len1.lVal;
/* summing elements */
int total = 0;
for (int i = 0; i < len; i++)
{
std::stringstream ss;
ss << ind =" CComBSTR(ss.str().c_str());">GetIDsOfNames(IID_NULL, &ind, 1, LOCALE_USER_DEFAULT, &id));
_C(disp->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, ¶ms, &res, NULL, NULL));
VARIANT val1;
VariantInit(&val1);
_C(VariantChangeType(&val1, &res, 0, VT_I4));
total += val1.lVal;
}
*Sum = total;
return S_OK;
}
What it does is simply the following:
- It is checked if an argument is some object (hopefully, a JScript array)
- IDispatch reference of an array is retrieved from the variant.
- The property length is obtained from the array's object as it is for any automation object. We receive some variant value, so we need to convert it to integer.
- For each element of an array its DISPID is queried and its value received, converted to integer, and summed up.
- It returns the sum of array's values.
var arr = new Array();
arr[0] = 10;
arr[1] = 15;
arr[2] = 2;
var obj = new ActiveXObject("ProgID.OfClass");
alert(obj.JSArrSum(arr));
Blog Archive
-
►
2007
(9)
- ► September 2007 (1)
- ► August 2007 (8)