Board index » cppbuilder » Re: Opening up Web Browsers inside my App

Re: Opening up Web Browsers inside my App


2005-06-06 07:56:25 AM
cppbuilder0
"Gav" < XXXX@XXXXX.COM >wrote in message
Quote
So now I have CreateProcess opening up the chosen web
browser(s) no problem - trouble is I can not give it any
arguments - I can not specify which web site to open up to
Yes, you can. That is what the lpCommandLine parameter of CreateProcess()
is for.
Quote
I am now doing it like this (GetDefaultBrowser function defined earlier)
:-
Your code is not using the command line properly. Use one of the following
approaches instead:
void __fastcall TMDIChild1::ITimageClick(TObject *Sender)
{
char DefaultBrowser[MAX_PATH+1] = {0};
MDIChild2->GetDefaultBrowser(DefaultBrowser);
STARTUPINFO si = {sizeof(STARTUPINFO), 0};
PROCESS_INFORMATION pi = {0};
AnsiString CmdLine = (AnsiQuotedStr(DefaultBrowser, '"') + " " +
AnsiQuotedStr("www.minitutorials.com", '"'));
if( ::CreateProcess(DefaultBrowser, CmdLine.c_str(), NULL, NULL,
FALSE, 0, NULL, NULL, &si, &pi) )
{
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);
}
}
Or:
void __fastcall TMDIChild1::ITimageClick(TObject *Sender)
{
char DefaultBrowser[MAX_PATH+1] = {0};
MDIChild2->GetDefaultBrowser(DefaultBrowser);
STARTUPINFO si = {sizeof(STARTUPINFO), 0};
PROCESS_INFORMATION pi = {0};
AnsiString CmdLine = (AnsiQuotedStr(DefaultBrowser, '"') + " " +
AnsiQuotedStr("www.minitutorials.com", '"'));
if( ::CreateProcess(NULL, CmdLine.c_str(), NULL, NULL, FALSE, 0,
NULL, NULL, &si, &pi) )
{
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);
}
}
Quote
Assuming CreateProcess() is working , which it is to a point, how do
I then locate the process as it starts and redirect it (dock it) into my
application inside a tabbed page or form.?
You have to loop through every running window, looking for the one that
belongs to the new process you just spawned. Use EnumWindows() and
GetWindowThreadProcessId() for that, using the process ID that
CreateProcess() returned in the PROCESS_INFORMATION structure. For example:
struct MyInfo
{
DWORD dwProcessId;
HWND hWnd;
};
BOOL CALLBACK FindBrowser(HWND hwnd, LPARAM lParam)
{
MyInfo *info = reinterpret_cast<MyInfo*>(lParam);
DWORD dwProcessId = 0;
::GetWindowThreadProcessId(hwnd, &dwProcessId);
if( dwProcessId == info->dwProcessId )
{
info->hWnd = hwnd;
return FALSE;
}
return TRUE;
}
if( ::CreateProcess(...) )
{
MyInfo info = {pi.dwProcessId, NULL};
::EnumWindows((WNDENUMPROC)FindBrowser,
reinterpret_cast<LPARAM>(&info));
if( info.hWnd != NULL )
// use info.hWnd as needed...
}
Gambit
 
 

Re:Re: Opening up Web Browsers inside my App

Gambit and Bob,
Problem 1 solved thanks to you both,
Problem 2 being worked on now, thanks for your excellent guidance on that
too Gambit.
Gav...
 

Re:Re: Opening up Web Browsers inside my App

Apologies for appearing thick Gambit, but I am getting errors,
Improper use of typedef BOOL
Statement missing ; (on BOOL line)
Undefined symbol FindBrowser.
So I have to ask then, where do I put the example code below
and do I need to alter it in anyway ?
Thanks
Gav...
Earlier Gambit wrote :-
You have to loop through every running window, looking for the one that
belongs to the new process you just spawned. Use EnumWindows() and
GetWindowThreadProcessId() for that, using the process ID that
CreateProcess() returned in the PROCESS_INFORMATION structure. For example:
struct MyInfo
{
DWORD dwProcessId;
HWND hWnd;
};
BOOL CALLBACK FindBrowser(HWND hwnd, LPARAM lParam)
{
MyInfo *info = reinterpret_cast<MyInfo*>(lParam);
DWORD dwProcessId = 0;
::GetWindowThreadProcessId(hwnd, &dwProcessId);
if( dwProcessId == info->dwProcessId )
{
info->hWnd = hwnd;
return FALSE;
}
return TRUE;
}
if( ::CreateProcess(...) )
{
MyInfo info = {pi.dwProcessId, NULL};
::EnumWindows((WNDENUMPROC)FindBrowser,
reinterpret_cast<LPARAM>(&info));
if( info.hWnd != NULL )
// use info.hWnd as needed... <== Something like :-
::SetParent ( info.hWnd, PagesDlg->TabSheet2->Handle );
PagesDlg->Show();
}
 

{smallsort}

Re:Re: Opening up Web Browsers inside my App

"Gav" < XXXX@XXXXX.COM >wrote in message
Quote
Improper use of typedef BOOL
Statement missing ; (on BOOL line)

Undefined symbol FindBrowser.
The code I gave you is a standalone function, and needs to be used as such.
It sounds like you probably put the code inside your ITimageClick() code
directly, which you cannot do. It should be more like this instead:
struct MyInfo
{
DWORD dwProcessId;
HWND hWnd;
};
BOOL CALLBACK FindBrowser(HWND hwnd, LPARAM lParam)
{
MyInfo *info = reinterpret_cast<MyInfo*>(lParam);
DWORD dwProcessId = 0;
::GetWindowThreadProcessId(hwnd, &dwProcessId);
if( dwProcessId == info->dwProcessId )
{
info->hWnd = hwnd;
return FALSE;
}
return TRUE;
}
void __fastcall TMDIChild1::ITimageClick(TObject *Sender)
{
char DefaultBrowser[MAX_PATH+1] = {0};
MDIChild2->GetDefaultBrowser(DefaultBrowser);
STARTUPINFO si = {sizeof(STARTUPINFO), 0};
PROCESS_INFORMATION pi = {0};
AnsiString CmdLine = (AnsiQuotedStr(DefaultBrowser, '"') + " " +
AnsiQuotedStr("www.minitutorials.com", '"'));
if( ::CreateProcess(NULL, CmdLine.c_str(), NULL, NULL, FALSE, 0,
NULL, NULL, &si, &pi) )
{
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);
MyInfo info = {pi.dwProcessId, NULL};
::EnumWindows((WNDENUMPROC)FindBrowser,
reinterpret_cast<LPARAM>(&info));
if( info.hWnd != NULL )
// use info.hWnd as needed...
}
}
Gambit
 

Re:Re: Opening up Web Browsers inside my App

"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote
The code I gave you is a standalone function, and needs to be used as
such.
It sounds like you probably put the code inside your ITimageClick() code
directly, which you cannot do. It should be more like this instead:
Thanks, I thought I had tried it as below but must have misplaced it
inside/outside a {or } somewhere.
I am no longer getting error messages, however, the last trick to the puzzle
is eluding me still, I thought I just
had to use SetParent to a Form or Tab and that the Browser would open up
inside that form, but it is not
happening.
My code is as yours below with the additions below your " // use info.hWnd
as needed..."
Quote

struct MyInfo
{
DWORD dwProcessId;
HWND hWnd;
};

BOOL CALLBACK FindBrowser(HWND hwnd, LPARAM lParam)
{
MyInfo *info = reinterpret_cast<MyInfo*>(lParam);
DWORD dwProcessId = 0;
::GetWindowThreadProcessId(hwnd, &dwProcessId);
if( dwProcessId == info->dwProcessId )
{
info->hWnd = hwnd;
return FALSE;
}
return TRUE;
}

void __fastcall TMDIChild1::ITimageClick(TObject *Sender)
{
char DefaultBrowser[MAX_PATH+1] = {0};
MDIChild2->GetDefaultBrowser(DefaultBrowser);

STARTUPINFO si = {sizeof(STARTUPINFO), 0};
PROCESS_INFORMATION pi = {0};

AnsiString CmdLine = (AnsiQuotedStr(DefaultBrowser, '"') + " " +
AnsiQuotedStr("www.minitutorials.com", '"'));
if( ::CreateProcess(NULL, CmdLine.c_str(), NULL, NULL, FALSE, 0,
NULL, NULL, &si, &pi) )
{
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);

MyInfo info = {pi.dwProcessId, NULL};
::EnumWindows((WNDENUMPROC)FindBrowser,
reinterpret_cast<LPARAM>(&info));
if( info.hWnd != NULL )
// use info.hWnd as needed...
::SetParent ( info.hWnd, Form4->Handle );
Form4->Show();
Quote
}
}
What happens is when the ITImageClick button is pressed, the DefaultBrowser
is found and executed
with the chosen URL no problems, but it is still doing this externally and
not in the Form4 (or tabbed page)
as I would like.
Having checked , the result of the if( info.hWnd != NULL ) statement is NULL
because the code inside it
does not get executed. In addition, placing the code outside the if
statement makes Form4 appear as it should
but the Browser is still not appearing there but externally as usual.
Is there something else I have missed?
Having never used window properties and SetParent much I have been
frantically researching it all and
trying different things but have not yet seen where I am going wrong.
Thanks
Gav...
 

Re:Re: Opening up Web Browsers inside my App

I am guessing here I need to add a WaitForInputIdle(CreateProcess , 1000);
or similar, I am experimenting the best place to put it, I got it to work
once but
changed it and it hasn't worked since .
I'll get there I'm sure :)
Gav...
 

Re:Re: Opening up Web Browsers inside my App

Ok, Looks like I got it :)
So I needed to experiment and change the values of the WaitForInputIdle
integer and also
combine that with the smallest Sleep(n) I worked out so that if( info.hWnd
!= NULL ) became true,
for an IE window that was Sleep(150).
Is there a concrete formulae I should have used or does everyone experiment
with timing in this case?
Thanks Guys,
Gav...(Phew!)
"Gav" < XXXX@XXXXX.COM >wrote in message
Quote
I am guessing here I need to add a WaitForInputIdle(CreateProcess , 1000);

or similar, I am experimenting the best place to put it, I got it to work
once but
changed it and it hasn't worked since .

I'll get there I'm sure :)

Gav...

 

Re:Re: Opening up Web Browsers inside my App

Spoke to soon,
Only works sometimes using this method,
any other ideas ?
Thanks
Gav...
"Gav" < XXXX@XXXXX.COM >wrote in message
Quote
Ok, Looks like I got it :)

So I needed to experiment and change the values of the WaitForInputIdle
integer and also
combine that with the smallest Sleep(n) I worked out so that if(
info.hWnd != NULL ) became true,
for an IE window that was Sleep(150).

Is there a concrete formulae I should have used or does everyone
experiment with timing in this case?

Thanks Guys,

Gav...(Phew!)


"Gav" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...
>I am guessing here I need to add a WaitForInputIdle(CreateProcess , 1000);
>
>or similar, I am experimenting the best place to put it, I got it to work
>once but
>changed it and it hasn't worked since .
>
>I'll get there I'm sure :)
>
>Gav...
>


 

Re:Re: Opening up Web Browsers inside my App

"Gav" < XXXX@XXXXX.COM >wrote in message
Quote
So I needed to experiment and change the values of the
WaitForInputIdle integer and also combine that with the
smallest Sleep(n) I worked out so that if( info.hWnd
!= NULL ) became true, for an IE window that was Sleep(150).
You do not need to use Sleep() if you are using WaitForInputIdle()
Gambit
 

Re:Re: Opening up Web Browsers inside my App

"Gav" < XXXX@XXXXX.COM >wrote in message
Quote
Spoke to soon,

Only works sometimes using this method,

any other ideas ?
Please show your latest code.
Gambit
 

Re:Re: Opening up Web Browsers inside my App

Hi Gambit,
Quote
Please show your latest code.


Gambit
No problem, from the top in case any headers may be missing I have :-
#include <vcl.h>
#pragma hdrstop
#include <Registry.hpp>
#include "MTB2Child1.h"
#include "MTB2Child3.h"
#include "MTBconversion2.h"
#include "MTB2conversion.h"
#include "Main.h"
#include "windows.h"
#include "shellapi.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "ChildWin"
#pragma resource "*.dfm"
TMDIChild1 *MDIChild1;
struct MyInfo
{
DWORD dwProcessId;
HWND hWnd;
};
BOOL CALLBACK FindBrowser(HWND hwnd, LPARAM lParam)
{
MyInfo *info = reinterpret_cast<MyInfo*>(lParam);
DWORD dwProcessId = 0;
::GetWindowThreadProcessId(hwnd, &dwProcessId);
if( dwProcessId == info->dwProcessId )
{
info->hWnd = hwnd;
return FALSE;
}
return TRUE;
}
//---------------------------------------------------------------------------
__fastcall TMDIChild1::TMDIChild1(TComponent* Owner)
: TMDIChild(Owner)
{
.....
.....
void __fastcall TMDIChild1::ITimageClick(TObject *Sender)
{
char DefaultBrowser[MAX_PATH+1] = {0};
MDIChild2->GetDefaultBrowser(DefaultBrowser);
STARTUPINFO si = {sizeof(STARTUPINFO), 0};
PROCESS_INFORMATION pi = {0};
AnsiString CmdLine = (AnsiQuotedStr(DefaultBrowser, '"') + " " +
AnsiQuotedStr("www.minitutorials.com", '"'));
if( ::CreateProcess(NULL, CmdLine.c_str(), NULL, NULL, FALSE, 0,
NULL, NULL, &si, &pi) )
{
WaitForInputIdle(CreateProcess, 200);
Sleep(175);
//WaitForInputIdle; <- ??
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);
MyInfo info = {pi.dwProcessId, NULL};
::EnumWindows((WNDENUMPROC)FindBrowser,reinterpret_cast<LPARAM>(&info));
if( info.hWnd != NULL )
{
::SetParent ( info.hWnd, Form4->Handle );
Form4->Show();
}
}
}
....
....
....
}
The above code does do what I want it to do but only sometimes.
I have had to experiment with the values of
WaitForInputIdle(CreateProcess, 200);
Sleep(175);
Sometimed changing 200 to 220 or 230 or 250 also works when the current
value fails. INFINITE does not work.
Strange I know but it will not work at all ever if the Sleep(175); is not in
there.
175 seems the optimal minimal value that works (i.e. 174 will not work)
Without the Sleep then this if statement does not execute.
if( info.hWnd != NULL )
{
::SetParent ( info.hWnd, Form4->Handle );
Form4->Show();
}
I am probably using WaitForInputIdle() incorrectly but I can't see where.
Maybe this is the wrong approach?
Gav...
 

Re:Re: Opening up Web Browsers inside my App

"Gav" < XXXX@XXXXX.COM >wrote in message
Quote
WaitForInputIdle(CreateProcess, 200);
Sleep(175);
You are not passing the correct HANDLE parameter to WaitForInputIdle(), and
you are only waiting for a fraction of a second overall. That is too short
a time. Get rid of the Sleep() and use a much larger timeout on
WaitForInputIdle(), or just use INFINITE. As for the HANDLE parameter to
WaitForInputIdle(), you need to use the hProcess member of the
PROCESS_INFORMATION structure.
Quote
INFINITE does not work.
Of course not, because you are not passing a valid HANDLE to
WaitForInputIdle() to begin with. Pass in the correct HANDLE, and then it
will work.
Gambit
 

Re:Re: Opening up Web Browsers inside my App

"Remy Lebeau (TeamB)" wrote :-
Quote
You are not passing the correct HANDLE parameter to WaitForInputIdle(),
and
you are only waiting for a fraction of a second overall. That is too
short
a time. Get rid of the Sleep() and use a much larger timeout on
WaitForInputIdle(), or just use INFINITE. As for the HANDLE parameter to
WaitForInputIdle(), you need to use the hProcess member of the
PROCESS_INFORMATION structure.
Oops, ok done that.
Quote

>INFINITE does not work.

Of course not, because you are not passing a valid HANDLE to
WaitForInputIdle() to begin with. Pass in the correct HANDLE, and then it
will work.
Your confidence in my abilities is flattering :)
However I now have :-
void __fast TMDIChild1::ITimageClick(TObject *Sender)
{
char DefaultBrowser[MAX_PATH+1] = {0};
MDIChild2->GetDefaultBrowser(DefaultBrowser);
STARTUPINFO si = {sizeof(STARTUPINFO), 0};
PROCESS_INFORMATION pi = {0};
AnsiString CmdLine = (AnsiQuotedStr(DefaultBrowser, '"') + " " +
AnsiQuotedStr("www.minitutorials.com", '"'));
if( ::CreateProcess(NULL, CmdLine.c_str(), NULL, NULL, FALSE, 0,
NULL, NULL, &si, &pi) )
{
WaitForInputIdle(pi.hProcess, INFINITE);
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);
MyInfo info = {pi.dwProcessId, NULL};
::EnumWindows((WNDENUMPROC)FindBrowser,reinterpret_cast<LPARAM>(&info));
if( info.hWnd != NULL )
{
::SetParent ( info.hWnd, Form4->Handle );
Form4->Show();
}
}
}
This still does not work, the Internet Explorer window still opens up in a
new window of its own external to my app, have I still got it wrong,
something missing, or maybe a different approach is required. The code above
all gets executed in that all ifs get executed, it seems that the
WaitForInputIdle() is not working somehow.
I have tried other variations that I have seen in Borland Newsgroups and
other sites none of which worked for me.
I am still experimenting. I take it WaitForInputIdle() is the correct/best
way to go about this.?
Gav...
 

Re:Re: Opening up Web Browsers inside my App

Having looked with Spy++ , the new window created using CreateProcess() does
not have a Parent Process.
Having quadruple checked the code I have added to Gambits code, I can see
nothing wrong (?)
Any more ideas anyone, it does seem to work for other people.
Thanks
Gav... (who probably wont go away until this is sorted once and for all :) )
 

Re:Re: Opening up Web Browsers inside my App

Just to add,
I am using SetParent to try and put the IE process into my own form.
I read somewhere that this does not (always) work unless the child is part
of the same application (?)
FindWindow I dont 'think' is an option as the text is unknown beforehand
(being a Web Browser going to an unkown URL)
unless someone tells me different.
Gav...