Scripts plugin

Discuss and announce AkelPad plugins
  • Author
  • Message
KDJ
Offline
Posts: 1949
Joined: Sat Mar 06, 2010 7:40 pm
Location: Poland

Post by KDJ »

Instructor
Maybe add a parameter eg. WGM_NOALTSPACESEND?

PS
How to read key messages if dialog created by AkelPad.CreateDialog is modal?

Offline
Site Admin
Posts: 6311
Joined: Thu Jul 06, 2006 7:20 am

Post by Instructor »

KDJ
Without subclassing there are several ways:

1.

Code: Select all

var hMainWnd=AkelPad.GetMainWnd();
var oSys=AkelPad.SystemFunction();
var hWndDialog=0;
var wCommand;
var dwFlags=0x3 /*CDF_PIXELS|CDF_MODAL*/;
var dwDialogThreadID;
var hHook;

//Control IDs
var IDC_BUTTON1=1001;
var IDC_BUTTON2=1002;
var IDC_EDIT=1003;

if (AkelPad.WindowRegisterClass("My Class"))
{
  AkelPad.CreateDialog(0, "My Class", "My Title",  0x90ca0040 /*DS_SETFONT|WS_VISIBLE|WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX*/, 10, 10, 300, 200, hMainWnd, DialogCallback, dwFlags, "|",
                       0, "BUTTON", "Button text 1", 0x50010001 /*WS_VISIBLE|WS_CHILD|WS_TABSTOP|BS_DEFPUSHBUTTON*/, 10, 10, 200, 20, IDC_BUTTON1, "|",
                       0, "BUTTON", "Button text 2", 0x50010000 /*WS_VISIBLE|WS_CHILD|WS_TABSTOP*/, 10, 50, 200, 20, IDC_BUTTON2, "|",
                       0, "EDIT", "Edit text 3", 0x50010000 /*WS_VISIBLE|WS_CHILD|WS_TABSTOP*/, 10, 90, 200, 20, IDC_EDIT);

  AkelPad.WindowUnregisterClass("My Class");
}

function DialogCallback(hWnd, uMsg, wParam, lParam)
{
  if (uMsg == 0x110 /*WM_INITDIALOG*/)
  {
    hWndDialog=hWnd;
    dwDialogThreadID=oSys.Call("user32::GetWindowThreadProcessId", hWndDialog, 0);
    hHook=AkelPad.ThreadHook(3 /*WH_GETMESSAGE*/, HookCallback, dwDialogThreadID, 0x100 /*WM_KEYDOWN*/);
  }
  else if (uMsg == 273 /*WM_COMMAND*/)
  {
    wCommand=LOWORD(wParam);

    if (wCommand == IDC_BUTTON1 ||
        wCommand == IDC_BUTTON2)
    {
      AkelPad.MessageBox(hWnd, "Button=" + wCommand, WScript.ScriptName, 0 /*MB_OK*/);
    }
    else if (wCommand == 2 /*IDCANCEL*/)
    {
      AkelPad.ThreadUnhook(hHook);
      oSys.Call("user32::EndDialog", hWnd, 0);
    }
  }
  return 0;
}

function HookCallback(nCode, wParam, lParam)
{
  var uMsg=AkelPad.MemRead(_PtrAdd(lParam, _X64?8:4) /*offsetof(MSG, message)*/, 3 /*DT_DWORD*/);

  if (uMsg == 0x100 /*WM_KEYDOWN*/)
  {
    wParam=AkelPad.MemRead(_PtrAdd(lParam, _X64?16:8) /*offsetof(MSG, wParam)*/, 2 /*DT_QWORD*/);

    if (wParam == 114 /*VK_F3*/)
    {
      WScript.Echo("F3");
    }
  }
}

function LOWORD(dwNumber)
{
  return (dwNumber & 0xffff);
}


2.

Code: Select all

var hMainWnd=AkelPad.GetMainWnd();
var oSys=AkelPad.SystemFunction();
var hWndDialog=0;
var wCommand;
var dwFlags=0x2 /*CDF_PIXELS*/;

//Control IDs
var IDC_BUTTON1=1001;
var IDC_BUTTON2=1002;
var IDC_EDIT=1003;

if (AkelPad.WindowRegisterClass("My Class"))
{
  AkelPad.CreateDialog(0, "My Class", "My Title",  0x90ca0040 /*DS_SETFONT|WS_VISIBLE|WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX*/, 10, 10, 300, 200, hMainWnd, DialogCallback, dwFlags, "|",
                       0, "BUTTON", "Button text 1", 0x50010001 /*WS_VISIBLE|WS_CHILD|WS_TABSTOP|BS_DEFPUSHBUTTON*/, 10, 10, 200, 20, IDC_BUTTON1, "|",
                       0, "BUTTON", "Button text 2", 0x50010000 /*WS_VISIBLE|WS_CHILD|WS_TABSTOP*/, 10, 50, 200, 20, IDC_BUTTON2, "|",
                       0, "EDIT", "Edit text 3", 0x50010000 /*WS_VISIBLE|WS_CHILD|WS_TABSTOP*/, 10, 90, 200, 20, IDC_EDIT);

  if (hWndDialog)
  {
    AkelPad.ScriptNoMutex();
    AkelPad.WindowGetMessage();
  }
  AkelPad.WindowUnregisterClass("My Class");
}

function DialogCallback(hWnd, uMsg, wParam, lParam)
{
  if (uMsg == 0x110 /*WM_INITDIALOG*/)
  {
    hWndDialog=hWnd;
    oSys.Call("User32::EnableWindow", hMainWnd, false);
  }
  else if (uMsg == 256 /*WM_KEYDOWN*/)
  {
    if (wParam == 114 /*VK_F3*/)
    {
      WScript.Echo("F3");
    }
  }
  else if (uMsg == 273 /*WM_COMMAND*/)
  {
    wCommand=LOWORD(wParam);

    if (wCommand == IDC_BUTTON1 ||
        wCommand == IDC_BUTTON2)
    {
      AkelPad.MessageBox(hWnd, "Button=" + wCommand, WScript.ScriptName, 0 /*MB_OK*/);
    }
    else if (wCommand == 2 /*IDCANCEL*/)
    {
      oSys.Call("User32::EnableWindow", hMainWnd, true);

      //Destroy dialog
      //Exit message loop
      oSys.Call("user32::PostQuitMessage", 0);

      oSys.Call("user32::DestroyWindow", hWnd);
    }
  }
  return 0;
}

function LOWORD(dwNumber)
{
  return (dwNumber & 0xffff);
}

KDJ
Offline
Posts: 1949
Joined: Sat Mar 06, 2010 7:40 pm
Location: Poland

Post by KDJ »

Instructor
Oh yes, thank you very much.

KDJ
Offline
Posts: 1949
Joined: Sat Mar 06, 2010 7:40 pm
Location: Poland

Post by KDJ »

Instructor
This sample script creates WebBrowser control using Atl.dll library:

Code: Select all

// descriptions:
// https://support.microsoft.com/en-us/kb/192560
// https://msdn.microsoft.com/en-us/library/aa768397%28v=vs.85%29.aspx
// https://msdn.microsoft.com/en-US/library/sxafe2b7%28v=vs.80%29.aspx

var oSys     = AkelPad.SystemFunction();
var hMainWnd = AkelPad.GetMainWnd();
var hInstDLL = AkelPad.GetInstanceDll();
var sClass   = "AkelPad::Scripts::" + WScript.ScriptName + "::" + hInstDLL;
var sTitle   = "WebBrowser control";

var sWBClass = "AtlAxWin";
var sWBTitle = "Shell.Explorer.2";
//var sWBTitle = "http://akelpad.sourceforge.net";
//var sWBTitle = AkelPad.GetAkelDir(2 /*ADTYPE_DOCS*/) + "\\AkelHelp-Eng.htm";
//var sWBTitle = "mshtml:<H1>Hello World</H1>";
//var sWBTitle = "AcroPDF.PDF.1";

var IDWB = 1000;
var hDlg;
var hWndWB;
var oWB;
var oDoc;

var hAtlLib = oSys.Call("Kernel32::LoadLibraryW", "Atl.dll");
oSys.Call("Atl::AtlAxWinInit");

AkelPad.WindowRegisterClass(sClass);

AkelPad.CreateDialog(0, sClass, sTitle, 0x90C80040 /*WS_VISIBLE|WS_POPUP|WS_CAPTION|WS_SYSMENU|DS_SETFONT*/, 200, 100, 500, 300, hMainWnd, DlgCallback, 0x3 /*CDF_PIXELS|CDF_MODAL*/, 0, 0, "", 0, 0, "|",
                     0, sWBClass, sWBTitle, 0x50300000 /*WS_VISIBLE|WS_CHILD|WS_HSCROLL|WS_VSCROLL*/, 0, 0, 500, 300, IDWB, 0);

AkelPad.WindowUnregisterClass(sClass);
oSys.Call("Kernel32::FreeLibrary", hAtlLib);

function DlgCallback(hWnd, uMsg, wParam, lParam)
{
  if (uMsg == 272 /*WM_INITDIALOG*/)
  {
    hDlg   = hWnd;
    hWndWB = oSys.Call("User32::GetDlgItem", hDlg, IDWB);

    WScript.Echo(hWndWB);

    //oWB = ... //how to get ActiveX object, WebBrowser object (use AtlAxGetControl()) ???
    //oWB.Navigate("http://akelpad.sourceforge.net");
    //oDoc = oWB.Document;
  }

  else if (uMsg == 273 /*WM_COMMAND*/)
  {
    if ((wParam & 0xFFFF) == 2 /*IDCANCEL*/)
      oSys.Call("user32::EndDialog", hDlg, 0);
  }

  return 0;
}

How to get ActiveX object (WebBrowser object) to be able to use its methods, properties and events described here: WebBrowser object?

Offline
Posts: 2247
Joined: Tue Aug 07, 2007 2:03 pm
Location: Vinnitsa, Ukraine

Post by FeyFre »

KDJ
I expect you want you this API. Well, I have no experience using it, maybe it is possible. But:

Short answer - FORGET IT. It is impossible to do now in JScript environment.
Long answer - Web Browser Control(as well as Windows Media Player, Data Grids, Flash player, and some other useful objects) is ActiveX Control. What that means? That means:
1. You can instantiate it using built-in into JScript engine object of type ActiveXObject, which is proxy object bound to default interface of requested ActiveX Component. It works for JScript because MS made it possible. Methods of dispinterface are transparently propagated as methods of returned object. (dispinterface is synonym for "COM interface derived from base interface IDispatch").
Example of successful usage of ActiveX Object - spellchecker using Microsoft Word (ActiveX object named "Word.application").

Code: Select all

var web = new ActiveXObject("Shell.Explorer.2");
//web has all methods which has dispinterface IWebBrowser2
web.Navigate("http://google.com/")
WebBrowser control is implemented in C:\WINDOWS\SYSTEM32\shdocvw.dll (you can inspect embedded typelib) there

2. ActiveX Control. That means, id client code want work with ActiveX Controls, he MUST provide proper environment. These requirements include a number of steps which must be performed before Control become usable and fully functional. These steps includes "putting" Control into Ole Container, Activating it, etc. And here we have problems: there is no tools in JScript to do that. [["putting" Control into Ole Container]] involves implementing special COM interfaces like: IOleClientSite, IOleWindow, IOleInPlaceSite, and querying some other interface from Control. The thing is - all those interfaces are not derived from IDispatch, they are derived from IUnknown directly, so is impossible in JScript. And even in plain C/C++ it requires deep understanding of technology. In C++ world MS provides us with helper libraries: ATL and MFC, but not for JScript.

You can find more info on MSDN, Sample implementation of that "environment" you can find here.

I see one possible solution suitable: we need to implementation of "environment" elsewhere: it can be other ActiveX Object, or special implementation provided by plugin itself(by Instructor).

Maybe I wrong?

KDJ
Offline
Posts: 1949
Joined: Sat Mar 06, 2010 7:40 pm
Location: Poland

Post by KDJ »

FeyFre
Yes, it seems to me that you're right. In JScript there is no tools for this.
Request to Instructor, can you implement it in Scripts plugin?

Offline
Site Admin
Posts: 6311
Joined: Thu Jul 06, 2006 7:20 am

Post by Instructor »

KDJ
With Scripts v17.7 you can call COM interface directly (be careful - hardcore code :)):

Code: Select all

// descriptions:
// https://support.microsoft.com/en-us/kb/192560
// https://msdn.microsoft.com/en-us/library/aa768397%28v=vs.85%29.aspx
// https://msdn.microsoft.com/en-US/library/sxafe2b7%28v=vs.80%29.aspx

var oSys     = AkelPad.SystemFunction();
var hMainWnd = AkelPad.GetMainWnd();
var hInstDLL = AkelPad.GetInstanceDll();
var sClass   = "AkelPad::Scripts::" + WScript.ScriptName + "::" + hInstDLL;
var sTitle   = "WebBrowser control";

var sWBClass = "AtlAxWin";
var sWBTitle = "Shell.Explorer.2";
//var sWBTitle = "http://akelpad.sourceforge.net";
//var sWBTitle = AkelPad.GetAkelDir(2 /*ADTYPE_DOCS*/) + "\\AkelHelp-Eng.htm";
//var sWBTitle = "mshtml:<H1>Hello World</H1>";
//var sWBTitle = "AcroPDF.PDF.1";

var IDWB = 1000;
var hDlg;
var hWndWB;
var oWB;
var oDoc;

var hAtlLib = oSys.Call("Kernel32::LoadLibraryW", "Atl.dll");
oSys.Call("Atl::AtlAxWinInit");

AkelPad.WindowRegisterClass(sClass);

AkelPad.CreateDialog(0, sClass, sTitle, 0x90C80040 /*WS_VISIBLE|WS_POPUP|WS_CAPTION|WS_SYSMENU|DS_SETFONT*/, 200, 100, 500, 300, hMainWnd, DlgCallback, 0x3 /*CDF_PIXELS|CDF_MODAL*/, 0, 0, "", 0, 0, "|",
                     0, sWBClass, sWBTitle, 0x50300000 /*WS_VISIBLE|WS_CHILD|WS_HSCROLL|WS_VSCROLL*/, 0, 0, 500, 300, IDWB, 0);

AkelPad.WindowUnregisterClass(sClass);
oSys.Call("Kernel32::FreeLibrary", hAtlLib);

function DlgCallback(hWnd, uMsg, wParam, lParam)
{
  if (uMsg == 272 /*WM_INITDIALOG*/)
  {
    hDlg   = hWnd;
    hWndWB = oSys.Call("User32::GetDlgItem", hDlg, IDWB);

    WScript.Echo(hWndWB);

    //Call COM interface directly
    {
      var lppUnknown=AkelPad.MemAlloc(_X64?8:4 /*sizeof(IUnknown**)*/);
      var lpUnknown;
      var lpUnknownVtbl;
      var lpUnknown_QueryInterface;
      var lpIID=AkelPad.MemAlloc(16 /*sizeof(IID)*/);
      var lppWebBrowser2=AkelPad.MemAlloc(_X64?8:4 /*sizeof(IUnknown**)*/);
      var lpWebBrowser2;
      var lpWebBrowser2Vtbl;
      var lpWebBrowser2_get_Name;
      var lpWebBrowser2_Release;
      var lppName=AkelPad.MemAlloc(_X64?8:4 /*sizeof(BSTR*)*/);
      var lpName;
      var pName;

      if (!oSys.Call("Atl::AtlAxGetControl", hWndWB, lppUnknown))
      {
        lpUnknown=AkelPad.MemRead(lppUnknown, 2 /*DT_QWORD*/);
        lpUnknownVtbl=AkelPad.MemRead(_PtrAdd(lpUnknown, 0) /*offsetof(IUnknown, lpVtbl)*/, 2 /*DT_QWORD*/);
        lpUnknown_QueryInterface=AkelPad.MemRead(_PtrAdd(lpUnknownVtbl, 0) /*offsetof(IUnknownVtbl, QueryInterface)*/, 2 /*DT_QWORD*/);

        oSys.Call("ole32::IIDFromString", "{D30C1661-CDAF-11d0-8A3E-00C04FC9E26E}", lpIID);

        if (!oSys.Call(lpUnknown_QueryInterface, lpUnknown, lpIID, lppWebBrowser2))
        {
          lpWebBrowser2=AkelPad.MemRead(lppWebBrowser2, 2 /*DT_QWORD*/);
          lpWebBrowser2Vtbl=AkelPad.MemRead(_PtrAdd(lpWebBrowser2, 0) /*offsetof(IWebBrowser2, lpVtbl)*/, 2 /*DT_QWORD*/);
          lpWebBrowser2_get_Name=AkelPad.MemRead(_PtrAdd(lpWebBrowser2Vtbl, 144) /*offsetof(IWebBrowser2Vtbl, get_Name)*/, 2 /*DT_QWORD*/);

          if (!oSys.Call(lpWebBrowser2_get_Name, lpWebBrowser2, lppName))
          {
            //Get name
            lpName=AkelPad.MemRead(lppName, 2 /*DT_QWORD*/);
            pName=AkelPad.MemRead(lpName, 1 /*DT_UNICODE*/);
            WScript.Echo(pName);
            oSys.Call("oleaut32::SysFreeString", lpName);

            //Navigate
            lpWebBrowser2_Navigate=AkelPad.MemRead(_PtrAdd(lpWebBrowser2Vtbl, 44) /*offsetof(IWebBrowser2Vtbl, Navigate)*/, 2 /*DT_QWORD*/);
            oSys.Call(lpWebBrowser2_Navigate, lpWebBrowser2, "http://akelpad.sourceforge.net", 0, 0, 0, 0);
          }
          lpWebBrowser2_Release=AkelPad.MemRead(_PtrAdd(lpWebBrowser2Vtbl, 8) /*offsetof(IWebBrowser2Vtbl, Release)*/, 2 /*DT_QWORD*/);
          oSys.Call(lpWebBrowser2_Release, lpWebBrowser2)
        }
      }
      AkelPad.MemFree(lppUnknown);
      AkelPad.MemFree(lpIID);
      AkelPad.MemFree(lppWebBrowser2);
      AkelPad.MemFree(lppName);
    }

    //oWB = ... //how to get ActiveX object, WebBrowser object (use AtlAxGetControl()) ???
    //oWB.Navigate("http://akelpad.sourceforge.net");
    //oDoc = oWB.Document;
  }

  else if (uMsg == 273 /*WM_COMMAND*/)
  {
    if ((wParam & 0xFFFF) == 2 /*IDCANCEL*/)
      oSys.Call("user32::EndDialog", hDlg, 0);
  }

  return 0;
}

Offline
Site Admin
Posts: 6311
Joined: Thu Jul 06, 2006 7:20 am

Post by Instructor »

Добавлено: возможность вызова функции по адресу в метод oSys.Call.

Added: possibility to call function by address in oSys.Call method.


Scripts plugin v17.7

KDJ
Offline
Posts: 1949
Joined: Sat Mar 06, 2010 7:40 pm
Location: Poland

Post by KDJ »

Instructor
That's great!
I have a few questions about IWebBrowser2:
1. What is IID structure?
2. What is IWebBrowser2 Vtable structure? Are the all elements of this table are the pointers?
3. How to handle the events, eg. NavigateComplete?

Offline
Posts: 2247
Joined: Tue Aug 07, 2007 2:03 pm
Location: Vinnitsa, Ukraine

Post by FeyFre »

KDJ
1. Technically IID == CLSID == UUID == GUID - an identifier. In world of COM all entities are identified by GUID identifier, which is 16-byte sized value(byte array). You can observe those in registry, for instance HKEY_CLASSES_ROOT\CLSID\{00000100-0000-0010-8000-00AA006D2EA4}
Difference between IID and CLSID and other *ID - its just hints for developer what kind of entity this GUID identifies.
There are such kind of entities:
IID - Interface identifier
CLSID - COM Object(Class) identifier
TLBID - Type Library identifier(metadata library)
(moreover, in Windows, drivers are expose their functionality using such Intreface ID)
All operations in world of COM are performed using such IDs.
If you want ask COM to create some object, you must provide its CLSID value. Moreover, CLSID is identifier of concrete class. But interaction with objects are done using COM Interfaces. COM Interface Definition consists of ordered list of methods(functions) and its signature(parameter types) that can be used by clients. An Unique IID value is assigned to each COM Interface Definition. Once COM Interface Definition desires to changed count, order of methods, or any of its parameters, it cannot use old IID, it MUST use other IID. So as second argument you provide COM with IID of interface you will interact with requested object.
See MSDN CoCreateInstance
IID {D30C1661-CDAF-11d0-8A3E-00C04FC9E26E} is assigned to interface IWebBrowser2. In Windows SDK we refer this constant value as IID_IWebBrowser.
But you can note: it is pretty hard to remember such 16-byte IDs.
For this reason MS introduced another one kind of ID - ProgId. It is human readable label of CLSID value. CLISD value of Web Browser Control is {8856F961-340A-11D0-A96B-00C04FD705A2} (in Windows SDK referred usually as CLSID_WebBrowser constant). There is exits ProgId which refers this value - "Shell.Explorer.2". JScript class ActiveXObject accepts both ProgIds and CLSIDs. Dictionary of ProgIds is stored in Windows Registry(HKEY_CLASSES_ROOT).
2. Yes, they all are. vTable - Virtual Functions Table - is core if Object-Oriented Paradigm. It is array of pointers(addresses) to functions in memory. In technical aspect COM Interface Definition is vTable structure.
3. Remember what I said in (1) "interaction with objects are done using COM Interfaces". In terminology of ActiveX Event - actually callback interface(dispinterface). Event interface must be implemented by client(i.e. you must create and fill vTable structure). Instance of such implantation must be given(registered) to object, and only in this case objects itself will invoke methods of event interface - Fire event.

It was brief explanation. I strongly recommend you read information about COM, ActiveX and practice it on C/C++(C++ easier to use, but harder to understand low-level details; C harder to use, but here in JScript it will be even harder). Well, I can say, I did not met good implementation of non-trivial interfaces on C yet. Well, you can look how interfaced used in C in sources of Scripts plugin and Speech plugin :)

KDJ
Offline
Posts: 1949
Joined: Sat Mar 06, 2010 7:40 pm
Location: Poland

Post by KDJ »

FeyFre
Thanks for the explanations.
I found IWebBrowser2Vtbl structure definition in ExDisp.h file. Now I see that offsetof(IWebBrowser2Vtbl, Navigate) is 44 (or 88 in x64 version).
Still I do not know how to capture the events. Maybe using DWebBrowserEvents2 interface?

Offline
Posts: 2247
Joined: Tue Aug 07, 2007 2:03 pm
Location: Vinnitsa, Ukraine

Post by FeyFre »

Yes, DWebBrowserEvents2 is default event dispinterface for this object. That means any object can have a number of event interfaces. Your task is to implement it. What to do after we will talk later. :D

Offline
Site Admin
Posts: 6311
Joined: Thu Jul 06, 2006 7:20 am

Post by Instructor »

KDJ
Please don't make me do it second time :)

Code: Select all

// descriptions:
// https://support.microsoft.com/en-us/kb/192560
// https://msdn.microsoft.com/en-us/library/aa768397%28v=vs.85%29.aspx
// https://msdn.microsoft.com/en-US/library/sxafe2b7%28v=vs.80%29.aspx

var oSys     = AkelPad.SystemFunction();
var hMainWnd = AkelPad.GetMainWnd();
var hInstDLL = AkelPad.GetInstanceDll();
var sClass   = "AkelPad::Scripts::" + WScript.ScriptName + "::" + hInstDLL;
var sTitle   = "WebBrowser control";

var sWBClass = "AtlAxWin";
var sWBTitle = "Shell.Explorer.2";
//var sWBTitle = "http://akelpad.sourceforge.net";
//var sWBTitle = AkelPad.GetAkelDir(2 /*ADTYPE_DOCS*/) + "\\AkelHelp-Eng.htm";
//var sWBTitle = "mshtml:<H1>Hello World</H1>";
//var sWBTitle = "AcroPDF.PDF.1";

var IDWB = 1000;
var hDlg;
var hWndWB;
var oWB;
var oDoc;

  //Connect to COM events - variables
  var lppUnknown=AkelPad.MemAlloc(_X64?8:4 /*sizeof(IUnknown**)*/);
  var lpUnknown=0;
  var lpUnknownVtbl;
  var lpUnknown_QueryInterface;
  var lpIID_WebBrowser2=AkelPad.MemAlloc(16 /*sizeof(IID)*/);
  var lppWebBrowser2=AkelPad.MemAlloc(_X64?8:4 /*sizeof(IUnknown**)*/);
  var lpWebBrowser2=0;
  var lpWebBrowser2Vtbl;
  var lpWebBrowser2_QueryInterface;
  var lpWebBrowser2_Navigate;
  var lpWebBrowser2_Release;
  var lpIID_ConnectionPointContainer=AkelPad.MemAlloc(16 /*sizeof(IID)*/);
  var lppConnectionPointContainer=AkelPad.MemAlloc(_X64?8:4 /*sizeof(IUnknown**)*/);
  var lpConnectionPointContainer=0;
  var lpConnectionPointContainerVtbl;
  var lpConnectionPointContainer_Release;
  var lpConnectionPointContainer_FindConnectionPoint;
  var lpDIID_DWebBrowserEvents2=AkelPad.MemAlloc(16 /*sizeof(IID)*/);
  var lppConnectionPoint=AkelPad.MemAlloc(_X64?8:4 /*sizeof(IUnknown**)*/);
  var lpConnectionPoint=0;
  var lpConnectionPointVtbl;
  var lpConnectionPoint_Release;
  var lpConnectionPoint_Advise;
  var lpConnectionPoint_Unadvise;
  var lpdwCookie=AkelPad.MemAlloc(4 /*sizeof(DWORD)*/);
  var dwCookie=0;
  var lpSinkVtbl;
  var lpSink=AkelPad.MemAlloc(_X64?8:4 /*sizeof(IUnknown*)*/);
  var aSinkVtbl=[];
  var lpIID_IUnknown=AkelPad.MemAlloc(16 /*sizeof(IID)*/);
  var lpIID_IDispatch=AkelPad.MemAlloc(16 /*sizeof(IID)*/);
  var i;


var hAtlLib = oSys.Call("Kernel32::LoadLibraryW", "Atl.dll");
oSys.Call("Atl::AtlAxWinInit");

AkelPad.WindowRegisterClass(sClass);

AkelPad.CreateDialog(0, sClass, sTitle, 0x90C80040 /*WS_VISIBLE|WS_POPUP|WS_CAPTION|WS_SYSMENU|DS_SETFONT*/, 200, 100, 500, 300, hMainWnd, DlgCallback, 0x3 /*CDF_PIXELS|CDF_MODAL*/, 0, 0, "", 0, 0, "|",
                     0, sWBClass, sWBTitle, 0x50300000 /*WS_VISIBLE|WS_CHILD|WS_HSCROLL|WS_VSCROLL*/, 0, 0, 500, 300, IDWB, 0);

AkelPad.WindowUnregisterClass(sClass);
oSys.Call("Kernel32::FreeLibrary", hAtlLib);

function DlgCallback(hWnd, uMsg, wParam, lParam)
{
  if (uMsg == 272 /*WM_INITDIALOG*/)
  {
    hDlg   = hWnd;
    hWndWB = oSys.Call("User32::GetDlgItem", hDlg, IDWB);

    //Connect to COM events - init
    {
      if (!oSys.Call("Atl::AtlAxGetControl", hWndWB, lppUnknown))
      {
        lpUnknown=AkelPad.MemRead(lppUnknown, 2 /*DT_QWORD*/);
        lpUnknownVtbl=AkelPad.MemRead(_PtrAdd(lpUnknown, 0) /*offsetof(IUnknown, lpVtbl)*/, 2 /*DT_QWORD*/);
        lpUnknown_QueryInterface=AkelPad.MemRead(_PtrAdd(lpUnknownVtbl, 0) /*offsetof(IUnknownVtbl, QueryInterface)*/, 2 /*DT_QWORD*/);

        oSys.Call("ole32::IIDFromString", "{D30C1661-CDAF-11d0-8A3E-00C04FC9E26E}", lpIID_WebBrowser2);
        if (!oSys.Call(lpUnknown_QueryInterface, lpUnknown, lpIID_WebBrowser2, lppWebBrowser2))
        {
          lpWebBrowser2=AkelPad.MemRead(lppWebBrowser2, 2 /*DT_QWORD*/);
          lpWebBrowser2Vtbl=AkelPad.MemRead(_PtrAdd(lpWebBrowser2, 0) /*offsetof(IWebBrowser2, lpVtbl)*/, 2 /*DT_QWORD*/);
          lpWebBrowser2_QueryInterface=AkelPad.MemRead(_PtrAdd(lpWebBrowser2Vtbl, 0) /*offsetof(IWebBrowser2Vtbl, QueryInterface)*/, 2 /*DT_QWORD*/);
          lpWebBrowser2_Release=AkelPad.MemRead(_PtrAdd(lpWebBrowser2Vtbl, 8) /*offsetof(IWebBrowser2Vtbl, Release)*/, 2 /*DT_QWORD*/);
          lpWebBrowser2_Navigate=AkelPad.MemRead(_PtrAdd(lpWebBrowser2Vtbl, 44) /*offsetof(IWebBrowser2Vtbl, Navigate)*/, 2 /*DT_QWORD*/);

          oSys.Call("ole32::IIDFromString", "{B196B284-BAB4-101A-B69C-00AA00341D07}", lpIID_ConnectionPointContainer);
          if (!oSys.Call(lpWebBrowser2_QueryInterface, lpWebBrowser2, lpIID_ConnectionPointContainer, lppConnectionPointContainer))
          {
            lpConnectionPointContainer=AkelPad.MemRead(lppConnectionPointContainer, 2 /*DT_QWORD*/);
            lpConnectionPointContainerVtbl=AkelPad.MemRead(_PtrAdd(lpConnectionPointContainer, 0) /*offsetof(IConnectionPointContainer, lpVtbl)*/, 2 /*DT_QWORD*/);
            lpConnectionPointContainer_Release=AkelPad.MemRead(_PtrAdd(lpConnectionPointContainerVtbl, 8) /*offsetof(IConnectionPointContainerVtbl, Release)*/, 2 /*DT_QWORD*/);
            lpConnectionPointContainer_FindConnectionPoint=AkelPad.MemRead(_PtrAdd(lpConnectionPointContainerVtbl, 16) /*offsetof(IConnectionPointContainerVtbl, FindConnectionPoint)*/, 2 /*DT_QWORD*/);

            oSys.Call("ole32::IIDFromString", "{34A715A0-6587-11D0-924A-0020AFC7AC4D}", lpDIID_DWebBrowserEvents2);
            if (!oSys.Call(lpConnectionPointContainer_FindConnectionPoint, lpConnectionPointContainer, lpDIID_DWebBrowserEvents2, lppConnectionPoint))
            {
              lpConnectionPoint=AkelPad.MemRead(lppConnectionPoint, 2 /*DT_QWORD*/);
              lpConnectionPointVtbl=AkelPad.MemRead(_PtrAdd(lpConnectionPoint, 0) /*offsetof(IConnectionPoint, lpVtbl)*/, 2 /*DT_QWORD*/);
              lpConnectionPoint_Release=AkelPad.MemRead(_PtrAdd(lpConnectionPointVtbl, 8) /*offsetof(IConnectionPointVtbl, Release)*/, 2 /*DT_QWORD*/);
              lpConnectionPoint_Advise=AkelPad.MemRead(_PtrAdd(lpConnectionPointVtbl, 20) /*offsetof(IConnectionPointVtbl, Advise)*/, 2 /*DT_QWORD*/);
              lpConnectionPoint_Unadvise=AkelPad.MemRead(_PtrAdd(lpConnectionPointVtbl, 24) /*offsetof(IConnectionPointVtbl, Unadvise)*/, 2 /*DT_QWORD*/);

              aSinkVtbl=[oSys.RegisterCallback(Sink_QueryInterface),
                         oSys.RegisterCallback(Sink_AddRef),
                         oSys.RegisterCallback(Sink_Release),
                         oSys.RegisterCallback(Sink_GetTypeInfoCount),
                         oSys.RegisterCallback(Sink_GetTypeInfo),
                         oSys.RegisterCallback(Sink_GetIDsOfNames),
                         oSys.RegisterCallback(Sink_Invoke)];
              lpSinkVtbl=AkelPad.MemAlloc((_X64?8:4 /*sizeof(PROC)*/) * aSinkVtbl.length);
              for (i=0; i < aSinkVtbl.length; ++i)
              {
                AkelPad.MemCopy(_PtrAdd(lpSinkVtbl, i * (_X64?8:4 /*sizeof(PROC)*/)), aSinkVtbl[i], 2 /*DT_QWORD*/);
              }
              AkelPad.MemCopy(_PtrAdd(lpSink, 0) /*lpSink->lpVtbl*/, lpSinkVtbl, 2 /*DT_QWORD*/);

              oSys.Call("ole32::IIDFromString", "{00000000-0000-0000-C000-000000000046}", lpIID_IUnknown);
              oSys.Call("ole32::IIDFromString", "{00020400-0000-0000-C000-000000000046}", lpIID_IDispatch);
              if (!oSys.Call(lpConnectionPoint_Advise, lpConnectionPoint, lpSink, lpdwCookie))
              {
                dwCookie=AkelPad.MemRead(lpdwCookie, 2 /*DT_QWORD*/);

                //Navigate
                oSys.Call(lpWebBrowser2_Navigate, lpWebBrowser2, "http://akelpad.sourceforge.net", 0, 0, 0, 0);
              }
            }
          }
        }
      }
    }

    //oWB = ... //how to get ActiveX object, WebBrowser object (use AtlAxGetControl()) ???
    //oWB.Navigate("http://akelpad.sourceforge.net");
    //oDoc = oWB.Document;
  }

  else if (uMsg == 273 /*WM_COMMAND*/)
  {
    if ((wParam & 0xFFFF) == 2 /*IDCANCEL*/)
    {
      //Connect to COM events - release
      {
        if (dwCookie)
          oSys.Call(lpConnectionPoint_Unadvise, lpConnectionPoint, dwCookie);
        for (i=0; i < aSinkVtbl.length; ++i)
        {
          oSys.UnregisterCallback(aSinkVtbl[i]);
        }
        if (lpConnectionPoint) oSys.Call(lpConnectionPoint_Release, lpConnectionPoint);
        if (lpConnectionPointContainer) oSys.Call(lpConnectionPointContainer_Release, lpConnectionPointContainer);
        if (lpWebBrowser2) oSys.Call(lpWebBrowser2_Release, lpWebBrowser2);
        AkelPad.MemFree(lppUnknown);
        AkelPad.MemFree(lpIID_WebBrowser2);
        AkelPad.MemFree(lppWebBrowser2);
        AkelPad.MemFree(lpDIID_DWebBrowserEvents2);
        AkelPad.MemFree(lpdwCookie);
        AkelPad.MemFree(lpIID_ConnectionPointContainer);
        AkelPad.MemFree(lppConnectionPointContainer);
        AkelPad.MemFree(lppConnectionPoint);
        AkelPad.MemFree(lpSink);
        AkelPad.MemFree(lpIID_IUnknown);
        AkelPad.MemFree(lpIID_IDispatch);
      }
      oSys.Call("user32::EndDialog", hDlg, 0);
    }
  }

  return 0;
}

//Connect to COM events - sink
function Sink_QueryInterface(thisObj, vTableGuid, ppv)
{
  if (oSys.Call("ole32::IsEqualGUID", vTableGuid, lpDIID_DWebBrowserEvents2) ||
      oSys.Call("ole32::IsEqualGUID", vTableGuid, lpIID_IUnknown) ||
      oSys.Call("ole32::IsEqualGUID", vTableGuid, lpIID_IDispatch))
  {
    AkelPad.MemCopy(ppv, thisObj, 2 /*DT_QWORD*/);
    return 0 /*S_OK*/;
  }
  AkelPad.MemCopy(ppv, 0, 2 /*DT_QWORD*/);
  return 0x80004002 /*E_NOINTERFACE*/;
}

function Sink_AddRef(thisObj)
{
  return 0;
}

function Sink_Release(thisObj)
{
  return 0;
}

function Sink_GetTypeInfoCount(thisObj, pCount)
{
  AkelPad.MemCopy(pCount, 0, 3 /*DT_DWORD*/);
  return 0 /*S_OK*/;
}

function Sink_GetTypeInfo(thisObj, itinfo, lcid, pTypeInfo)
{
  AkelPad.MemCopy(pTypeInfo, 0, 2 /*DT_QWORD*/);
  return 0 /*S_OK*/;
}

function Sink_GetIDsOfNames(thisObj, riid, rgszNames, cNames, lcid, rgdispid)
{
  return 0 /*S_OK*/;
}

function Sink_Invoke(thisObj, dispid, riid, lcid, wFlags, params, result, pexcepinfo, puArgErr)
{
  if (dispid == 259 /*DISPID_DOCUMENTCOMPLETE*/)
  {
    WScript.Echo("DISPID_DOCUMENTCOMPLETE");
  }
  return 0 /*S_OK*/;
}

Offline
Posts: 2247
Joined: Tue Aug 07, 2007 2:03 pm
Location: Vinnitsa, Ukraine

Post by FeyFre »

Instructor, дали бы поупражняться KDJ, зачем сразу всё писать. Человек бы проникся. А так копипаста будет, и будут ещё вопросы. :D
Оно тут всё так и просится в врапер :)

KDJ
Offline
Posts: 1949
Joined: Sat Mar 06, 2010 7:40 pm
Location: Poland

Post by KDJ »

Instructor
You just have proven that in AkelPad Scripts and JS can do everything, like in C/C++.
Excellently, thank you very much.
Now I need a few days to understand it. :D

FeyFre
No, No, No! I myself I would never do that! :D
Post Reply