Page 8 sur 9

Publié : sam. 07/avr./2007 18:45
par Anonyme2
Je m'adresse à ceux qui auraient utilisé GDI+ et en particulier les 2 fonctions

Code : Tout sélectionner

GdiplusNotificationHook
GdiplusNotificationUnHook
Pratiquement rien dans la doc MS, ces 2 fonctions ne sont pas implémentés dans le wrapper C de MS
Sur le Net, rien si ce n'est la même chose que la doc MS
J'arrive bien à récupérer les pointeurs, mais j'intercepte quoi avec ça ?

Une idée ? :roll:



Et aussi ceci

j'ai défini une procédure de degug (callback dont j'ai mis l'adresse dans input\DebugEventCallback avant l'appel de GdiplusStartup(@*token, @input, @output) )

Code : Tout sélectionner

Procedure DebugCallback(DebugEventLevel.l, *message)

; *DebugEventProc)(DebugEventLevel level, CHAR *message)

EndProcedure
Le paramètre DebugEventLevel peut prendre 2 valeurs

Code : Tout sélectionner

  #DebugEventLevelFatal = 0 
  #DebugEventLevelWarning = 1
Je pense (mais sans être sur) que si l'utilisation des fonctions GDI+ entraîne une erreur fatale ou une alerte (warning), on peut vérifier dans la callback avec le message et le type et la provenance, mais je n'ai pas trouvé d'explications sur ces 2 types erreurs, car je voulais les provoquer pour tester, mais bon, j'en reste là sans solution.

Une idée ? :roll:

Publié : lun. 09/avr./2007 18:54
par SFSxOI
GdiplusNotificationHook
GdiplusNotificationUnhook

Maybe this:

http://com.it-berater.org/gdiplus/nofra ... ctions.htm

see this:

"If you do not do this, there will be resource leaks that won't be cleaned up until the process exits."

?????

Also:

GdiplusStartup (*token, @GdiplusStartupInput, @GdiplusStartupOutput)

@GdiplusStartupOutput can be #Null if the SuppressBackgroundThread member of the input parameter is #False. If GdiplusStartupOutput is not #False then you have to supply a pointer to notification hook function and notification unhook function which are members of the GdiplusStartupOutput structure. From my understanding its not necessary to supply the pointers, thus the GdiplusStartupOutput can be #Null, like this:

GdiplusStartup (*token, @GdiplusStartupInput, #Null)

So maybe it would look like this?

Code : Tout sélectionner

ProcedureDLL.l Gdiplus_New(version.l = 1, *hEventCB = #Null, Codecs.l = #False, bgThread.l = #False)
  Protected *token, input.GdiplusStartupInput
  input\GdiPlusVersion = version
  input\DebugEventCallback = *hEventCB
  input\SuppressExternalCodecs = Codecs
  input\SuppressBackgroundThread = bgThread
  GdiplusStartup(@*token, @input, #Null)
  GdiplusNotificationHook(*token)
  GdiplusNotificationUnhook(*token)
  ProcedureReturn *token
EndProcedure
or, this:

Code : Tout sélectionner

Prototype.l DebugEventProc(level.l, message.p-unicode)

ProcedureDLL.l Gdiplus_New(version.l = 1, Codecs.l = #False, bgThread.l = #False)
  Protected *token, input.GdiplusStartupInput
  input\GdiPlusVersion = version
  input\DebugEventCallback = @DebugEventProc(level, message)
  input\SuppressExternalCodecs = Codecs
  input\SuppressBackgroundThread = bgThread
  GdiplusStartup(@*token, @input, #Null)
  GdiplusNotificationHook(*token)
  GdiplusNotificationUnhook(*token)
  ProcedureReturn *token
EndProcedure

Publié : mar. 10/avr./2007 15:35
par Anonyme2
SFSxOI a écrit :GdiplusNotificationHook
GdiplusNotificationUnhook

Maybe this:

http://com.it-berater.org/gdiplus/nofra ... ctions.htm

see this:

"If you do not do this, there will be resource leaks that won't be cleaned up until the process exits."

?????

Also:

GdiplusStartup (*token, @GdiplusStartupInput, @GdiplusStartupOutput)

@GdiplusStartupOutput can be #Null If the SuppressBackgroundThread member of the input parameter is #False. If GdiplusStartupOutput is Not #False then you have To supply a pointer To notification hook function And notification unhook function which are members of the GdiplusStartupOutput Structure. From my understanding its Not necessary To supply the pointers, thus the GdiplusStartupOutput can be #Null, like this:

GdiplusStartup (*token, @GdiplusStartupInput, #Null)

So maybe it would look like this?

Code : Tout sélectionner

ProcedureDLL.l Gdiplus_New(version.l = 1, *hEventCB = #Null, Codecs.l = #False, bgThread.l = #False)
  Protected *token, input.GdiplusStartupInput
  input\GdiPlusVersion = version
  input\DebugEventCallback = *hEventCB
  input\SuppressExternalCodecs = Codecs
  input\SuppressBackgroundThread = bgThread
  GdiplusStartup(@*token, @input, #Null)
  GdiplusNotificationHook(*token)
  GdiplusNotificationUnhook(*token)
  ProcedureReturn *token
EndProcedure
Or, this:

Code : Tout sélectionner

Prototype.l DebugEventProc(level.l, message.p-unicode)

ProcedureDLL.l Gdiplus_New(version.l = 1, Codecs.l = #False, bgThread.l = #False)
  Protected *token, input.GdiplusStartupInput
  input\GdiPlusVersion = version
  input\DebugEventCallback = @DebugEventProc(level, message)
  input\SuppressExternalCodecs = Codecs
  input\SuppressBackgroundThread = bgThread
  GdiplusStartup(@*token, @input, #Null)
  GdiplusNotificationHook(*token)
  GdiplusNotificationUnhook(*token)
  ProcedureReturn *token
EndProcedure
Hi SFSxOI
Before i send this post, i saw Jose Roca's page you've taking to. But no example. It's MS explanations.
For these Hook/unHook functions, MS tell us that input\SuppressBackgroundThread from input parameter must be set To #True.
Using Threads With GDI+ is Not As simple As it seems To be...
MS explains (SDK doc) the ways to avoid crashes.

Almost no infos are given about these functions.

MS tells us this for GdiplusNotificationHook():
The GdiplusStartup function returns (in its output parameter) a pointer to a GdiplusStartupOutput structure. One of the members of the structure is a pointer to a notification hook function that has the same signature as GdiplusNotificationHook.

There are two ways you can call the notification hook function; you can use the pointer returned by GdiplusStartup or you can call GdiplusNotificationHook. In fact, GdiplusNotificationHook simply verifies that you have suppressed the background thread and then calls the notification hook function that is returned by GdiplusStartup.

The token parameter receives an identifier that you should later pass in a corresponding call to the notification unhook function.
and for GdiplusNotificationUnhook():
The GdiplusStartup function returns (in its output parameter) a pointer to a GdiplusStartupOutput structure. One of the members of the structure is a pointer to a notification unhook function that has the same signature as GdiplusNotificationUnhook.

There are two ways you can call the notification unhook function; you can use the pointer returned by GdiplusStartup or you can call GdiplusNotificationUnhook. In fact, GdiplusNotificationUnhook simply verifies that you have suppressed the background thread and then calls the notification unhook function that is returned by GdiplusStartup.

When you call the notification unhook function, pass the token that you previously received from a corresponding call to the notification hook function. If you do not do this, there will be resource leaks that won't be cleaned up until the process exits.
if i well understand, two ways. First using directly and only GdiplusStartup and the other is to call Gdip Hook/unhook functions. With the second way, calling GdiplusNotificationhook will retrun a token but i thing it's not the same as token value received by GdiplusStartup

I use this to init GDI+ With hooks functions (to try to understand):

Code : Tout sélectionner

  ; init Gdi+
  input\GdiPlusVersion = 1
  input\DebugEventCallback = @DebugCallback()  ; to try with debug callback
  input\SuppressExternalCodecs = #False 
  input\SuppressBackgroundThread = #True    ; here to get hooks pointers
;  GdiplusStartup(@*token, *input.GdiplusStartupInput, *output.GdiplusStartupOutput) 
   GdiplusStartup(@*token, @input, @output)    ; call init function
With these code, i get pointer values but my reel question is :

What can i do with these pointers ? :wink:
May be cooking :mrgreen:

No MS explanations, no call by MS C wrapper.

A hook is a point in the Microsoft® Windows® message-handling mechanism where an application can install a subroutine to monitor the message traffic in the system and process certain types of messages before they reach the target window procedure (from MS doc).

How to do this with GDI+ ???

Publié : jeu. 12/avr./2007 23:12
par SFSxOI
Ahhhh...OK, the mystery deepends. The MS documentation also says @GdiplusStartupOutput can be #Null if the SuppressBackgroundThread member of the input parameter is #False. Maybe the notification hook is put on the stack like it is with the GdipSaveGraphics function?

the purebasic structure

Code : Tout sélectionner

Structure GdiplusStartupInput ;{
  GdiPlusVersion.l 
  *DebugEventCallback.DebugEventProc 
  SuppressBackgroundThread.l 
  SuppressExternalCodecs.l 
EndStructure
In GdiPlusInit.h it looks like this:

Code : Tout sélectionner

GdiPlusInit.h also says:

"// Callback function that GDI+ can call, on Debug builds, For assertions
// And warnings.
typedef VOID (WINAPI *DebugEventProc)(DebugEventLevel level, CHAR *message);

// Notification functions which the user must call appropriately If
// "SuppressBackgroundThread" (below) is set.

typedef Status (WINAPI *NotificationHookProc)(OUT ULONG_PTR *token);
typedef VOID (WINAPI *NotificationUnhookProc)(ULONG_PTR token);

Does this mean you don't need the call back except for debug builds?


struct GdiplusStartupInput
{
    UINT32 GdiplusVersion;             // Must be 1  (or 2 for the Ex version)
    DebugEventProc DebugEventCallback; // Ignored on free builds
    BOOL SuppressBackgroundThread;     // FALSE unless you're prepared to call 
                                       // the hook/unhook functions properly
    BOOL SuppressExternalCodecs;       // FALSE unless you want GDI+ only to use
                                       // its internal image codecs.
    
    GdiplusStartupInput(
        DebugEventProc debugEventCallback = NULL,
        BOOL suppressBackgroundThread = FALSE,
        BOOL suppressExternalCodecs = FALSE)
    {
        GdiplusVersion = 1;
        DebugEventCallback = debugEventCallback;
        SuppressBackgroundThread = suppressBackgroundThread;
        SuppressExternalCodecs = suppressExternalCodecs;
    }
};

where DebugEventProc debugEventCallback = NULL, and suppressBackgroundThread = #FALSE

and...the GdiplusStartupOutput structure looks like this

struct GdiplusStartupOutput
{
    // The following 2 fields are NULL If SuppressBackgroundThread is FALSE.
    // Otherwise, they are functions which must be called appropriately To
    // replace the background thread.
    //
    // These should be called on the application's main message loop - i.e.
    // a message loop which is active For the lifetime of GDI+.
    // "NotificationHook" should be called before starting the loop,
    // And "NotificationUnhook" should be called after the loop ends.
    
    NotificationHookProc NotificationHook;
    NotificationUnhookProc NotificationUnhook;
};

see where it says: "These should be called on the application's main message loop - i.e. a message loop which is active For the lifetime of GDI+. "NotificationHook" should be called before starting the loop,  and "NotificationUnhook" should be called after the loop ends.

so...would it look like this?: (pseudo code)

GdiplusStartup
NotificationHook
App Message Loop
NotificationUnhook
GdiplusShutdown(*token)






Publié : lun. 16/avr./2007 13:55
par Anonyme2
Toujours à propos de GDI+

Il est obligatoire d'initialiser au moins une fois GDI+ (on peut le faire plusieurs fois et c'est même recommandé de le faire avec des threads ou des fonctions encapsulées dans une Dll).

A partir du moment ou l'on passe le pointeur d'initialisation à la fonction de "fermeture" de GDI+, les objets deviennent inaccessibles, ma question est la suivante :

SI les objets deviennent inaccessibles, ont-ils été détruits par GDI+ ?

Publié : jeu. 20/sept./2007 18:40
par Ollivier
Bonjour, j'aimerai poser une question à Denis ou Erix14 qui sont assez calés là-dedans.

Depuis que je connais le forum, j'ai découvert (il me semble que c'est déjà par ce post) GDI+. Mais juste de nom. Je ne suis pas rentré dans les détails, car ça me semblait trop lourd. Le simple fait, par exemple de ne pas pouvoir poster un code immédiatement exécutable sur ce forum crée une barrière.

Est-ce qu'il est possible d'énumérer l'ensemble des avantages offerts par le travail colossal que vous avez effectué?

Publié : jeu. 20/sept./2007 18:44
par Backup
ouaip ! en clair Denis t'en est ou avec ta lib 8O :D

Publié : jeu. 20/sept./2007 19:50
par Anonyme2
Salut Dobro (et les autres ) :D

Après un break (obligé) de 3 mois, je suis en train de terminer la doc.
Si je bosse bien, je mettrais en ligne mon exe qui regroupe un peu plus de 820 fichiers dont 683 fichiers d'exemples dans environ 2 à 3 semaines (l'exe fait presque 12 Mo).

Ce n'est pas une lib au sens de PB mais des includesfiles regroupant les fichiers nécessaires.

Après cette première version pour GDI+1.0 qui d'ailleurs est celle qui tourne sous Vista , je me mettrais aux exemples des 21 fonctions suplémentaires introduites par Gdi+ 1.1 (1.1 n'est pas redistribuable mais on peut contourner pour pouvoir utiliser les fonctions des effets comme la correction des yeux rouges ou autre).

Les possibilités de Gdi+ sont assez importantes, mais cela ne touche pas la 3D. Elle ajoute plein de possibilités sur plein de points à la gestion de Gdi.

GDI+ permet (entre autre) :

- graphisme vectoriel en 2D avec gestion possible des coordonnées en nombres réels simple précision.
- Gestion de l'anti-crénelage (anti-aliasing) des images et du texte
- Nombreux formats d'images supportés (BMP, GIF, JPEG, EXIF, PNG, TIFF)
- Gestion de l'échelle des graphiques, on peut faire un zoom d'une image avec peu de code
- Gestion de la transparence
- Gestion différents modes de combinaison de couleur
- Gestion des textures, des brush (différents types de dégradés linéaires)
- Gestion des pen (gestion de différents formats de traits comme les pointillés etc.)
- Possililté de définir les embouts des lignes soit avec des formes prédéfinies soit personnalisées.
- Gestion des région pour obtenir les effets voulus (exclusion, intersection, union et d'autres)
- Gestion des Path (chemin) qui délimitent les contours des formes géométriques, ces formes pouvant être remplies avec des brush dédiées.
- Gestion des Container graphiques (c'est un peu comme une pile, on peut entasser ou superposer des dessins avec leur zones et revenir au container précédant)

Après ces 9 mois de travail sur Gdi+, je dirais une chose. Il faut savoir utiliser les callback windows et éviter les callback PB et proscrire complètement l'événement repaint dispo dans PB, les résultats sont assez mauvais, même si beaucoup de mes exemples utilisent ces méthode, c'est d'ailleurs à cause de cela que je me suis rendu compte des problèmes.

Gdi+ nécessite que le rafraichissement des images ou objet soit fait par l'utilisateur, le système ne le fait pas. Les résultats sont parfois meilleurs avec les thèmes XP activé. Sur de grosse images, Gdi+ est lent, c'est pour celà qu'il serait nécessaire dans des applications de ne redessiner que la zone modifiée comme la superposition des fenêtres etc.

L'approche de Gdi+ nécessite pas mal de travail si on veut comprendre comment ça marche. La doc MS est pratiquement inexistante, je me suis basée sur ce que j'ai pu trouver sur le wrapper C et celui de .Net. Pour certaines fonctions, c'est par déduction que j'en tire des conclusions. Certaines fonctions restent de grandes inconnues :roll:

Microsoft a volontairement orienté la doc sur son wrapper C et .Net en disant même qu'il est préférable de ne pas utiliser directement les fonctions. A aujourd'hui, mon ordi n'a pas encore fumé suite à l'utilisation de Gdi+.

La doc est une explication des paramètres et de ce que l'on est en droit d'obtenir, mais certaines fonctions ont des paramètres qui peuvent prendre différentes valeurs, je n'ai pas testé toutes les valeurs.

J'ai vraiment eu du mal avec certaines fonctions de gestion des métafichiers.

Publié : jeu. 20/sept./2007 19:55
par Backup
ben dit donc, t'es un courageux toi :D

Publié : jeu. 20/sept./2007 20:23
par Ollivier
C'est clair!

Publié : lun. 24/sept./2007 18:16
par Flype
Denis a toujours été un grand bosseur.
Merci d'avance pour l'énooooorme travail fournit.
J'ai hâte d'essayer tout tes exemples et bravo pour la compatibilité vista, c'est une bonne nouvelle çà.

Publié : lun. 24/sept./2007 19:16
par Anonyme2
Je teste et reteste sous Vista mes exemples d'origine et ceux issue de l'extraction; je viens de passer 2 jours sur une fonction dont l'exemple va bien sous XP mais j'ai une erreur d'accès mémoire sous Vista.

J'en ai déduit que j'avais mal interprêté la fonction (car pas d'explication de MS), je corrige la doc encore et toujours...


alzheimer ... :D

Publié : lun. 24/sept./2007 19:29
par Flype
:wink:

Publié : jeu. 11/oct./2007 21:06
par erix14
En attendant la doc de Denis, je vous propose une petite démo GDI+. C'est le début d'un logiciel de dessin vectoriel. Vous pouvez faire des lignes et des cercles, les sélectionner en cliquant dessus et les supprimer. Pour tout désélectionner, cliquer à côté. J'espère que cela va vous faire aimer GDI+ :) http://www.rx14.info/archives/GDIDemoRX.exe

Publié : jeu. 11/oct./2007 21:32
par Anonyme2
Excellent la démo :D