Thursday, September 25, 2008

Calling javascript from ActiveX component.

Recently I was trying to call javascript functions in a web page from an embeded activex component i'm working on (The same way a flex developer do using ExternalInterface).

Problems facing this kind of action:


The problem in MFC is that life is not easy like Flex in this specific point. You have to deal with alot of COM interfaces to get what you want. So my problem was as follows.

  1. I should get a reference to the window that the ActiveX control is embeded in (in my case, it will be an IE tab).

  2. Try to get an interface from this window to an html container to be able to access html and javascript.

  3. find the javascript function you want to call.

  4. formulate the parameters in the way that suits the Interface.

    1. Starting a normal ActiveX control application using the app wizzard, leaving all the default settings.

    2. in the ActiveXCtrl class added a CComPtr which i will be using to access the javascript functions inside the web page.

    3. Added a new method I called it FindMainWindow() and called it in the OnDraw()method.

    4. the code of FindMainWindow()Is as follows.
      void FindMainWindow()
      {
      LPOLECLIENTSITE lpClientSite = NULL;
      lpClientSite = GetClientSite();
      CComPtr<IServiceProvider> serviceProvider(0);
      CComPtr<IWebBrowserApp> webBrowserApp(0);
      CComPtr<IWebBrowser2> webBrowser(0);
      CComPtr<IDispatch> dispatch(0);
      if(SUCCEEDED(lpClientSite->QueryInterface(IID_IServiceProvider,(void**)&serviceProvider))) {
      }
      if(SUCCEEDED(serviceProvider->QueryService(IID_IWebBrowserApp,IID_IWebBrowserApp,(void**)&webBrowserApp)))
      { }
      if(SUCCEEDED(webBrowserApp->QueryInterface(IID_IWebBrowser2,(void**)&webBrowser)))
      {
      webBrowser->get_Document(&dispatch);
      }
      if(SUCCEEDED(dispatch->QueryInterface(IID_IHTMLDocument2,(void**)&htmlDoc)))
      {
      LOG(_T("Found Html Document:"));
      }
      }

      As you can see here, I needed to get first an IServiceProvider interface from theIOLEClientSite i got by calling GetClientSite().
      The following link in the msdn documentation says in the remarks section that The IWebBrowser2 interface derives from IDispatch indirectly. IWebBrowser2 derives from IWebBrowserApp, which in turn derives from IWebBrowser, which finally derives from IDispatch. So i had to get an IWebBrowserApp interface then IWebBrowser2. Finally getting an IDispatch interface to get the IHTMLDocumtne2 from it.

    5. Here we start to call a javascript methods within the IHTMLDocument2 interface we have got earlier. we call get_script(IDispatch*) to get the script object. The following code demonstrate how to get the id of a given javascript function name, formulating the parameters and invoking the function.
      CComPtr spScript;
      if(!GetJScript(spScript))
      {
      return false;
      }
      CComBSTR bstrMember(function);
      DISPID dispid = NULL;
      HRESULT hr = spScript->GetIDsOfNames(IID_NULL,&bstrMember,1,LOCALE_SYSTEM_DEFAULT,&dispid);

      if(FAILED(hr))
      {
      return false;
      }

      CStringArray paramArray;
      const int arraySize = paramArray.GetSize();
      DISPPARAMS dispparams;
      memset(&dispparams, 0, sizeof dispparams);
      dispparams.cArgs = arraySize;
      dispparams.rgvarg = new VARIANT[dispparams.cArgs];

      for( int i = 0; i < arraySize; i++)
      {
      CComBSTR bstr = paramArray.GetAt(arraySize - 1 - i); // back reading
      bstr.CopyTo(&dispparams.rgvarg[i].bstrVal);
      dispparams.rgvarg[i].vt = VT_BSTR;
      }
      dispparams.cNamedArgs = 0;
      EXCEPINFO excepInfo;
      memset(&excepInfo, 0, sizeof excepInfo);
      CComVariant vaResult;
      UINT nArgErr = (UINT)-1; // initialize to invalid arg

      hr = spScript->Invoke(dispid,IID_NULL,0,DISPATCH_METHOD,&dispparams,&vaResult,&excepInfo,&nArgErr);
      if(FAILED(hr))
      {
      return false;
      }
      *pVarResult = vaResult;
      return true;




  5. Finally call the javascript and cross fingers!

    Solution:


    Here is what i succeeded in after 5 hours of searching and reading and debugging code.

    I have simplified this example as it was a testing to show that javascript is called successfully.
    The detailed example on calling javascript from IHTMLDocument2 can be found in this link
Wednesday, June 4, 2008

Introducing Goosh (Google Shell)

Have you ever wondered, when can i search the web using command line?
Are you a command line geek?
Would you like to get the power of command line and the essence of web.

I felt all that when i opened goosh.org.
When you open the site, you will find a simple white screen with some welcome message like what you see if you have been using a Nix shell before.

just type help and press enter to see what you can do with this shell.

One of the amazing things i have tried is the translate command.
Here is a screenshot of the result for translating "I'm amr and i like to talk" from english to arabic


Totally amazing? Just watch out for the other abilities as well. and share your feedbacks about it and if there is any other amazing commands you did on it.

I will try to read the javascript of the page and share hints.

Happy command line searching
Friday, May 30, 2008

Firefox 3 to score a Guinness World Record

An amazing idea is to aim at scoring a world record for the most downloaded software in 24 hours. Firefox team is spreading its popularity by this announcement as most of Firefox users will talk about it, more users will be interested in trying Firefox if they were not using it and Firefox will gain more popularity.

I have tried Firefox beta 1 and it was very inspiring. But as a developer, I needed more variety of add ons and i couldn't find some addons support for it like firebug and web developer. So i switched to Firefox 2 and waiting for the release of the amazing Firefox 3.

I hope they break the record
Saturday, May 24, 2008

A word about eventmachine gem for Rails

I was working recently in a project that required special purpose server to be implemented from scratch. so i got down to business and started coding. But instead of reinventing the wheel, I started the implementation using the event machine gem for Ruby On Rails . After finishing the coding and basic testing, I got an unexpected problem. The server Always crash!!

First I tried to look back into my code, may be the problem is there. I have tried to repeat a certain request several times and log the server results. Some requests are served and some are not, then the server just stop responding. When I shut it down, It seems to be buffering the rest of the requests. So what happens is that it sends the rest of the requests and then terminate.

The solution to my problem was very simple, Switch OS!!!!!! What I did was installing the Rails environment and deploying my project on Ubuntu machine, then testing with the same sequence. It didn't crash. I even made my stress testing even more aggressive by initiating a request loop for around 10,000,000 requests from two different machines each and the server still RESPONDS!

I think you already have guessed what platform i was using for development. It was WINDOWS of course.

Viva Microsoft !!!
Tuesday, April 29, 2008

A talk about Gamunity

I've been away a little bit in the past few months as i joined the military. Military service is nice, but there is much time wasted in vain.

Anyway. I'm here to talk about something else. Something I hope it will be a great revolution in web based applications. It's called Gamunity.

Gamunity is our next product that will be introduced in the upcoming months. It will have alot of support from many platforms.

Watch my blog for more information about Gamunity and an introduction about it soon.