?
Solved

Adding HTML Control to Visual C++ program

Posted on 2003-02-28
26
Medium Priority
?
1,993 Views
Last Modified: 2013-12-14
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
0
Comment
Question by:moshem
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 14
  • 12
26 Comments
 
LVL 6

Expert Comment

by:PlanetCpp
ID: 8046770
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
 
LVL 1

Author Comment

by:moshem
ID: 8047102
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
 
LVL 6

Expert Comment

by:PlanetCpp
ID: 8048632
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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 6

Expert Comment

by:PlanetCpp
ID: 8048651
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
 
LVL 1

Author Comment

by:moshem
ID: 8049182
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
 
LVL 1

Author Comment

by:moshem
ID: 8049195
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
 
LVL 6

Expert Comment

by:PlanetCpp
ID: 8049299
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
 
LVL 1

Author Comment

by:moshem
ID: 8049309
can you share your project files? I will complile it as it
0
 
LVL 6

Expert Comment

by:PlanetCpp
ID: 8049428
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
 
LVL 1

Author Comment

by:moshem
ID: 8084626
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
 
LVL 1

Author Comment

by:moshem
ID: 8084724
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
 
LVL 6

Expert Comment

by:PlanetCpp
ID: 8084907
you wrote a win32 api program,,the whole thing won't work in another OS.
0
 
LVL 1

Author Comment

by:moshem
ID: 8086443
I meant another Windows OS
0
 
LVL 6

Expert Comment

by:PlanetCpp
ID: 8086494
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
 
LVL 1

Author Comment

by:moshem
ID: 8086517
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
 
LVL 6

Accepted Solution

by:
PlanetCpp earned 1200 total points
ID: 8086738
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
 
LVL 1

Author Comment

by:moshem
ID: 8086798
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
 
LVL 6

Expert Comment

by:PlanetCpp
ID: 8086918
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
 
LVL 1

Author Comment

by:moshem
ID: 8089199
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
 
LVL 6

Expert Comment

by:PlanetCpp
ID: 8090731
navigate2 would do that
when you get the pointer to the control and the interface pointer you can control it much better
0
 
LVL 1

Author Comment

by:moshem
ID: 8090754
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
 
LVL 6

Expert Comment

by:PlanetCpp
ID: 8090980
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
 
LVL 1

Author Comment

by:moshem
ID: 8091044
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
 
LVL 1

Author Comment

by:moshem
ID: 8091088
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
 
LVL 6

Expert Comment

by:PlanetCpp
ID: 8091233
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
 
LVL 1

Author Comment

by:moshem
ID: 8091268
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

Featured Post

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
Jaspersoft Studio is a plugin for Eclipse that lets you create reports from a datasource.  In this article, we'll go over creating a report from a default template and setting up a datasource that connects to your database.
The viewer will learn how to use NetBeans IDE 8.0 for Windows to connect to a MySQL database. Open Services Panel: Create a new connection using New Connection Wizard: Create a test database called eetutorial: Create a new test tabel called ee…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
Suggested Courses

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question