Link to home
Start Free TrialLog in
Avatar of moshem
moshem

asked on

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
Avatar of PlanetCpp
PlanetCpp

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>"

Avatar of moshem

ASKER

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);
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.
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)
Avatar of moshem

ASKER

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 ?
Avatar of moshem

ASKER

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 ?
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.
Avatar of moshem

ASKER

can you share your project files? I will complile it as it
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.
Avatar of moshem

ASKER

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!
Avatar of moshem

ASKER

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 ?

you wrote a win32 api program,,the whole thing won't work in another OS.
Avatar of moshem

ASKER

I meant another Windows OS
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.
Avatar of moshem

ASKER

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?
ASKER CERTIFIED SOLUTION
Avatar of PlanetCpp
PlanetCpp

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of moshem

ASKER

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!
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.
Avatar of moshem

ASKER

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
navigate2 would do that
when you get the pointer to the control and the interface pointer you can control it much better
Avatar of moshem

ASKER

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!
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.
Avatar of moshem

ASKER

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!
Avatar of moshem

ASKER

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 ?
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
Avatar of moshem

ASKER

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);
     }