NOTE:THIS DOCUMENT IS AN EARLY RELEASE OF THE FINAL SPECIFICATION. IT IS MEANT TO SPECIFY AND ACCOMPANY THE TUTORIAL THAT IS STILL IN DEVELOPMENT.SOME OF THE INFORMATION IN THE TUTORIAL MAY BE IMPRECISE OR MAY NOT BE AN ACCURATE REPRESENTATION OF THE FUNCTIONALITY OF THE FINAL DOCUMENT OR TUTORIAL.
WE ASSUME NO RESPONSIBILITY WHATSOEVER FOR ANY DAMAGES THAT MIGHT OCCUR EITHER DIRECTLY OR INDIRECTLY FROM THESE INACCURACIES. ALL THE FAMILY TROUBLES ACCRUING AS A RESULT OF EXCESSIVE PERUSAL OF THIS TUTORIAL AND LESS OF TIME BEING SPENT IN THE HOUSE THEREOF; OR BY WAY OF SCUFFLES RELATING TO TIME-SLOTS ON THE COMPUTER; OR ANY OTHER FORM OF LEGAL/ILLEGAL HASSLES ARISING AS A DIRECT OR INDIRECT CONSEQUENCE OF THE SUBJECT MATTER OF THESE FILES, INCLUDING INTELLECTUAL DEBATES, BUT EXCLUDING PHILOSOPHICAL TYPOS; OR THE DILAPIDATION OF THE COMPUTER WHILE EXECUTING ANY OF THE CODE BUNDLED HEREWITH; OR ANY UPSURGE IN THE REGISTRATIONS AT THE LOCAL ASYLUM OR MONASTERY ACCOUNTABLE TO NAUSEATING PROGRAMS ETC. -- SHALL NOT BE THE LIABILITY OF THE AUTHORS.
In this section, we demonstrate ActiveX objects by means of four programs:
Program 1: Displaying static text
Program 2: Displaying from an html file
Program 3: Displaying a bmp file
Program 4: Playing an avi file
PROGRAM 1
zzz.cpp
#define INITGUID
#define INITOBJECTS
#include "Internet.h"
#include "Globals.H"
#include <stdio.h>
DEFINE_GUID(LIBID_wwwobject, 0xB92BB5C0L, 0x2E73, 0x11CF, 0xB6, 0xCF, 0x00, 
0xAA, 0x00, 0xA7, 0x4D, 0xAF);
DEFINE_GUID(CLSID_www, 0xBD11A280L, 0x2E73, 0x11CF, 0xB6, 0xCF, 0x00, 0xAA, 
0x00, 0xA7, 0x4D, 0xAF);
void myaa(char *p)
{
	FILE *fp;
	fp=fopen("d:\\zzz\\z.txt", "a+");
	fprintf(fp, "%s..\n", p);
	fclose(fp);
}
const char g_szLibName[] = "www";
WNDPROC g_ParkingWindowProc = NULL;
const short g_fSatelliteLocalization = FALSE;
const unsigned short g_wszLicenseKey [] = L"";
LCID  g_lcidLocale = MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT);
const CLSID *g_pLibid	= &LIBID_wwwobject;
char a[200];
WNDCLASS d;
class ccc:public CInternetControl, IDispatch
{
  public:
    DECLARE_STANDARD_UNKNOWN();
    DECLARE_STANDARD_DISPATCH();
    ccc(IUnknown *);
    static IUnknown *mycreate(IUnknown *);
    long  _stdcall LoadBinaryState(IStream *)
    {return 0;}
    long _stdcall SaveBinaryState(IStream *)
    {return 0;}
    long _stdcall LoadTextState(IPropertyBag *, IErrorLog *)
    {return 0;}
    long _stdcall SaveTextState (IPropertyBag *, BOOL )
    {return 0;}
    long _stdcall OnDraw (void *, LPCRECTL, LPCRECTL, void * )
    {return 0;}
    virtual BOOL    RegisterClassData(void);
    virtual long OnData( long, unsigned long, IStream *, unsigned long )
    {return 0;}
    virtual long WindowProc(void *, unsigned int, unsigned int, long);
};
CONTROLOBJECTINFO o = {{{&CLSID_www, "wwwCtl", ccc::mycreate}, 1, 0, 0, NULL, 0}, 0, 0, 1, "sss", FALSE, 1, 0, 0, 0, NULL } ;
OBJECTINFO g_ObjectInfo[]	= {{OI_CONTROL, (void *)&(o)}, 
   						{OI_BOGUS, 0}, 
						{OI_BOGUS, 0}};
void InitializeLibrary()
{	myaa("InitializeLibrary");
}
void UninitializeLibrary()
{	myaa("uninitializeLibrary");
}
BOOL CheckForLicense()
{	myaa("Checkforlicense");
	return TRUE;
}
BOOL RegisterData()
{	myaa("RegisterData");
	return TRUE;
}
BOOL UnregisterData()
{	myaa("UnregisterData");
	return TRUE;
}
IUnknown *ccc::mycreate(IUnknown *p)
{
	sprintf(a, "p..%p", p);
	myaa(a);
	ccc *c = new ccc(p);
	IUnknown *m_pIUnknown = c-PrivateUnknown();
	sprintf(a, "ccc::Create m_pIUnknown=%p c=%p", m_pIUnknown, c);
	myaa(a);
	return m_pIUnknown;
}
ccc::ccc(IUnknown *p):CInternetControl(p, 0, (IDispatch *)this)
{
	myaa("ccc::ccc");
}
BOOL ccc::RegisterClassData()
{
	myaa("ccc::RegisterClassData");
	d.lpfnWndProc = COleControl::ControlWindowProc;
	d.hInstance = g_hInstance;
	d.lpszClassName = "sss";
	return RegisterClass(&d);
}
long ccc::WindowProc(void * w, unsigned int x, unsigned int y, long z)
{
	if (x == WM_LBUTTONDOWN)
	{
		void * h = GetDC(w);
		TextOut(h, LOWORD(z), HIWORD(z), "hello", 4);
		ReleaseDC(w, h);
	}
	return DefWindowProc(w, x, y, z);
}
zzz.rc
1 TYPELIB zzz.TLB
zzz.odl
#include <OLEctl.h
[ uuid(b92bb5c0-2e73-11cf-b6cf-00aa00a74daf), lcid(0x0000), version(1.0)]
library wwwobject {
        importlib("STDOLE32.TLB");
        importlib(STDTYPE_TLB);
        importlib("datapath.tlb");
        [uuid(bd11a280-2e73-11cf-b6cf-00aa00a74daf)]
        coclass www {
        [default]         interface IDispatch;
         };
};
zzz.def
LIBRARY         zzz
EXPORTS         DllRegisterServer
EXPORTS		DllUnregisterServer
EXPORTS		DllCanUnloadNow
EXPORTS		DllGetClassObject
zzz.htm
<HTML>
<HEAD>
<TITLE>OLE Control Example</TITLE>
</HEAD>
<BODY>
<CENTER>
HELLO<br>
<OBJECT CLASSID="clsid:{bd11a280-2e73-11cf-b6cf-00aa00a74daf}"
      HEIGHT=234 WIDTH=312>
</OBJECT>
</CENTER>
<HR>
</BODY>
</HTML>
z.txt
InitializeLibrary..
RegisterData..
uninitializeLibrary..
InitializeLibrary..
Checkforlicense..
ccc::ccc..
p..000000
ccc::Create i=0048E654 c=0048E648..
ccc::RegisterClassData..
uninitializeLibrary..
The zzz.cpp, zzz.rc, zzz.odl, zzz.def will be the files within the project. Before you build the project to create the zzz.ocx, you will have to make some changes to its default settings.
For the include files, add
d:\inetsdk\include and
d:\inetsdk\samples\basectl\include
For the lib files, add
d:\inetsdk\lib
d:\inetsdk\samples\basectl\lib
CtlFwd32.lib uuid2.lib uuid3.lib urlmon.lib kernel32.lib advapi32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib OLE32.lib OLEaut32.lib uuid.lib winspool.lib version.lib msvcrtd.lib oldnames.lib
When you build this project the file zzz.ocx is created in the Debug directory and it automatically gets registered in the system registry.
Lets understand the VC++ 4.0 program step by step. You have to create a cpp file, rc file, odl file and a def file. The rc file can be created in DOS. Note that the htm file will be needed when you are running the program.
We assume that you know what an interface is, or more specifically, what a QueryInterface is. Nonetheless, if you are wondering what that is, or if you want to brush up, you can read the docobjects.
Since this technology is not yet complete from the Microsoft's point of view, they have given a large number of cpp files. These files can be found in the inetsdk directory at the following path
d:\inetsdk\Basectl\Framewrk
This code is used to build a library that is why the lib subdirectory comes in when the cpp files are compiled. The lib directory will have a CtlFwd32.lib file; meanwhile, the include has the header files for the code. Hence, there are extern global variables like g_szLibName, g_ParkingWindowProc, g_fSatelliteLocalization, g_wszLiscencseKey . These extern variables contain valuable information that we will need later.
In the htm file we add a new tag called 'object' as:
<OBJECT CLASSID="clsid:{bd11a280-2e73-11cf-b6cf-00aa00a74daf}"
      HEIGHT=234 WIDTH=312>As is amply evident, the syntax is
<OBJECT CLASSID = "clsidno" HEIGHT = no WIDTH = no >
With CLASSID, a clsid number has to be given. The clsid number in our case represents zzz.ocx . This number could be any number and can be changed. It stands for the OCX because when the program is compiled successfully, the regserver program registers the control with that number in the system registry of Windows 95. It is worthwhile to point here that this clsidno is the same as the clsidno for the coclass www in the .odl file. A coclass is the name given for a server or a control.A server will basically comprise of methods and events. Which in turn means that a coclass is a collection of methods and events. As regards what these really are, let us defer it for the time being. When the OCX will have methods and events, that is the time we shall pry into them.
Next, if you run the program regedit, and look out for the number
bd11a280-2e73-11cf-b6cf-00aa00a74daf
it will point to zzz.ocx which is shown along with its pathname. This means that the Internet Explorer , when it loads the htm file, will go to the system registry and look for this clsid number. Once found, it will load the server or the OCX file or the OLE 2.0 server in the htm document The width and height in the htm file will decide the area for the server. Now if you click anywhere in the center, below the word 'hello', 'hell' will be displayed.
When the server is loaded into memory, some code from Framewrk and some from the program will get called at the same time. Lets get it a little more clearly.
To start with, the functions called InitialiseLibrary, RegisterData and UninitialiseLibrary get called. It is all because of the 4 functions given in the def file. Note that these functions are specified as 'exportable'. These four functions have absolutely no code in the program, but they are indispensable. In addition, InitializeLibrary, CheckForLicense, InitialiseLibrary, RegisterData and UninitialiseLibrary also get called by the functions in the library CtlFwd32.lib. The CheckForLicense function is meant more for licensing purposes of the server. As of now, we have no code within these functions because nothing is to be done when the server is being started.
Since our work will be done by means of objects, we first derive a class called ccc from CInternetControl, and IDispatch. The prototype for CInternet Control is in the Internet.h header file which is in the include subdirectory of BaseCtl. The CInternetControl class has a large number of virtual = 0 functions or pure functions. Since they are virtual = 0 functions, the ccc class which is derived from it has to have them. The ccc class is also derived from IDispatch which means that the 4 functions of IDispatch are also to be present in the ccc class.The DECLARE_STANDARD_DISPATCH macro will bring in these functions.As of now there is no code given for these functions as they don't do anything. We will take up IDispatch in excruciating detail later, because IDispatch is meant for information about methods, properties and events. DECLARE_STANDARD_UNKNOWN macro stands for QueryInterface, AddRef and Release.
The insider information that you might be wondering about now is : "How did this object that looks like ccc get created ?"
To understand this, lets look at the odl (object description language) file. As the rc file gives a res file, the odl file, which is a programming language ,when compiled gives a tlb file. A program called mktyplib is to be executed to give a tlb file. As for us, the tlb file is created by the project which internally calls the mktyplib program. At the same time, in the rc file we add the tlb file, which finally goes into our OCX. Now if we look at g_pLibid , it is an extern variable which is initialised to the address of our library. By doing so, a reference to the library or the tlb file is provided (in fact, this is a basic detail that has to be stated). The odl file contains a library called www_object . Mark that the DEFINEGUID in the cpp file and the libid number of www_object in the odl are the same. Again the odl file will be explained in detail later.
The next significant item is the structure called g_ObjectInfo . This structure is in one of the header files. It is not important to know what g_ObjectInfo contains. For all we care, it could contain a zillion structures itself. Right now it is an array of three, i.e. it has three object infos in it. Now an object info structure has two members -- first is the number and the second is the address of the CONTROLOBJECTINFO structure. Out of the three members, the last two are not important but we have to have them. OI_CONTROL says that this objectinfo is a control. The second parameter is an address to a CONTROLOBJECTINFO which we have called o . The structure requires the address of the CONTROLOBJECTINFO because it has all the information that is needed about the OCX. The browser i.e.Internet Explorer will first go to the OBJECTINFO and then it will go to o .
Now in the CONTROLOBJECTINFO, the CILSID_www is the number of the coclass or the ocx. wwwCtl is the name for the OCX. The third member which is mycreate is most crucial for us. It is a static function. For the ones who donot know what static functions are, an object need not be created to use the function. Therefore, as the third member is the address of the static function, mycreate gets executed. In this static function we create an object that looks like ccc and we also pass the pointer that is given to us, i.e. when InternetExplorer or whoever calls the static function, it puts a pointer to IUnknown on the stack. Fortunately it happens to be 0 (zero) so we don't have to worry about what it does. Now after creating an object that looks like ccc , the PrivateUnknown function is called. PrivateUnknown is obviously a function in CInternetControl which also returns a pointer to IUnknown. We will explain later what this pointer is, but if noticed c and m_pIUnknown have similar values. This pointer is returned back to whoever calls mycreate . The reason why mycreate has to be a static function and a part of CInternetControl class is because it can then only access PrivateUnknown otherwise not. (private and protected decides who can access what functions).
After mycreate , the next function that gets called is RegisterClassData. RegisterClassData is a virtual function in which a class has to be registered. The Internet Explorer is going to create a window for you, in which your OCX is going to lie. But it cannot create a window unless it has the name of the class. One of the parameter in CONTROLOBJECTINFO is sss which happens to be the name of the class. This class will be used to create a window. Please remember that the window will be created by Internet Explorer, we have to simply give it the name of the class.We have to register the class because we have to decide how the window looks like. To register the class is a must, so we have registered it with the bare minimum possible. The hInstance of WNDCLASS is initialised to g_hInstance. That is the g_hInstance is the number of this program which is given by the Framework. Our class name is sss and the callback function is ControlWindowProc. The ControlWindowProc is a function in COleControl. All the window messages will come to this callback function. With RegisterClass function, the sss class gets registered.
Now each time you click inside the OCX window, which will be just below "Hello", that click goes to ControlWindowProc. ControlWindowProc in turn calls WindowProc. And WindowProc function in the program, displays hell wherever we click.
So there.You have your first (not to forget, the smallest) ActiveX Object that does something. In this AXO, you have to register the server in your local machine. The browser searches for the CLSID number in the registry and then loads the object in the htm file. Now if this zzz.htm was on other server, the ActiveX Object would come onto your machine, the Internet Explorer or the browser would look into the registry for the CLSID of the object. If it is not there on your machine, obviously it would download the code from the Internet and then may or may not install it on your local machine.
Now this part is yet in Alpha. Microsoft has promised that they will change it. What we wanted to tell you is that these are minor extensions to OLE2.0 so that they can now be Internet Ready. The philosophy of Microsoft has been not to reorient the OLE 2.0 concepts, but to stretch it to encompass the Internet. For instance, the earlier OLE2.0 said that if you wanted to display a bitmap in a control, the data would come from the local machine. Now it is possible for the data to wriggle down to your machine from any server on the Internet.
But there are issues that have to be attended to. As a case in point, how does the OCX handle the inflow of data in the event of disconnection ? Or how does it handle voluminous files without making the user wait indefinitely ? In the above program, we are just displaying an OCX, and when you click inside it, "Hell" is displayed.
zzz.cpp
#define INITGUID
#define INITOBJECTS
#include "Internet.h"
#include "Globals.H"
#include "Util.H"
#include <stdio.h>
DEFINE_GUID(LIBID_wwwobject,0xB92BB5C0L,0x2E73, 0x11CF,0xB6,0xCF,0x00,
0xAA,0x00,0xA7,0x4D,0xAF);
DEFINE_GUID(CLSID_www,0xBD11A280L,0x2E73, 0x11CF,0xB6,0xCF,0x00,
0xAA,
0x00,0xA7,0x4D,0xAF);
void myaa(char *p)
{
	FILE *fp;
	fp=fopen("d:\\zzz\\z.txt","a+");
	fprintf(fp,"%s..\n",p);
	fclose(fp);
}
const char g_szLibName[]		= "www";
WNDPROC g_ParkingWindowProc 		= NULL;
const short g_fSatelliteLocalization= FALSE;
const unsigned short g_wszLicenseKey[] = L"";
LCID  g_lcidLocale = MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT);
const CLSID *g_pLibid= &LIBID_wwwobject;
VARIANT v;
unsigned short m[] = L"ttt";
char a[200];
char s[100];
WNDCLASS d;
char * t;
class ccc:public CInternetControl,IDispatch
{
  public:
    DECLARE_STANDARD_UNKNOWN();
    DECLARE_STANDARD_DISPATCH();
    ccc(IUnknown *);
    static IUnknown *mycreate(IUnknown *);
    long  _stdcall LoadBinaryState(IStream *)
    {return 0;}
    long _stdcall SaveBinaryState(IStream *)
    {return 0;}
    long _stdcall LoadTextState(IPropertyBag *, IErrorLog *);
    long _stdcall SaveTextState (IPropertyBag *, BOOL )
    {return 0;}
    long _stdcall OnDraw (void *,LPCRECTL,LPCRECTL,void *)
    {return 0;}
    virtual BOOL  RegisterClassData(void);
    virtual long OnData(long, unsigned long,IStream *,unsigned long)
    {return 0;}
    virtual long WindowProc(void *, unsigned int,unsigned int,long);
};
CONTROLOBJECTINFO o={{{&CLSID_www,"wwwCtl",ccc::mycreate},1, 0, 0,
NULL, 0},0,0, 1, "sss", FALSE, 1, 0, 0, 0, NULL } ;
OBJECTINFO g_ObjectInfo[]={	{OI_CONTROL,(void *)&(o)},
					{OI_BOGUS,0},
					{OI_BOGUS,0}};
void InitializeLibrary()
{	myaa("InitializeLibrary");
}
void UninitializeLibrary()
{	myaa("uninitializeLibrary");
}
BOOL CheckForLicense()
{	myaa("CheckForLicense");
	return TRUE;
}
BOOL RegisterData()
{	myaa("RegisterData");
	return TRUE;
}
BOOL UnregisterData()
{	myaa("UnregisterData");
	return TRUE;
}
IUnknown *ccc::mycreate(IUnknown *p)
{
	ccc *c = new ccc(p);
	IUnknown *m_pIUnknown = c-PrivateUnknown();
	sprintf(a,"ccc::Create m_pIUnknown=%p c=%p",m_pIUnknown,c);
	myaa(a);
	return m_pIUnknown;
}
ccc::ccc(IUnknown *p):CInternetControl(p,0,(IDispatch *)this)
{
	myaa("ccc::ccc");
}
BOOL ccc::RegisterClassData()
{
	myaa("ccc::RegisterClassData");
	d.lpfnWndProc    = COleControl::ControlWindowProc;
	d.hInstance      = g_hInstance;
	d.lpszClassName  = "sss";
	return RegisterClass(&d);
}
long ccc::WindowProc(void * w, unsigned int x, unsigned int y, long z)
{
	if (x == WM_LBUTTONDOWN)
	{
		void * h = GetDC(w);
		TextOut(h,LOWORD(z),HIWORD(z),s,5);
		ReleaseDC(w,h);
	}
	return DefWindowProc(w, x, y, z);
}
long ccc::LoadTextState(IPropertyBag *m_pIPropertyBag,IErrorLog *m_pIErrorLog)
{
	v.vt = VT_BSTR;
	myaa("In LoadTextState");
	m_pIPropertyBag-Read(::m, &v,m_pIErrorLog);
	MAKE_ANSIPTR_FROMWIDE(t,v.bstrVal);
	lstrcpy(s,t);
	return 0;
}
zzz.rc
1 TYPELIB zzz.TLB
zzz.odl
#include <olectl.h
[ uuid(b92bb5c0-2e73-11cf-b6cf-00aa00a74daf),lcid(0x0000),version(1.0)]
library wwwobject {
        importlib("STDOLE32.TLB");
        importlib(STDTYPE_TLB);
        importlib("datapath.tlb");
        [uuid(bd11a280-2e73-11cf-b6cf-00aa00a74daf)]
        coclass www {
        [default]         interface IDispatch;
         };
};
zzz.def
LIBRARY         zzz
EXPORTS     DllRegisterServer
EXPORTS		DllUnregisterServer
EXPORTS		DllCanUnloadNow
EXPORTS		DllGetClassObject
zzz.htm
<HTML>
<HEAD>
<TITLE>OLE Control Example</TITLE>
</HEAD>
<BODY>
<CENTER>
HELLO<br>
<OBJECT CLASSID="clsid:{bd11a280-2e73-11cf-b6cf-00aa00a74daf}"
      HEIGHT=234 WIDTH=312>
      <PARAM NAME="ttt" VALUE="hello">
</OBJECT>
</CENTER>
<HR>
</BODY>
</HTML>
z.txt
InitializeLibrary..
RegisterData..
UninitializeLibrary..
InitializeLibrary..
CheckForLicense..
ccc::ccc..
ccc::Create m_pIUnknown=0046CB28 c=0046CB1C..
In LoadTextState..
ccc::RegisterClassData..
uninitializeLibrary..
In this example, we display the OCX and when clicked inside it with the Left Mouse Button, "hello" will be displayed there. It differs from Program 1 because there we had hard-coded the word "hello", but here we are picking it up as a parameter from the htm file. Note that in the htm file, along with the word object we add the word PARAM NAME, the name of the parameter being ttt , and the value being "hello".
Which means that we can now decide what should be displayed on the screen when clicked. The idea here is that whatever is in the htm file becomes a part of the definition of the OLE server.
It becomes rather comfortable for all you need is a virtual function called LoadTextState. This function gets called before RegisterClassData and has two pointers passed to it. One is to the IPropertyBag and the other to an IErrorLog.
A smart programmer usually has a sound reason to introduce any new class. So let us ask ourselves, "Why do we need the classes IPropertyBag and IErrorLog?" Well, IPropertyBag stands for the properties you want to initialize from the htm file. All that it knows is how to read PARAM NAME....VALUE from the object tag . You could have had multiple of PARAM NAME clauses in the htm file and still have them read by this class.
As regards IErrorLog, let us put it off for the time being.
An object v that looks like VARIANT is created and made global.This VARIANT is basically a union and is used because it is large enough to handle all data types.We have initialised the vt member of the union to VT_BSTR which signifies that this variant will be used basically for strings.
The IPropertyBag class has a function called Read.The first parameter to this function is m which is a global variable. Apparently, m is an array of numbers. It is initialised to L"ttt" . The L converts ttt into a format which the IPropertyBag can read. These are basically OLESTRings.
In due course of time we will tell you that the ordinary strings (the 'char *') that C/C++ programmers are used to, have a few problems. The first problem is that the length of the string is not stored along with the string. The second is that the member of the strings are all 1 byte large giving the Chinese / Japanese people a reason to worry. But there are a couple of other patterns of the string -- one being UNICODE (where it is not a single byte but 2 bytes at a time) and second being OLESTRings. We can safely procrastinate the disclosure of the various particulars of OLESTRings, UNICODE and ordinary Strings till later.
The IErrorLog is what you have to give LoadPropertyBag .
The variable m stands for ttt . Hence, all that Read will do is from the htm file pick up the value for ttt (in our case, "hello"). The text hello is stored in strval member of the VARIANT i.e b.strval will have hello.The only problem is that hello is a WIDESTRING and we need to convert it into an ANSISTRING or ASCIISTRING because that is the way we know it. The macro MAKEANSIPTRFROMWIDE will convert the widestring to ANSISTRING. The macro needs a 'char *' to which we have given t and the WIDESTRING which is stored in b.strval . Remember we have not created t . This macro will convert the WIDESTRING hello into an ANSISTRING hello. Then we do a string copy from t to s . In the WindowProc as before when clicked , the value in s will be displayed which is hello.
In this way you can make your program more dynamic by picking up data from htm files.
zzz.cpp
#define INITGUID
#define INITOBJECTS
#include "Internet.h"
#include "Globals.h"
#include "Util.h" 
#include <stdio.h
#include "DibCls.h"
void myaa(char *p)
{
	FILE *fp;
	fp=fopen("d:\\zzz\\z.txt","a+");
	fprintf(fp,"%s..\n",p);
	fclose(fp);
}
DEFINE_GUID(LIBID_wwwobject,0xB92BB5C0L,0x2E73, 0x11CF,0xB6,0xCF,0x00,0xAA,0x00,0xA7,0x4D,0xAF);
DEFINE_GUID(CLSID_www,0xBD11A280L,0x2E73, 0x11CF,0xB6,0xCF,0x00,0xAA,0x00,0xA7,0x4D,0xAF);
class ccc:public CInternetControl,IDispatch
{
public:
	 DECLARE_STANDARD_UNKNOWN();
	 DECLARE_STANDARD_DISPATCH();
	 ccc(IUnknown *);
	 static IUnknown *mycreate(IUnknown *);
	 long _stdcall LoadBinaryState(IStream *)
	 {return 0;}
	 long _stdcall SaveBinaryState(IStream *)
	 {return 0;}
	 long _stdcall LoadTextState(IPropertyBag *, IErrorLog *);
	 long _stdcall SaveTextState(IPropertyBag *, BOOL )
	 {return 0;}
	 long OnData (long,unsigned long, IStream *,unsigned long);
	 virtual long WindowProc(void *, unsigned int, unsigned int, long);
	 long _stdcall OnDraw (HDC, LPCRECTL,LPCRECTL, HDC);
	 virtual BOOL RegisterClassData(void);
	 void ccc::AfterCreateWindow();
} ;
CONTROLOBJECTINFO o={{{&CLSID_www,"wwwCtl",ccc::mycreate},1,0, 0, NULL, 0}, 0,0, 1, "sss", FALSE, 1, 0, 0, 0, NULL } ;
OBJECTINFO g_ObjectInfo[] = {{OI_CONTROL,(void *)&(o)},
							{OI_BOGUS,0},
							{OI_BOGUS,0}
							};
const char g_szLibName[]		= "www";
WNDPROC g_ParkingWindowProc	= NULL;
const short g_fSatelliteLocalization	= FALSE;
const unsigned short g_wszLicenseKey [] = L"";
LCID  g_lcidLocale= MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT);
const CLSID *g_pLibid	= &LIBID_wwwobject;
char a[100];
VARIANT v;
char b[200];
unsigned short m[] = L"PICT";
WNDCLASS d;
CDibFile * f;
CDibSection * j;
HDC dc;
void InitializeLibrary()
{	myaa("InitializeLibrary");
}
void UninitializeLibrary()
{	myaa("UninitializeLibrary");
}
BOOL CheckForLicense()
{	myaa("CheckForLicense");
	return TRUE;
}
BOOL RegisterData()
{	myaa("RegisterData");
	return TRUE;
}
BOOL UnregisterData()
{	myaa("UnregisterData");
	return TRUE;
}
void ccc::AfterCreateWindow()
{	myaa("In AfterCreate Window");
	dc = ::GetDC(m_hwnd); 
}
IUnknown * ccc::mycreate(IUnknown *p)
{
	ccc *c = new ccc(p);
	IUnknown *m_pIUnknown = c-PrivateUnknown();
	sprintf(a,"ccc::Create m_pIUnknown=%p c=%p",m_pIUnknown,c);
	myaa(a);
	return m_pIUnknown;
}
ccc::ccc(IUnknown * p):CInternetControl(p,0,(IDispatch *)this)
{
	myaa("ccc::ccc");
}
BOOL ccc::RegisterClassData()
{
	myaa("ccc::RegisterClassData");
	d.hInstance      = g_hInstance;
	d.lpfnWndProc    = COleControl::ControlWindowProc;
	d.lpszClassName  = "sss";
	return RegisterClass(&d);
}
long ccc::WindowProc(void *w, unsigned int x, unsigned int y, long z)
{
	return DefWindowProc(w,x,y,z);
}
long ccc::LoadTextState(IPropertyBag *m_pIPropertyBag, IErrorLog *m_pIErrorLog)
{	HRESULT h;
	myaa("In Load Text State");
	v.vt = VT_BSTR;
	m_pIPropertyBag-Read(::m, &v, m_pIErrorLog);
	MAKE_ANSIPTR_FROMWIDE(psz,v.bstrVal);
	lstrcpy(b,psz);
	h=SetupDownload(OLESTRFROMANSI(b),102) ;
	sprintf(a,"SetupDownload  %p",h);
	myaa(a);
	return 0;
}
long _stdcall ccc::OnDraw (HDC h, LPCRECTL p,LPCRECTL q, HDC t)
{
	myaa("in ccc::OnDraw");
	j-PaintTo(h,p-left,p-top);
	return 0;
}
                      
long ccc::OnData (long i,unsigned long g, IStream *s,unsigned long  l)
{	myaa("in OnData");
	sprintf(a,"i..%ld..",i);
	myaa(a);
	unsigned int n;
	f = new CDibFile;
	f-GetFileHeader(s);
	f-GetInfoHeader(s);
	j = new CDibSection;
	j-Setup(dc);
	j-Create (*f);
	j-ImageSize(f-CalcImageSize());
	n = (f-HeaderSize() + sizeof(BITMAPFILEHEADER));
	j-ReadFrom(s,l-n) ;
	return 0;
}
zzz.rc
1 TYPELIB zzz.TLB
zzz.odl
#include <olectl.h
[ uuid(b92bb5c0-2e73-11cf-b6cf-00aa00a74daf),lcid(0x0000),version(1.0)]
library wwwobject {
        importlib("STDOLE32.TLB");
        importlib(STDTYPE_TLB);
        importlib("datapath.tlb");
        [uuid(bd11a280-2e73-11cf-b6cf-00aa00a74daf)]
        coclass www {
        [default]         interface IDispatch;
         };
};
zzz.def
LIBRARY         zzz
EXPORTS         DllRegisterServer
EXPORTS		DllUnregisterServer
EXPORTS		DllCanUnloadNow
EXPORTS		DllGetClassObject
zzz.htm
<HTML>
<HEAD>
<TITLE>OLE Control Example</TITLE>
</HEAD>
<BODY>
<CENTER>
HELLO<br>
<OBJECT CLASSID="clsid:{bd11a280-2e73-11cf-b6cf-00aa00a74daf}"
      HEIGHT=234 WIDTH=312>
      <PARAM NAME="ttt" VALUE="hello">
      <PARAM NAME="PICT" VALUE="zzz.bmp">
</OBJECT>
</CENTER>
<HR>
</BODY>
</HTML>
z.txt
InitializeLibrary..
RegisterData..
UninitializeLibrary..
InitializeLibrary..
CheckForLicense..
ccc::ccc..
ccc::Create m_pIUnknown=0046CAC8 c=0046CABC..
In Load Text State..
SetupDownload  00000000..
ccc::RegisterClassData..
In AfterCreate Window..
in OnData..
i..102..
in ccc::OnDraw..
UninitializeLibrary..
Now lets look at the third program (which incidentally has a lot of concepts clubbed together). To begin with, we will display a bitmap. So the PARAM NAME is PICT and the value is zzz.bmp. zzz.bmp is a file on disk. As of now, it resides on my hard disk but it could very well be on the server from where the htm document comes, or any other server anywhere in the world. Now at this point in time, we as programmers, do not know how to pick up a file from the server (because we do not know whether we should use ftp or http or any other protocol for that matter). So we'd rather have Internet Explorer pick up the file for us.
As usual LoadTextState gets called to get the properties from the htm file. b will now stand for zzz.bmp . In LoadTextState, there is a function called Setupdownload which needs an OLESTRing as the first parameter and a number for the second parameter. b is a string in ANSI, which is converted into an OLESTRing. And then we give it some number. SetupDownLoad has been called with zzz.bmp , and we give it a number 102. The number is an identification number to the file , because I can very well use SetupDownLoad a million and one times.Now while these files are being downloaded, they have to be downloaded asynchronously. SetupDownLoad function will then call the OnData function.
In OnData , the first parameter i has the same identification number, i.e. 102 . Irrespective of whether the file is coming from the local machine, or a non-local server, an IStream is basically what you want to do to read/write data in OLE2.0. Furthermore, we have an IStream pointer called s ; the last parameter l stores the length of the file.
The first step is to create an object that looks like CDibFile. CDibFile is a class that deals with bitmaps. The bitmaps are stored on disk as .bmp files. Every bitmap to start with has 3 components to it.
1. The file header;
2. The info header; and
3. The actual bmp data;
So we pass the IStream * s to the GetFileHeader of CDibFile function.Which means we are passing zzz.bmp as s stands for zzz.bmp . Therefore, GetFileHeader will now have the header of zzz.bmp . The same is done for GetInfoHeader . So the first two basically become the file header and the info header. That means some parts from the "Internet disk" have been read and the file pointer is now at the bmp file data. The CDibFile cannot be used directly and all we need is a section of it. So an object that looks like CDibSection has to be created.
In the OnData, the Setup function has to setup the windows device context. After the window has been created, the window device context can be stored. There are two functions which get called during the creation of the window -- BeforeCreateWindow and AfterCreateWindow . In AfterCreateWindow the dc which is a global variable is initialised using m_hwnd (m_hwnd is a number of the window created by the Framework).
The CDibSection needs to setup the DeviceContext to operate in.Then it creates a CDibSection with CDibFile as a parameter given to it.This is because the CDibFile has the information about the file header and the info header.The Imagesize of CDibSection also has to be set to the the imagesize in the header of the CDibFile.So with the CalcImageSize function of the CDibFile, the size of the image can be obtained and the imagesize is set.
Evidently, the file header and the info header have both been read. Which means only the 'actual bmp data' is left to be read. There is a variable n which will have the total number of bytes already read i.e the header size of CDibFile and the bitmap header size. l is the total size of the stream. The file pointer in the stream now points to the bmpdata. With the ReadFrom function in the CDibSection, the remaining part of the stream is read, i.e., it the ReadFrom function that allows us to marshal the location from where we have to start reading the data. OnDraw gets called each time. In the OnDraw , the PaintTo function of CDibSection is called with the DC.
Now where the OCX really is to be displayed is not known.So we use p , which is a parameter to OnDraw . This way we can procure the location of the OCX in the window.The left and top in CRect (p is a pointer to CRect) will be the respective positions where the OCX will be drawn. Now what we have to understand here is that SetupDownLoad is called which makes sure that it is picking up the file. After picking up the file entirely, it will call OnDraw .
Here's a simple old lesson. Whatever we display in LButtonDown (in WindowProc) does not stay unless we don't paint it. Now, OnDraw is equivalent to the Paint. Hence, whatever we wish to have permanantly on the screen, we will have to put it in the OnDraw. The other advantage of OnDraw is it gives you the DC as also the size of the RectStructure.
zzz.cpp
#define INITGUID
#define INITOBJECTS
#include "Internet.h"
#include "Globals.h"
#include "Util.h" 
#include <stdio.h
#include <vfw.h
void myaa(char *p)
{
	FILE *fp;
	fp=fopen("d:\\zzz\\z.txt","a+");
	fprintf(fp,"%s..\n",p);
	fclose(fp);
}
DEFINE_GUID(LIBID_wwwobject,0xB92BB5C0L,0x2E73, 0x11CF,0xB6,0xCF,0x00,
0xAA,0x00,0xA7,0x4D,0xAF);
DEFINE_GUID(CLSID_www,0xBD11A280L,0x2E73, 0x11CF,0xB6,0xCF,0x00,0xAA,
0x00,0xA7,0x4D,0xAF);
class ccc:public CInternetControl,IDispatch
{
public:
	 DECLARE_STANDARD_UNKNOWN();
	 DECLARE_STANDARD_DISPATCH();
	 ccc(IUnknown *);
	 static IUnknown *mycreate(IUnknown *);
	 long _stdcall LoadBinaryState(IStream *)
	 {return 0;}
	 long _stdcall SaveBinaryState(IStream *)
	 {return 0;}
	 long _stdcall LoadTextState(IPropertyBag *, IErrorLog *);
	 long _stdcall SaveTextState(IPropertyBag *,BOOL)
	 {return 0;}
	 long OnData (long,unsigned long,IStream *,unsigned long)
	 {return 0;};
	 virtual long WindowProc(void *, unsigned int, unsigned int,long);
	 long _stdcall OnDraw (HDC,LPCRECTL,LPCRECTL,HDC)
	 {return 0;};
	 virtual BOOL RegisterClassData(void);
} ;
CONTROLOBJECTINFO o={{{&CLSID_www,"wwwCtl",ccc::mycreate},1,0, 0, 
NULL, 0}, 0,0, 1, "sss", FALSE, 1, 0, 0, 0, NULL } ;
OBJECTINFO g_ObjectInfo[] = {{OI_CONTROL,(void *)&(o)},
					{OI_BOGUS,0},
					{OI_BOGUS,0}
					};
WNDCLASS d;
const char g_szLibName[]	= "www";
WNDPROC g_ParkingWindowProc	= NULL;
const short g_fSatelliteLocalization	= FALSE;
const unsigned short g_wszLicenseKey[] 	= L"";
LCID  g_lcidLocale	= MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT);
const CLSID *g_pLibid	= &LIBID_wwwobject;
char a[100],b[200];
VARIANT v;
unsigned short m [] = L"AVIFILE";
HWND wd;
void InitializeLibrary()
{	myaa("InitializeLibrary");
}
void UninitializeLibrary()
{	myaa("UninitializeLibrary");
}
BOOL CheckForLicense()
{	myaa("CheckForLicense");
	return TRUE;
}
BOOL RegisterData()
{	myaa("RegisterData");
	return TRUE;
}
BOOL UnregisterData()
{	myaa("UnregisterData");
	return TRUE;
}
IUnknown * ccc::mycreate(IUnknown *p)
{
	ccc *c = new ccc(p);
	IUnknown *m_pIUnknown = c-PrivateUnknown();
	sprintf(a,"ccc::Create m_pIUnknown=%p c=%p",m_pIUnknown,c);
	myaa(a);
	return m_pIUnknown;
}
ccc::ccc(IUnknown * p):CInternetControl(p,0,(IDispatch *)this)
{
	myaa("ccc::ccc");
}
BOOL ccc::RegisterClassData()
{
	myaa("ccc::RegisterClassData");
	d.hInstance      = g_hInstance;
	d.lpfnWndProc    = COleControl::ControlWindowProc;
	d.lpszClassName  = "sss";
	return RegisterClass(&d);
}
long ccc::LoadTextState(IPropertyBag *m_pIPropertyBag,IErrorLog *m_pIErrorLog)
{ 
	HRESULT h;
	myaa("In Load Text State");
	v.vt = VT_BSTR;
	m_pIPropertyBag-Read(::m, &v,m_pIErrorLog);
	MAKE_ANSIPTR_FROMWIDE(psz,v.bstrVal);
	lstrcpy(b,psz);
	return 0;
}
long ccc::WindowProc(void * w, unsigned int x, unsigned int y, long z)
{
	 if (x == WM_LBUTTONDOWN)
	 {
		myaa(b);
		wd=MCIWndCreate(w,g_hInstance,0,b);
		MCIWndPlay(wd);
	 }
	return DefWindowProc(w,x,y,z);	
}
zzz.rc
1 TYPELIB zzz.TLB
zzz.odl
#include >olectl.h
[ uuid(b92bb5c0-2e73-11cf-b6cf-00aa00a74daf),lcid(0x0000),version(1.0)]
library wwwobject {
        importlib("STDOLE32.TLB");
        importlib(STDTYPE_TLB);
        importlib("datapath.tlb");
        [uuid(bd11a280-2e73-11cf-b6cf-00aa00a74daf)]
        coclass www {
        [default]         interface IDispatch;
         };
};
zzz.def
LIBRARY         zzz
EXPORTS         DllRegisterServer
EXPORTS		DllUnregisterServer
EXPORTS		DllCanUnloadNow
EXPORTS		DllGetClassObject
zzz.htm|
<HTML>
<HEAD>
<TITLE>OLE Control Example</TITLE>
</HEAD>
<BODY>
<CENTER>
HELLO<br>
<OBJECT CLASSID="clsid:{bd11a280-2e73-11cf-b6cf-00aa00a74daf}"
      HEIGHT=234 WIDTH=312>
      <PARAM NAME="ttt" VALUE="hello">
      <PARAM NAME="PICT" VALUE="zzz.bmp">
      <PARAM NAME="AVIFILE" VALUE="bbohyeah.avi">
</OBJECT>
</CENTER>
<HR>
</BODY>
</HTML>
z.txt
InitializeLibrary..
RegisterData..
UninitializeLibrary..
InitializeLibrary..
CheckForLicense..
ccc::ccc..
ccc::Create m_pIUnknown=0048E658 c=0048E64C..
In Load Text State..
ccc::RegisterClassData..
bbohyeah.avi..
UninitializeLibrary..
In the project settings vfw32.lib is to be added to the Library/Object module. In this last example, we are displaying an avi file. Naturally this time we will only use OnData because if the avi file is present on my local hard disk, then I don't have to worry about downloading it from the net. Using SetUpDownLoad I could have brought the entire file from the server. It is subject to individual decision that the file is to be played after it has been downloaded entirely or is played concurrently as it is being downloaded, a chunk at a time.
Unfortunately, for an avi file, there happens to be no class available (like CDibFile or CDibSection) as yet, but nothing stops us from writing code for an avi file as we have done for a bmp file because its file structure is known. It is a structure, so instead of waiting for the entire file to arrive, we could have written a class would pick it up and keep displaying while the file is being downloaded.
The apparent point here is : OCX certainly scores over Java. Anyone who has Windows95 installed on his machine, has dlls and one of it has the code for playing an avi file. So the code for playing does not have to come across the Internet.What has to come across is the avi file. At this point in time, one would not really like to figure out a neat way of downloading a file from the Internet. So the next logical alternative is that he can use OnData . The OnData will give him an IStream which will stand for the file. All that remains to be done is actually picking up the data of the file and then simply displaying it.
Back to the vagaries of the Digital Black-OLE, the main tutorial. If not yet tired, grab a coke and HEAD FOR the rest of the story...
Have any suggestions, comments, ideas, cracked code, feed back ? Feel free to let us know .
Want to be in touch with still more latest technologies? Visit VIJAY MUKHI'S TECHNOLOGY CORNUCOPIA .
Vijay Mukhi's Computer Institute 
B-13, Everest Building, Tardeo, Mumbai 400 034, India. 
 http://www.vijaymukhi.com            
e-mail :vmukhi@giasbm01.vsnl.net.in 
Tel : 91-22-496 4335 /6/7/9 
Fax : 91-22-307 28 59