OVH Cloud OVH Cloud

pb iwebbrowser2

12 réponses
Avatar
gl
Bonjour,

Je tourne en rond, je ne vois pas où ça buggue !!!

Voilà, j'ai développé un truc en Win32 pur (j'utilise MSVS.NET C++ 2003)
J'ai emprunté une source trouvée sur le site cppfrance concernant une
utilisation simple de iwebvowser2, celle-ci :
http://www.cppfrance.com/dlzip.zipnix?ID=29171&accept=1

Depuis mon dialogue principal, je veux simplement afficher dans un dialogue
modal un fichier HTML présent sur le disque:
La ressource contient:
- un contrôle Edit (IDC_CONTENEUR) qui hébergera le contrôle ActiveX pour
afficher la page HTML
- un contrôle Edit (IDC_EDITHTML) pour afficher le code HTML pour info.
- un bouton de fermeture (ID_OK)

------------------------------------------------------------------------------------
J'ai bien mis le:
#include <exdisp.h>

J'ai déclaré ces variables globales:
IWebBrowser2 * pIWeb; // objet Browser utilisé dans preview
HINSTANCE hDLL; // instance atl.dll

------------------------------------------------------------------------------------

Dans WinMain, je crée une instance du Browser une fois pour toutes...

// Charger la DLL "atl.dll" pour le WebBrowser
hDLL = LoadLibrary("atl.dll");
// Initialiser la librairie COM pour le programme:
CoInitialize(0);
// Créer une instance de l'objet WebBrowser et de l'interface IWebBrowser2:
CoCreateInstance(CLSID_WebBrowser,0,CLSCTX_ALL,IID_IWebBrowser2,(void**)&pIWeb);

Puis j'appelle le dialogue principal:
// créer le dialogue principal
hDlg=CreateDialog(hInstance,(LPCTSTR)IDD_MAIN_DIALOG,NULL,(DLGPROC)MainProc);
// le centrer et l'afficher
CenterWindow(hDlg);
ShowWindow(hDlg,SW_SHOW);

Ensuite la boucle des messages...
// boucle messages
MSG msg;
while(GetMessage(&msg,NULL,0,0)==TRUE)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;

Et je libère l'interface:
// Libérer l'interface IWebBrowser2:
pIWeb->Release();
// Fermer la librairie COM pour le programme:
CoUninitialize();
// Fermer la DLL "atl.dll"
FreeLibrary(hDLL);

------------------------------------------------------------------------------------

Dans le dialogue principal, un bouton appelle le dialogue "WebBrowser"
inclus dans les ressources:

DialogBoxParam(hInst,MAKEINTRESOURCE(IDD_WEBDLG), MainDlg,(DLGPROC)WebProc,
(LPARAM)st.c_str());
(st est une string contenant le code HTML)

Et voilà la procédure callback du dialogue "WebBrowser":

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * */
// procédure callback messages WebBrowser
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * */
LRESULT CALLBACK WebProc(HWND hwnd, UINT message,WPARAM wParam,LPARAM
lParam)
{

// test message
switch(message)
{

case WM_INITDIALOG:
{
hPreview=hwnd; // utilisé dans la procédure OnSize()

CenterWindow(hwnd);

// afficher l'icône système
SendMessage(hwnd, WM_SETICON, ICON_SMALL,
(LPARAM)LoadIcon(hInst,
MAKEINTRESOURCE(IDI_MAINICON)));
SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(hInst,
MAKEINTRESOURCE(IDI_MAINICON)));

// LPARAM pointe sur la chaîne contenant le code
HTML
// Il est mis dans l'edit pour info
SendDlgItemMessage(hwnd, IDC_EDITHTML, WM_SETTEXT, 0,
(LPARAM)lParam);

// Définir le type de pointeur pour la fonction
"AtlAxAttachControl":
typedef HRESULT (WINAPI *PAttachControl)(IUnknown*,
HWND,IUnknown**);
// Récupérer l'adresse de la fonction "AtlAxAttachControl":
PAttachControl AtlAxAttachControl = (PAttachControl)
GetProcAddress(hDLL, "AtlAxAttachControl");

// Attacher l'objet WebBrowser à notre EDIT conteneur:
AtlAxAttachControl(pIWeb,GetDlgItem(hwnd, IDC_CONTENEUR),0);

// mise en forme URL
WCHAR url[256];
char buff[256];
strcpy(buff,sAppPath.c_str());
strcat(buff, "\\html.htm");
MultiByteToWideChar (CP_ACP, 0,buff, -1, url, 256);

// Lancer la navigation:
pIWeb->Navigate(url,0,0,0,0);

// Sauter la procédure originale:
return true;
}
/*
j'ai essayé ça, mais c'est pareil !...
case WM_DESTROY:
VARIANT_BOOL pBool;
if ((pIWeb->get_Busy(&pBool))==S_OK)
if (pBool==VARIANT_TRUE)
pIWeb->Stop();
return true;
*/

case WM_SIZE:
OnSize(wParam, LOWORD(lParam), HIWORD(lParam));
return true;

case WM_COMMAND:
switch(HIWORD(wParam))
{
case BN_CLICKED:
switch(LOWORD(wParam))
{
case IDOK:
// Quitter le dialogue
EndDialog(hwnd, LOWORD(wParam));
return true;
}
}

case WM_SYSCOMMAND:
if ((wParam & 0xFFF0) == SC_CLOSE)
{
EndDialog(hwnd,LOWORD(wParam));
return true;
}

default:
return false;
}
}

Je ne vois pas où est l'erreur ???
Au début, j'avais mis les initilisations/libérations de l'interface dans
WM_INITDIALOG de la fenêtre "Webbrowser", mais le résultat est le même et ça
prend du temps : ça recharge la DLL à chaque appel !

Le problème :
Tout a l'air de fonctionner normalemenr.
Mais... si dans le texte HTML, il y a par exemple ceci : <IMG
src="http://machintruc"></IMG>, au premier appel du dialogue la fenêtre de
connexion apparaît, ce qui est normal.
Si je refuse la connexion, l'image est représentée par le carré rouge,
toujours normal.
Mais quand je referme le dialogue et que je le réouvre deux ou trois fois,
ça "plante" à la fermeture comme si quelque chose n'était pas libéré...
Le dialogue se ferme, mais ne rend pas la main à la proceduré principale !
Je dois passer par "Le programme ne répond pas, terminer maintenant, envoyer
le rapport etc....."

De plus le comportement est assez erratique !
Parfois, ça marche mais ça ne repropose pas la connexion !...

Il me semble que l'appel au dialogue (le DialogBoxParam plus haut...) attend
indéfiniment su'une fonction appelée se termine.

Je suis dans le brouillard.
Je suis prêt à adopter une autre solution... mais pour faire aussi court
?!...

Merci pour votre aide.

10 réponses

1 2
Avatar
Sylvain
gl wrote on 15/03/2006 22:28:
Bonjour,

Je tourne en rond, je ne vois pas où ça buggue !!!
[...]
Le problème :
Tout a l'air de fonctionner normalemenr.
Mais... si dans le texte HTML, il y a par exemple ceci : <IMG
src="http://machintruc"></IMG>, au premier appel du dialogue la fenêtre de
connexion apparaît, ce qui est normal.
Mais quand je referme le dialogue et que je le réouvre deux ou trois fois,
ça "plante" à la fermeture comme si quelque chose n'était pas libéré...
Le dialogue se ferme, mais ne rend pas la main à la proceduré principale !
Je dois passer par "Le programme ne répond pas, terminer maintenant, envoyer
le rapport etc....."


le code apparait correct et n'a pas de raison de se bloquer (pas
d'object trop ref. compter par exemple).

j'ai reproduit en simplifiant à un seul dialogue votre code (ci-après)
et cela fonctionne parfaitement avec les nuances suivantes:
- lorsqu'une connexion internet est dispo. tout est fluide,
- si la connexion est coupée ou si la requête générée par Navigate() est
bloquée par un firewall, le composant mets un temps variable à répondre,
je n'ai pas pour autant obtenu de blocage, ni crash ou exception.

il est possible que les comportements observés viennent de votre couche
PPP (sinon IP) et non de votre code lui-même.

vous pouvez essayer de minimiser les blocages en testant la connexion
(Cf CInternetSession::GetHttpConnection, afxinet.h qui ne dépends pas
des MFC) avant d'essayer d'ouvrir l'URL.

autre piste, coder un destroy plus autoritaire:

case WM_DESTROY:
for (VARIANT_BOOL pBool = VARIANT_TRUE; pBool == VARIANT_TRUE; ){
if (pIWeb->get_Busy(&pBool) != S_OK)
break;
if (pBool == VARIANT_TRUE)
pIWeb->Stop();
}
pIWeb->Quit();
return true;

Sylvain.


outils: VC98, Atl.dll 3.5.2283.0, host Win2003.

#include "stdio.h"
#include "stdlib.h"
#include <windows.h>
#include <baseTyps.h>
#include <exdisp.h>

#define null NULL

// resource
#define IDD_MAIN_DIALOG 1000
#define IDD_EDIT_CTRL 1001
#define IDD_HTML_CTRL 1002
/*
resource.rc

1000 DIALOG DISCARDABLE 0, 0, 274, 207
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,217,386,50,14
PUSHBUTTON "Cancel",IDCANCEL,152,286,50,14
EDITTEXT 1001,7,7,260,81,ES_MULTILINE
EDITTEXT 1002,7,94,260,186,ES_AUTOHSCROLL
END
*/

const char* html = "<html><body><p>Hello World</p>"
"<img src='http://www.gnu.org/brave-gnu-world/rungnu/"
"brave_gnu_world2.png' /></body></html>";

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE gInstance = null;
HINSTANCE hAltDll = null;
IWebBrowser2* pIWeb = null;
HWND dlgMain = null;

LPWSTR a2wstr(const char* text)
{
if (!text)
return null;
// compute required size & allocate buffer
register size_t length = ::strlen(text) + 1;
LPWSTR bStr = new WCHAR[length];
if (!bStr)
return null;
// convert to Unicode
if (mbstowcs(bStr, text, length) == -1)
delete [] bStr, bStr = null;
return bStr;
}

LRESULT CALLBACK mainProc(HWND dlg, UINT message, WPARAM wParam, LPARAM
lParam)
{
switch(message){
case WM_INITDIALOG:
// copy raw html into first edit
SendDlgItemMessage(dlg, IDD_EDIT_CTRL, WM_SETTEXT, 0, (LPARAM) html);
// initialise WebControl
{
typedef HRESULT (WINAPI *PAttachControl)
(IUnknown*, HWND, IUnknown**);
PAttachControl AtlAxAttachControl = (PAttachControl)
::GetProcAddress(hAltDll, "AtlAxAttachControl");
AtlAxAttachControl(pIWeb, ::GetDlgItem(dlg, IDD_HTML_CTRL), 0);
LPWSTR wUrl = a2wstr("w:/html.htm");
if (wUrl){
HRESULT result = pIWeb->Navigate(wUrl, 0, 0, 0, 0);
delete [] wUrl;
}
}
return true;

case WM_COMMAND:
switch(LOWORD(wParam)){
case IDOK:
::EndDialog(dlg, 1);
::PostQuitMessage(0);
return TRUE;
case IDCANCEL:
::EndDialog(dlg, 0);
::PostQuitMessage(0);
return TRUE;
}
// follow

default:
return FALSE;
}
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR, int)
{
// create html file with fixed content
FILE* file = fopen("w:html.htm", "wt");
if (!file)
return -1;
fputs(html, file);
fclose(file), file = null;
// load ATL library
if ((hAltDll = ::LoadLibrary("atl.dll")) == null)
return -2;
// initialize COM
if (CoInitialize(null) != S_OK)
return -3;
pIWeb = null;
if (::CoCreateInstance(CLSID_WebBrowser, 0, CLSCTX_ALL,
IID_IWebBrowser2, (void**) &pIWeb) != S_OK)
return -4;

// create dialog & display it
gInstance = hInstance;
dlgMain = ::CreateDialog(hInstance, (LPCTSTR) IDD_MAIN_DIALOG,
null, (DLGPROC) mainProc);
::ShowWindow(dlgMain, SW_SHOW);

MSG msg;
while (::GetMessage(&msg, NULL, 0, 0)){
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}

if (pIWeb)
pIWeb->Release(), pIWeb = null;
CoUninitialize();
FreeLibrary(hAltDll);
return 0;
}

Avatar
gl
"Sylvain" a écrit dans le message de news:
4418b045$0$18311$

le code apparait correct et n'a pas de raison de se bloquer (pas d'object
trop ref. compter par exemple).


Merci c'est bien ce que je pensais.

- si la connexion est coupée ou si la requête générée par Navigate() est
bloquée par un firewall, le composant mets un temps variable à répondre,
je n'ai pas pour autant obtenu de blocage, ni crash ou exception.


Le firewall est désactivé.
Ce n'est pas un crash que j'obtiens, XP ne m'affiche même pas la fenêtre "Ce
programme ne répond plus", le dialogue contenant le browser est bien
refermé, mais le programme semble tourner dans une boucle sans fin, ou
plutôt semble attendre la libération d'un objet, il est "gelé", j'ai une
fenêtre grise (ou blanche) et les contrôles ne se réaffichent pas... Ça peut
rester come ça 10 minutes ! Ce n'est qu'en cliquant sur la croix de
fermeture que j'obtiens la boîte classique "Teminer maintenant".
Autrement dit, XP ne semble pas considérer que le log ne répond plus...

il est possible que les comportements observés viennent de votre couche
PPP (sinon IP) et non de votre code lui-même.


Il me semble que ça peut effectivement venir de ça.

vous pouvez essayer de minimiser les blocages en testant la connexion (Cf
CInternetSession::GetHttpConnection, afxinet.h qui ne dépends pas des MFC)
avant d'essayer d'ouvrir l'URL.


Là, je n'ai pas tout compris... Dans la doc MSDN,
CInternetSession::GetHttpConnection fait bien partie des MFC...

autre piste, coder un destroy plus autoritaire:

case WM_DESTROY:
for (VARIANT_BOOL pBool = VARIANT_TRUE; pBool == VARIANT_TRUE; ){
if (pIWeb->get_Busy(&pBool) != S_OK)
break;
if (pBool == VARIANT_TRUE)
pIWeb->Stop();
}
pIWeb->Quit();
return true;


J'ai essayé ce destroy : comportement identique !

Pour info, je suis sous XP Pro, MSVC++ 2003, atl.dll v3.5.2284.0

Dernière remarque, si IE est hors connexion (coche en face de
Fichier/Travailler hors connexion), mon dialogue ne me propose même pas la
connexion... Je pensais que l'instance IWebBrowser2 que j'utilisais était
indépendante de IE lui-même ?

Merci beaucoup pour votre réponse !
Je vais essayer en partant du code que vous proposez.

gl

Avatar
Sylvain
gl wrote on 16/03/2006 18:55:

vous pouvez essayer de minimiser les blocages en testant la connexion (Cf
CInternetSession::GetHttpConnection, afxinet.h qui ne dépends pas des MFC)
avant d'essayer d'ouvrir l'URL.


Là, je n'ai pas tout compris... Dans la doc MSDN,
CInternetSession::GetHttpConnection fait bien partie des MFC...


yep, erreur! CInternetSession dépend inutilement (par CString) des MFC.
le code ci-après [2] ne dépend que de wininet.h et permet de "pinger"
une url (directement via readInetDoc ou plus finement via getInetDoc).


autre piste, coder un destroy plus autoritaire:
J'ai essayé ce destroy : comportement identique !



y compris avec le Quit() ?

Pour info, je suis sous XP Pro, MSVC++ 2003, atl.dll v3.5.2284.0


VC 2003 est mort-né (c'était un peu le véhicule marketting de C#),
quitte à abandonner VC6, passez plutôt à VC2005 [1] (version express
(limitée) gratuite).

Dernière remarque, si IE est hors connexion (coche en face de
Fichier/Travailler hors connexion), mon dialogue ne me propose même pas la
connexion... Je pensais que l'instance IWebBrowser2 que j'utilisais était
indépendante de IE lui-même ?


non c'est bien le même "moteur" derrière, le composant reprend donc tous
les settings globaux.

dans l'exemple ci-après, vous pouvez controler plus finement le mode de
connexion (forcer online, avec/depuis/sans cache disque) mais vous
devrez écrire votre parser/render html pour obtenir le résultat final.

Sylvain.

[1]: http://msdn.microsoft.com/vstudio/express/visualc/download/

[2] -- source testé avec VC6
//-----------------------------
// 2 spaces/tab for usenet

#include <windows.h>
#include <ostream.h>
#include <wininet.h>

#define null NULL

class String {
protected:
char* string;
size_t length;
size_t capacity;

public:
String() { string = null; capacity = length = 0; }
~String() { if (string) delete [] string; }

operator const char* () const { return string; }
operator bool () const { return (length != 0); }

String& insert(const char* inStr, size_t inLen){
if (inStr){
if (length + inLen > capacity){
capacity += (inLen + 0x3FFF) & 0x7FFFC000;
char* newStr = new char[capacity];
::memcpy(newStr, string, length);
delete [] string;
string = newStr;
}
::memcpy(string + length, inStr, inLen);
length += inLen;
string[length] = 0;
}
return *this;
}
};


bool getInetDoc(
const char* server, const char* docUrl,
String& document, String* header)
{
// get optional proxy address from global setting or ...
const char* proxy = null;
const char* proxyBypass = null;
// check connexion availability
HINTERNET internet = ::InternetOpen(
"myAgent",
(proxy) ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG,
proxy, proxyBypass, 0);

if (!internet)
return false;

// 1- methode controlée

// setup internet connexion
const char* types = "text/*";

HINTERNET handle = ::InternetConnect(internet, server,
INTERNET_DEFAULT_HTTP_PORT,
null, // no user name
null, // no password
INTERNET_SERVICE_HTTP,
0, // no flag requierd for htttp protocol
null); // no context

if (handle){
// try to open an Http request for the provided server
HINTERNET request = ::HttpOpenRequest(handle, "GET", docUrl,
null, // HTTP/1.1 is default
null, // no referer
&types, // accepted ytpes
INTERNET_FLAG_NO_CACHE_WRITE,
null); // no context

if (request){
// transmit the request (perform actual connexion)
if (::HttpSendRequest(request,
null, // no request header
0, // length of header
null, // no POST, nor GET parameters
0)) // length of parameters
{
// read header response, if required
if (header){
char buffer[1024];
DWORD length = 1024;
if (::HttpQueryInfo(request, HTTP_QUERY_RAW_HEADERS_CRLF,
buffer, &length, null)){
if (length)
header->insert(buffer, length);
}
}
// read response content
char buffer[1024];
DWORD length = 1024;
for (;;){
if (::InternetReadFile(request, buffer, 1024, &length) == FALSE)
break;
// EOF reached ?
if (length == 0)
break;
// append data to stream/collector/...
document.insert(buffer, length);
}
}
::InternetCloseHandle(request);
}
::InternetCloseHandle(handle);
}
// clean up
::InternetCloseHandle(internet);
return document;
}


bool readInetDoc(const char* fullUrl, String& document)
{
// get optional proxy address from global setting or ...
const char* proxy = null;
const char* proxyBypass = null;
// check connexion availability
HINTERNET internet = ::InternetOpen(
"myAgent",
(proxy) ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG,
proxy, proxyBypass, 0);

if (!internet)
return false;

HINTERNET file = InternetOpenUrl(internet,
fullUrl, // protocol + server + document
null, // no headers
0, // length of headers
INTERNET_FLAG_DONT_CACHE,
null); // no context

if (file){
char buffer[1024];
DWORD length = 1024;
for (;;){
if (::InternetReadFile(file, buffer, 1024, &length) == FALSE)
break;
// EOF reached ?
if (length == 0)
break;
// append data to stream/collector/...
document.insert(buffer, length);
}
::InternetCloseHandle(file);
}

// clean up
::InternetCloseHandle(internet);
return document;
}

int main(int argc, char* argv[])
{
const char* server = "www.google.com";
const char* target = "/";

String document;
String header;
if (getInetDoc(server, target, document, &header))
cout << "header:n" << header
<< "ndocument:n" << document << "n";

const char* url = "http://www.google.com/";

String page;
if (readInetDoc(url, page))
cout << "npage:n" << page << "n";

return 0;
}


Avatar
Sylvain
Sylvain wrote on 16/03/2006 23:25:

char* newStr = new char[capacity];


lire: char* newStr = new char[capacity + 1];

(gestion du zero terminal lorsque les blocs insérés sont de la taille de
l'incrément d'allocation).

Sylvain.

Avatar
gl
"Sylvain" a écrit dans le message de news:
4419e5d7$0$6683$

le code ci-après [2] ne dépend que de wininet.h et permet de "pinger" une
url (directement via readInetDoc ou plus finement via getInetDoc).

D'accord, mais ça ne répond pas à mon attente !!


Je "débute" en C++. Jusque-là je développais (en amateur) avec des langages
plus évolués (Pascal d'abord, VB et surtout Delphi).
Avec ces langages, le développement d'une petite appli est très rapide, mais
l'exe est tout de suite très volumineux et son exécution dépend de DLLs pas
forcément présentes sur tous les systèmes !
Alors, j'ai eu envie de me mettre au C pur (que je ne connaissais que très
peu), sans les MFC, sinon, pourquoi quitter Delphi ?
Ceci afin de réduire la taille de l'exe et surtout de le rendre indépendant
de toute DLL spécifique.

En plus en API pur, on "voit" et on "sait" vraiment ce qu'on fait, mais le
codage est évidemment bien plus ardu ! Et j'ai assez de mal avec les
allocations méaoire et les pointeurs, ce qui est relativement transparent
dans Delphi !

Si j'ai bien compris ce nouveau code, on ouvre une URL, on lit le header, on
lit ensuite le document et on met tout ça dans un stream
?
Non ? J'ai tout faux ?


J'ai essayé ce destroy : comportement identique !
y compris avec le Quit() ?



Oui, même avec le pIWeb->Quit() !

VC 2003 est mort-né (c'était un peu le véhicule marketting de C#), quitte
à abandonner VC6, passez plutôt à VC2005 [1] (version express (limitée)
gratuite).


Désolé, je n'ai qu'une connexion RTC 56Ko, alors inutile d'envisager un
téléchargement.. mais je pense bientôt disposer le la v2005 complète... et
éventuellement de l'ADSL dans quelques mois...

Même avec le Quit(), inéluctablement, à la nièmeme réouverture du dialogue,
le browser ne se ferme manifestement pas.
En mode Debug, j'arrive *très rarement* à reprendre la main... j'ai alors un
petit triangle vert devant la ligne :
-> DialogBoxParam(hInst,MAKEINTRESOURCE(IDD_WEBDLG),
MainDlg,(DLGPROC)WebProc,
(LPARAM)st.c_str()); qui appelle la boîte de dialogue censée être fermée.
Il m'est alors indiqué un message du genre : "Cette procédure a appelé une
fonction qui n'est pas terminée. Elle reprendra ensuite...".

Mais aujourd'hui, je ne comprends rien, dès le deuxième appel, la connexion
n'est même plus proposée !??! Avec le même code !! Donc je n'arrive même
plus en mode Debug à reproduire cette situation !!
Et un clic-droit/Actualiserdans le browser ne repropose pas la connexion.
j'ai même essayé pIWeb->put_Offline(VARIANT_FALSE) avant le Navigate(), la
connexion n'est toujours pas demandée !
La couche PPP (ou IP) de mon PC a, commme vous dites, un comportement
bizarre...
Je crois que je vais laisser tomber.. ou alors repartir sur d'autres bases
?...
En tout cas, merci pour votre aide. C'est sympa !

Je dis qu'il me semble que ce dernier code proposé m'est inutile ou plutôt
inadapté. Je vais essayer de vous préciser pourquoi.

La finalité du soft que je suis en train de développer est de créer des
fichiers texte respectant un format bien précis destinés à préparer par
avance des posts pour un forum.
J'ai donc une boîte de dialogue principale avec des zones de saisie, des
combos des différentes rubriques... et une zone principale du "corps" du
post.
A l'aide de boutons de commande, je permets à l'utilisateur d'insérer
automatiquement des balises BBCode. Ainsi, une fois le fichier texte
enregistré, un simple copier/coller dans l'éditeur PHP du forum contient
toute la mise en forme (couleur, gras, polices etc). Ça évite de perdre du
temps, sutout quand on "rame" avec une connexion RTC où le forfait n'est pas
illimité !!
Ce n'est qu'au fil du temps que j'ai pensé rajouter cette fonction "Preview"
qui me paraissait agréable, d'où l'utilisation de IWebBrowser2.

Je convertis donc le "texte BBCode" en HTML dans une string et j'écris sur
le disque un fichier html.htm dans le dossier de l'exe.
La chaîne est passée en lparam au dialogue pour remplir l'edit "Info" et le
fichier local est est passé comme url de Navigate().
Voilà, c'est long comme explication, mais en fait c'est simple.

Et là où le bât blesse, c'est lors de l'insertion d'une URL d'image dans le
BBCode.
Dans ce cas là, le browser a besoin d'une connexion effective pour charger
l'image.

J'ai même essayé en mode connecté : si je ferme le dialogue avant le
chargement complet de l'iimage, ça "freeze" !

Voilà, désolé de vous avoir pris de votre temps, et encore merci pour vos
réponses.

gl


Avatar
Arnaud Meurgues
gl wrote:

Je "débute" en C++. Jusque-là je développais (en amateur) avec des langages
plus évolués (Pascal d'abord, VB et surtout Delphi).
^^^^^^^^^^^^ ^^^^^^ ^^


Ah ! Ah ! :'-D

Ça, pour du troll, c'est du troll...
--
Arnaud

Avatar
gl
"Arnaud Meurgues" a écrit dans le
message de news: 441adc48$0$31454$
gl wrote:

Je "débute" en C++. Jusque-là je développais (en amateur) avec des
langages
plus évolués (Pascal d'abord, VB et surtout Delphi).
^^^^^^^^^^^^ ^^^^^^ ^^


Ah ! Ah ! :'-D


Je veux simplement dire plus faciles d'utilisation !!!
Avec IDE, composants tout prêts, c'est tout...

Je reste persuadé qu'avec le C on peut faire bien mieux, pour la simple
raison qu'on est vraiment tout proche du langage machine !
J'ai aussi programmé en assembleur !

Ça, pour du troll, c'est du troll...


Peut-être...


Avatar
Sylvain
gl wrote on 17/03/2006 15:00:

le code ci-après [2] ne dépend que de wininet.h et permet de "pinger" une
url (directement via readInetDoc ou plus finement via getInetDoc).

D'accord, mais ça ne répond pas à mon attente !!



je suis d'accord sur le fait que cela n'explique pas votre blocage
stricto sensus, mais il me parait indispensable de savoir cerner et
contourner les blocages pour ne pas rester piéger par ses a priori ou
des bugs d'une fourniture tierce.

ces codes (snippets) ne doivent que vous servir à tester ce qui
fonctionne (valider la connexion internet, le comportement de l'agent
accès réseau à distance, un layout PPP made in Free, ...) pour mieux
isoler ce qui ne fonctionne pas afin de lui trouver un codage de
substitution qui sera plus stable.

Je "débute" en C++. Jusque-là je développais (en amateur) avec des langages
plus évolués (Pascal d'abord, VB et surtout Delphi).


langages plus "intégrés", un IDE VB ou Delphi est aujourd'hui
principalement un clicodrome où l'essentiel du codage de "la solution"
se fait à la souris.

Avec ces langages, le développement d'une petite appli est très rapide, mais
l'exe est tout de suite très volumineux et son exécution dépend de DLLs pas
forcément présentes sur tous les systèmes !


oui.

Alors, j'ai eu envie de me mettre au C pur (que je ne connaissais que très
peu), sans les MFC, sinon, pourquoi quitter Delphi ?


j'avais noté ce coté un peu "cuir" (maso) ;-) 99% des applications que
l'on peut croiser et qui utiliseraient les mêmes mécanismes sont codés
selon le template dialog based des MFC avec des morceaux d'ATL Object
Wizard dedans.

toutefois, la comparaison n'est pas tout à fait exacte; on peut préférer
ne pas utiliser les MFC car ce n'est pas une véritable librairie objet,
toutefois elle produit et s'alimente de code C++ contrairement aux
clicodromes sus-nommés qui s'alimentent bcp plus de composants fermés
que le développeur doit se contenter de connecter.

reste que les MFC sont parfois laborieuses par le comportement masqué de
macros trop abondantes et des noms de méthodes pas tjrs évidents; pour
ces raisons, on peut préférer se contenter des API Win32 (... tant
qu'elles existent encore).

En plus en API pur, on "voit" et on "sait" vraiment ce qu'on fait, mais le
codage est évidemment bien plus ardu ! Et j'ai assez de mal avec les
allocations méaoire et les pointeurs, ce qui est relativement transparent
dans Delphi !


Delphi utilise peut être des mécanismes masqués qui semblaient rendre
les choses plus rapides, vous aurez la même aisance en C++ une fois
choisi ou implémenté par vous même vos smart pointeurs et autres chaînes
de caractères.

Si j'ai bien compris ce nouveau code, on ouvre une URL, on lit le header, on
lit ensuite le document et on met tout ça dans un stream ?
Non ? J'ai tout faux ?


les codes montrent comment on peux faire pour tester si une page est
accessible, en aucun cas vous devez nécessairement faire comme cela; je
répète ces exemples peuvent soit servir en phase de mise au point
uniquement (pour déterminer le truc qui coince) ou au pire comme moyen
de contournement si un blocage potentiel demeure et que vous voulez
ajouter un code testant l'environnement (par exemple la connexion) avant
de lancer bille en tête la procédure pouvant échouer.

à vous de voir si cela peut apporter et ce que ça apporte effectivement.

Même avec le Quit(), inéluctablement, à la nièmeme réouverture du dialogue,
le browser ne se ferme manifestement pas.
En mode Debug, j'arrive *très rarement* à reprendre la main... j'ai alors un
petit triangle vert devant la ligne :
-> DialogBoxParam(hInst,MAKEINTRESOURCE(IDD_WEBDLG),
MainDlg,(DLGPROC)WebProc,
(LPARAM)st.c_str()); qui appelle la boîte de dialogue censée être fermée.


cet appel est sûrement le dernier tracé mais vous pouvez poser des
points d'arrêts dans WebProc (après l'appel à DialogBoxParam(...,
WebProc) ou pendant son exécution - notez qu'entre l'appel à
DialogBoxParam et l'entrée dans votre méthode figurera une dizaine
d'appel à l'intérieur des librairies windows (la plupart non débuggable
sauf artillerie lourde) mais vous devez pouvoir tracer l'appel à vos
EndDialog() et remonter la pile (même en asm dans le texte) afin de voir
si le code dépile jusqu'à votre appel à DialogBoxParam. si le code part
on-sait-pas-où vous pouvez également le breaker (Debug, Break) pour
essayer de voir où il tourne en rond.

Il m'est alors indiqué un message du genre : "Cette procédure a appelé une
fonction qui n'est pas terminée. Elle reprendra ensuite...".


normal pour le DialogBoxParam imbriqué .... oh, oh, en effet imbriqué,
votre application (principale) est un dialogue modal qui affiche un
dialogue modal de preview html - oui, et alors? - il y a des cas où
DialogBoxParam ne réentre pas très bien, je n'ai plus ça en tête mais ça
m'évoque des mauvais souvenirs ...

Mais aujourd'hui, je ne comprends rien, dès le deuxième appel, la connexion
n'est même plus proposée !??! Avec le même code !! Donc je n'arrive même
plus en mode Debug à reproduire cette situation !! [...]
La couche PPP (ou IP) de mon PC a, commme vous dites, un comportement
bizarre...
Je crois que je vais laisser tomber.. ou alors repartir sur d'autres bases


y'a des jours, rien ne veux tomber en marche ;-)

La finalité du soft que je suis en train de développer est de créer des
fichiers texte respectant un format bien précis destinés à préparer par
avance des posts pour un forum. [...]
A l'aide de boutons de commande, je permets à l'utilisateur d'insérer
automatiquement des balises BBCode. Ainsi, une fois le fichier texte
enregistré, un simple copier/coller dans l'éditeur PHP du forum contient
toute la mise en forme (couleur, gras, polices etc). [...]
Ce n'est qu'au fil du temps que j'ai pensé rajouter cette fonction "Preview"
qui me paraissait agréable, d'où l'utilisation de IWebBrowser2.


ça ouvre d'autres pistes ! et notamment sur l'ergonomie:

1- votre éditeur principal est donc basé sur BBCode qui offre un codage
simplifié/symbolique des attributs HTML; la capitalisation de
l'expérience de l'utilisateur se fonde donc sur les icones (si
présentes) insérant tel tag ou sa syntaxe qu'il tapera lui-même après
apprentissage; dès lors lui présenter le code HTML généré ne sert à rien
(il ne vous montre qu'à vous que vous avez bien codé la traduction) l'
"utilisateur normal" n'est pas concerné par cela.

2- l'utilisateur a l'habitude de visualiser des pages HTML (sans se
préoccuper de la syntaxe HTML) dans son navigateur, pas dans un dialogue
modal (qu'il vous coutera de rendre redimensionnable, de supporter les
tailles de fontes variables, etc)

votre bouton prévisualiser peut donc (avantageusement?) être transformé
en un appel au browser pré-enregistré pour lui demandé d'afficher la
page que vous venez de créer dynamiquement (plaçant l'utilisateur dans
un cadre qu'il connaît); vous réaliserez cela avec un simple WinExec ou
CreateProcess qui ne créera pas les noeuds actuels (et si IE plante, ce
ne sera que de sa faute!).

le nom du butineur choisi par l'utilisateur est stocké sous
[HKEY_CLASSES_ROOTHTTPshellopenddeexecApplication]

Sylvain.


Avatar
gl
"Sylvain" a écrit dans le message de news:
441b5df2$0$21267$
gl wrote on 17/03/2006 15:00:


votre bouton prévisualiser peut donc (avantageusement?) être transformé en
un appel au browser pré-enregistré pour lui demandé d'afficher la page que
vous venez de créer dynamiquement (plaçant l'utilisateur dans un cadre
qu'il connaît); vous réaliserez cela avec un simple WinExec ou
CreateProcess qui ne créera pas les noeuds actuels (et si IE plante, ce ne
sera que de sa faute!).


Je crois que je vais me contenter de cette solution pour l'instannt...

le nom du butineur choisi par l'utilisateur est stocké sous
[HKEY_CLASSES_ROOTHTTPshellopenddeexecApplication]

Et encore un grand merci pour vos conseils précieux.


fl

Avatar
gl
"Sylvain" a écrit dans le message de news:
441b5df2$0$21267$

les codes montrent comment on peux faire pour tester si une page est
accessible, en aucun cas vous devez nécessairement faire comme cela; je
répète ces exemples peuvent soit servir en phase de mise au point
uniquement (pour déterminer le truc qui coince) ou au pire comme moyen de
contournement si un blocage potentiel demeure et que vous voulez ajouter
un code testant l'environnement (par exemple la connexion) avant de lancer
bille en tête la procédure pouvant échouer.

à vous de voir si cela peut apporter et ce que ça apporte effectivement.


Je crois avoir trouvé ce qui fait "planter" !!!...

Dans mon cas (modem RTC 56Ko), quand on ouvre IE, une boîte de dialogue
propose la connexion d'accès à distance...

J'ai constaté (pur hasard) que si j'ouvre le BrowserDialog et que je le
referme en "ignorant" cette boîte de "connexion d'accès à distance" (je le
peux, cette dernière est modeless !), je reproduis systématiquement le
plantage !!!
Et même si je referme ensuite le dialogue de connexion (dans ce cas, je le
peux, il est dans la barre des tâches), la procédure principale ne reprend
pas pour autant la main !! Il faudrait fermer la boîte de connexion
*avant*........

Dans le cas général, je suppose c'est cette boîte de dialogue qui est sur le
point de s'ouvrir (ou qui n'est pas complètement libéreée ?), ce qui fait le
BrowserDialog ne rend pas la la main...

Donc, ce qu'il faudrait, c'est forcer sa fermeture avant de quitter le
BrowserDialog.
Mais comment faire ? Je n'ai vraiment aucune idée...

Il faudrait envoyer un WM_QUIT à cette fenêtre, mais comment la localiser ?
Et si elle est en phase de création, elle n'apparaît pas encore dans la
liste des fenêtres, non ?
Comment savoir si elle est en préparation ?...

Merci de me dire si vous avez une idée...

gl

1 2