Adding HTML Control to Visual C++ program

Hi

I wrote a C++ software that displays text with links, I used richedit control fot this.

I now want to "upgrade" to HTML based control, but I can't find a way to do it unless I use MFC or ATL.

my software is Win32 API only. I need to use internet explorer HTML control (the lightest version since I want to keep my software small and compact).

can someone show me the way or even better share a Visual studio sample project ?


thanks
LVL 1
moshemAsked:
Who is Participating?
 
PlanetCppConnect With a Mentor Commented:
when your using MFC they make this pretty easy. you can use simple message maps. you can't use them (as far as i know) in win32 cause you need to have created that class with one of a few class objects that MSDN mentions.
you pass it to BEGIN_MSG_MAP
i never really saw i nice defined way to get the messages and trying to use the WM_COMMAND method like you do with buttons doesn't work so what i did when i wanted messages was change the window proc to one of my own. it's simple really.
globally define a wndproc variable to ghold the old windowoe procedure address that was given to the browser window
WNDPROC oldwndproc;

then after you create the browser use:
oldwndproc = (WNDPROC)SetWindowLong(browserwindow,GWL_WNDPROC,(long)BrowserProc);
you had to have made a function for this called BrowserProc (or whatever you want)

LRESULT CALLBACK BrowserProc(HWND ahWnd,UINT aiMsg,WPARAM awParam,LPARAM alParam)
{
     switch(aiMsg)
     {
     case WM_PAINT:
          SetWindowText(mainwindow,"painted browser");
          break;
     };

     return CallWindowProc(oldwndproc,ahWnd,aiMsg,awParam,alParam);
}
now all the messages will go through BrowserProc first
i know that was the dumbest example with WM_PAINT but its 3:30am :o\ and im more then certain you understand
0
 
PlanetCppCommented:
You canadd a brwser control to a WIN32 API program using ATL, you dont have to change anything at all besides adding some code. no stupid wizards or dialogs. if the reason you don't want to use ATL is cause it complicates it when people use other compilers then this is no good for you but if not then here:
first you need to include a header and link to a lib, i use #pragma to link to libs but you can just use the project settings if you want to:

#include <atlbase.h>
#pragma comment(lib,"atl.lib")//or add atl.lib to project libs

then in wm_create or winmain:
//INIT ATL FOR BROWSER
AtlAxWinInit();

then tada!:

browser = CreateWindowEx(NULL,"AtlAxWin","http://www.PlanetCpp.com",WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL,0,0,447,295,parenthwnd,NULL,hInstance,NULL);


and thats all, that's only to show stuff if you want to add more functionality you'll have to look up how to do that with atlaxwin, i only used it to show html code a program i wrote generated.
to show raw html you need to prefix the html with MSHTML:
so you can pass it "MSHTML:<b>Hello World</b>"

0
 
moshemAuthor Commented:
I tried it, but it does not work, browser window fails to create.

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }


bool b = false;

b=AtlAxWinInit();

HWND browser =
          CreateWindowEx(NULL,"AtlAxWin","http://www.PlanetCpp.com",
          WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL,0,0,447,295,
          hWnd,NULL,hInstance,NULL);

   ShowWindow(browser, nCmdShow);
   UpdateWindow(browser);

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
PlanetCppCommented:
i just made a program from scratch and it works, i don't know what you did, make sure the lib is included, header and you aso don't need to use ShowWindow on it, i used WS_VISIBLE in the style.
the window isn't showing at all? sounds like you didn't include what was needed.
0
 
PlanetCppCommented:
also is the createwindow code for atlaxwin in winmain? if not you have to use your global hinstance variable you might have overlooked that. better to just get the hinstance each time, theres other methods but i use
(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE)
0
 
moshemAuthor Commented:
I did exactly that... I created a new project with a Win32 skeletlton (Visual Studio.net), then added :

first the includes:

#pragma comment(lib, "atl.lib")

#include <atlbase.h>

then winmain :

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
      // TODO: Place code here.
     MSG msg;
     HACCEL hAccelTable;

     // Initialize global strings
     LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
     LoadString(hInstance, IDC_DISPLAYHTML, szWindowClass, MAX_LOADSTRING);
     MyRegisterClass(hInstance);

     // Perform application initialization:
     if (!InitInstance (hInstance, nCmdShow))
     {
          return FALSE;
     }

     hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_DISPLAYHTML);


     bool b = false;

b=AtlAxWinInit();

// this fails

HWND browser =
CreateWindowEx(NULL,"AtlAxWin","http://www.google.com",
          WS_OVERLAPPEDWINDOW|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL,0,0,447,295,
          0,NULL,hInstance,NULL);








     // Main message loop:
     while (GetMessage(&msg, NULL, 0, 0))
     {
          if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
          {
               TranslateMessage(&msg);
               DispatchMessage(&msg);
          }
     }

     return (int) msg.wParam;
}



What is wrong ?
0
 
moshemAuthor Commented:
sorry, one line got replaced, this is how I do it:

HWND browser =
CreateWindowEx(NULL,"AtlAxWin","http://www.google.com",
          WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL,0,0,447,295,
          hWnd,NULL,hInstance,NULL);


now, what am I doing wrong ?
0
 
PlanetCppCommented:
i don't know, only differences is i use vs 6 and i dont have it create a skeleton i just write it out. that shouldn't be a problem, i don't know why it won't work for you, i'm not doing anything special and it's only like 3 lines of code. not much to go on.
0
 
moshemAuthor Commented:
can you share your project files? I will complile it as it
0
 
PlanetCppCommented:
email me at Hound@PlanetCpp.com and ill zip it up and mail it. ill be back a little later. if ti doesnt work after that then it's definately a .NET thing.
0
 
moshemAuthor Commented:
I got your project and your executable works fine for me, I tried to compile the project using Visual Studio.NET and it compiled but when I run it, it exhibit the exact same problems I saw with my own program, meaning, it does not work!

any ideas what I need to change in order for it to work with the latest version of the compiler?

thanks!
0
 
moshemAuthor Commented:
Ok, I figured it out, I changed the window class name to "AtlAxWin7" instead of AtlAxWin" and it works.

the question is will it also work with other OS ?

0
 
PlanetCppCommented:
you wrote a win32 api program,,the whole thing won't work in another OS.
0
 
moshemAuthor Commented:
I meant another Windows OS
0
 
PlanetCppCommented:
shouldn't be a problem at all
i just read an MSDN article saying that in .NET atlaxwin was renamed to atlaxwin7, from what i read it didn't say why.
0
 
moshemAuthor Commented:
Ok, one last question, how do I recieve events from the Atl window? can you write a few lines of sample code here or send me to a link?
0
 
moshemAuthor Commented:
thanks, but I meants more control specific events...

I'll give you the points, you were more than helpfull, if you can be more specific as for object events and can post it here, I'll be very glad.


thanks!
0
 
PlanetCppCommented:
i didn't know you wanted to use this as a fully functional web browser. i usually use it to display one thing, maybe some html.
just make a small change, make the startup text "Shell.Explorer.1" instead of a webpage.
now the rest i can only point you in the right direction cause i havent played with it much.
you need to create an IUnknown
IUnknown *pUnk;
then use
AtlAxGetControl(browserwindow,pUnk);
then you need to make a CComPtr
CComPtr browserPtr
then through the iunknown you have to call QueryInterface
pUnk->QueryInterface(IID_IWebBrowser2,(void**)&browserPtr);
i'm not 100% sure just using -> will be ok, the compiler might not know what it's dereferencing, but try it.
if you got anything but NULL in browserPtr then your good to go
from there the only command i know of is Navigate2
browserPtr->Navigate2(..im not sure of the parametrs)
for more info lookup the functions i wrote and also
CComVariant - youll need to pass this type to functions
i'm sure it's not hard i just never played with it yet.
0
 
moshemAuthor Commented:
Hi,

if I can impose one more question, how can I reset the source of the explorer window, if I want display HTML using MSHTML: and later change the HTML without destroying the control and recreating it, how would I do that?

thanks
0
 
PlanetCppCommented:
navigate2 would do that
when you get the pointer to the control and the interface pointer you can control it much better
0
 
moshemAuthor Commented:
yeah, I tried to get the pointer but it keeps failing!

do you have a code snippet?

BTW, I only need to change the HTML each time or to add to the exisitng HTML (push into the top). I have no need for it to navigate to a site.

I tried using SetWindowText, but it does nothing!
0
 
PlanetCppCommented:
i just did the happy dance! i scoured MSDN for 10 minutes and found bits and peices of info on this and put it all together and im very surprised that it worked lol
here is how to use Navigate2 (i really suggest you do what im going to do now which is so find more info, i might be using something and not releasing it or something like that)
add <exdisp.h> to your includes first off
i keep seeing one called <mshtml.h> but so far ive needed nothing from it
after you create the browser window

HWND browser =
CreateWindowEx(NULL,"AtlAxWin","http://www.google.com",
         WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL,0,0,400,300,
         hWnd,NULL,hInstance,NULL);

IUnknown *pUnk = NULL;
//i had to fight with this next line to get it right
AtlAxGetControl(browser,(IUnknown**)&pUnk);
if(pUnk == NULL)
     MessageBox(0,"can't get pointer","error",MB_OK); //might want to exit too
//this is instead of CComPtr, it looks more appropriate to use in this case
IWebBrowser2 *iweb = NULL;

pUnk->QueryInterface(IID_IWebBrowser2,(void**)&iweb);
pUnk->Release();//iweb is what we want now
if(iweb)
{
CComVariant ccv,ccvurl("http://www.PlanetCpp.com");
     iweb->put_Visible(VARIANT_TRUE);
     iweb->Navigate2(&ccvurl,&ccv,&ccv,&ccv,&ccv);
}

that's all hopefully it's no different in .NET
i changed it form "Shell.Explorer.1" to any site cause,,well you'll see why it makes scrollbars double up for some reason.
0
 
moshemAuthor Commented:
that's great, it actually works, but the damn thing won't work with custom HTML (using MSHTML:) anymore! and that is what I need, damn!
0
 
moshemAuthor Commented:
Ok, I tried creating the window with a MSHTML string,

then changed your code to:

IUnknown *pUnk = NULL;
//i had to fight with this next line to get it right
AtlAxGetControl(browser,(IUnknown**)&pUnk);
if(pUnk == NULL)
    MessageBox(0,"can't get pointer","error",MB_OK); //might want to exit too
//this is instead of CComPtr, it looks more appropriate to use in this case
IHTMLDocument2 *iweb = NULL;

pUnk->QueryInterface(IID_IHTMLDocument2,(void**)&iweb);
pUnk->Release();//iweb is what we want now
if(iweb)
{
     CComVariant ccv,ccvurl("mshtml:<html><body><b>hi</b></body></html>");
//    iweb->put_Visible(VARIANT_TRUE);
  //  iweb->Navigate2(&ccvurl,&ccv,&ccv,&ccv,&ccv);

     iweb->write
     
}

and it works, just that iweb->write, expects SAFEARRAY, you don't know how to hand it a string, don't you ?
0
 
PlanetCppCommented:
id have to look around to figure that out it seems wierd
try using a local htm file, thats what i use on one of my programs, i keep opening a tmp.htm in my programs directory and i change it when needed. i dont use the navigate2 method but it should work
0
 
moshemAuthor Commented:
this works, writing into a file is one option, but a clumsy one. dynamic updating would be much nicer...

this works, but now I need to pass it dynamic string, one that takes char* or std::string...

HRESULT hresult = S_OK;
     VARIANT *param;
     SAFEARRAY *sfArray;
     BSTR bstr = SysAllocString (OLESTR("hi"));

     // Creates a new one-dimensional array
     sfArray = SafeArrayCreateVector(VT_VARIANT, 0, 1);
     
     if (sfArray == NULL || iweb == NULL) {
          goto cleanup;
     }

     hresult = SafeArrayAccessData(sfArray,(LPVOID*) & param);
     param->vt = VT_BSTR;
     param->bstrVal = bstr;
     hresult = SafeArrayUnaccessData(sfArray);
     hresult = iweb->write(sfArray);

cleanup:
     SysFreeString(bstr);
     if (sfArray != NULL) {
          SafeArrayDestroy(sfArray);
     }
0
All Courses

From novice to tech pro — start learning today.