This project is read-only.

Changes Coming for GDIPlusX

Topics: General, Attention VFPX Admins
Jun 19, 2007 at 11:20 AM
Edited Jun 19, 2007 at 11:22 AM
I've been working on optimizing the GDIPlusX class libraries recently. The library has been in ALPHA for about a year and I would like to get it into BETA status this month.

Even though some of the code was generated, it has been quite a bit of work getting it to the stage it is now. It seems pretty stable. I've gotten a lot of positive feedback from people using it and Ceasar Chalom's samples and blog entries have surly helped to stabilize and enhance the library.

To take it to the next level we will be taking the following actions:

  • Any of the classes that have not been started (particularly the “converter” classes) will be removed from the library and will be added back in a future version. These classes don’t seem to be super useful right now and removing them will help get the remaining classes into a production version faster.
  • An FLL will be created to accompany the library. This is mainly to deal with the Stream classes and methods that require callbacks but we will also be incorporating some functionality that could really benefit from being written in C++, such as a palette generator for GIFs.
  • An updated help file will be created. We could use some assistance with this one if anyone wants to help out.
  • This is a BIGGIE, the entire library will be converted to .PRG based classes. There are several reasons for this:
    • Stability and Speed – each class DECLAREs the API functions it needs when it initializes. If somewhere along the way, someone issues a CLEAR DLLS or re-DECLAREs the function, the GDIPlusX library could error. We will employ a technique I first saw in the Web Connection framework where we will wrap each API function in a VFP function that auto-DECLAREs the API function when it is first called. I thought this was a pretty clever solution because each successive call will go directly to the API function because it has priority over the UDF. If for some reason the DECLARE is lost, the UDF auto-DECLAREs the API function again. We will also alias each function so there is no parameter conflict with any other DECLARE of the same function. And because these will be in the PRG with the class, the class will always find it. You don’t have to have a “SET PROCEDURE TO”. Here is an example:

FUNCTION xfcGdipGetPageUnit(hGraphics, nUnit)
    DECLARE LONG GdipGetPageUnit IN GDIPLUS.DLL ;
        AS xfcGdipGetPageUnit ;
        LONG hGraphics, LONG @nUnit
    RETURN xfcGdipGetPageUnit(m.hGraphics, @m.nUnit)
ENDFUNC

    • Stability and Speed – The base class for the GDIPlusX library includes a method called “CreateNew”. This method came about because we wanted to avoid using the “NEWOBJECT” function. We discovered early on that NEWOBJECT could be 2x to 3x slower than calling a SET CLASSLIB TO…ADDITIVE with a CREATEOBJECT and because we want as much performance from a drawing library as we can get, we opted to wrap the SET CLASSLIB/CREATEOBJECT functionality up in a single method. If we are using PRG based classes, this is a non-issue. If we are instantiating a class within the same PRG, we only need to issue CREATEOBJECT. There is no need for SET PROCEDURE TO or NEWOBJECT.
    • Speed – We noticed that instantiation times were 3x to 8x faster for PRG based classes over VCX based classes. The more members the class has, the slower the VCX was to instantiate. I’m guessing there is more overhead in parsing the members out of the VCX table than just using the compiled PRG. Whatever it is, it is a significant difference.
    • Size – One of the most common complaints I have gotten about the library is the size. It can add about 1.5MB to a compiled EXE. That doesn’t seem like a lot for the amount of functionality you gain, but a couple of users said they avoided using GDIPlusX in their projects because they only needed to use a small fraction of the library and that 1.5MB was too much overhead to justify it. By putting all of the classes into a PRG, not only will the compile size be smaller than the VCX (about 500KB) but we will also be able to provide compile time directives to #DEFINE out any functionality you don’t need. If you only needed to open a JPEG and read out the EXIF data, for example, you could #DEFINE out all the classes you didn’t need and get the library down to 10KB or less compiled.
    • Negative – The down side to this is that anyone using the library in production now may have to change their implementation. If you are instantiating all of your classes via the _SCREEN.System object, then there should be no problem. You just need to change the way the “System” object is instantiated. All other code should remain unchanged.

Once we have finished (or mostly finished) these 4 items we will move the library’s status to BETA and then hopefully to PRODUCTION by the end of July.

We welcome any feedback and we would like to know how you are using the GDIPlusX library.

Thanks,
Bo Durban
GDIPlusX Project Manager
Jun 21, 2007 at 12:07 AM
Thanks for posting this announcement Bo. I can't wait to try out the library once the conversion to PRGs is completed. Will active development be done using the PRGs from now on? What type of break out for the PRGs have you decided on? Using .NET namespaces or grouping by functionality? For what it's I still think the former is a better idea for a number of reasons (easy, logical, organized, lends itself to other .NET namespaces being created in the future, etc.. Will GDIPlusX allow the developer to use the library without the FLL (check whether SET LIBRARY TO has been called on the FLL and if not use the older code that is not reliant on the FLL) or will the FLL be mandatory moving forward?

The compiler directives are a great idea. The Function/Declare trick you are proposing of implementing for the API calls is nice as well. I like the way Microsoft did it using an object that wrapped all the gdiplus API functions, but I must admit that the solution you are going to implement is simple and very elegant. Thanks to you and Ceasar for all of your hard work on this amazing GDI+ class library.

PS Have we figured out a good way to allow the library to be compatible with the _gdiplus.vcx that ships with Visual FoxPro 9.0? It would be cool if developers could take advantage of existing code base that utilizes the _gdiplus.vcx while enjoying the multitude of classes, features, and improvements provided by the significantly more robust GDIPlusX library. I know you, Ceasar, and I talked about it at one time and there seemed to be some workable ideas at the time.
Jun 21, 2007 at 1:33 PM




craigsboyd wrote:
What type of break out for the PRGs have you decided on? Using .NET namespaces or grouping by functionality?

I think we should add some #Defines in the PRG in order to separate each of the original VCX classes. This way, it will be easier for us to do some maintenance, and to users to compile just some pieces of the library.



craigsboyd wrote:
Will GDIPlusX allow the developer to use the library without the FLL (check whether SET LIBRARY TO has been called on the FLL and if not use the older code that is not reliant on the FLL) or will the FLL be mandatory moving forward?


IMO, the FLL will just bring some additional functions that require a great speed of processing, like GIF optimization, using the Octrees technique, and for the management of streams that require callbacks...
Bo, did you manage to test the classes that I created for streams ? I'm really not sure if the FLL is really needed, because the performance was exactly the same from the ActiveX created by Calvin Hsia, and in my tests, memory is being released properly... What did you find on that ?


craigsboyd wrote:
The Function/Declare trick you are proposing of implementing for the API calls is nice as well.

Hey Bo, that's so simple, and so nice !
I've learned another good one! Thanks !


craigsboyd wrote:
PS Have we figured out a good way to allow the library to be compatible with the _gdiplus.vcx that ships with Visual FoxPro 9.0? It would be cool if developers could take advantage of existing code base that utilizes the _gdiplus.vcx while enjoying the multitude of classes, features, and improvements provided by the significantly more robust GDIPlusX library. I know you, Ceasar, and I talked about it at one time and there seemed to be some workable ideas at the time.


At this moment, people from _gdiplus.vcx can use some specific objects created by GdiPlusX, like the special brushes - Gradient and Path Gradient and Texture brushes, just passing the GdiPlusX brush as a parameter. The use of Image Attributes is also available, and an ImageAttribute object can be created in GdiPlusX, with all parameters needed and passed as a parameter to the "DrawImageRectRect" method.

But do you want to know the truth ? I am subscribed to many VFP forums, and I have never seen any question regarding this. ADvanced users already know how to do that, getting the GDI+ handles, and using them when needed.

For my personal case, at the beginning, I started using some brushes and other stuff from GdiPlusX with _GdiPlus.vcx . But the code became a little bit confuse... and after I got really familiarized with "X", I converted all codes so fast. After that, my code became much easier to understand, and debug... Today I don't have any code from the legacy libraries.

But that's a good idea for a future blog post indeed.

It's very nice to see you back Craig !
Your presence brings the enthusiasm that people need !
Jun 25, 2007 at 12:52 PM
Thanks for the feedback.


craigsboyd wrote:
Will active development be done using the PRGs from now on? What type of break out for the PRGs have you decided on? Using .NET namespaces or grouping by functionality? For what it's I still think the former is a better idea for a number of reasons (easy, logical, organized, lends itself to other .NET namespaces being created in the future, etc..


Yes, PRGs will soon replace the library VCXs. However, the imgCanvas class, and derivatives, will remain visual classes.

The breakout will be by namespace. The PRGs may even be named by thier namespace:
  • System.prg
  • System.Drawing.prg
  • System.Drawing.Drawing2D.prg
  • etc...


craigsboyd wrote:
Will GDIPlusX allow the developer to use the library without the FLL (check whether SET LIBRARY TO has been called on the FLL and if not use the older code that is not reliant on the FLL) or will the FLL be mandatory moving forward?


If the FLL is there, the library will use it. If it is not there and the function can be completed without the FLL, it will do it. If the function will only work with the FLL and it is not there, an error will occur. The help file will designate which functions require or are optimized by the FLL.


craigsboyd wrote:
PS Have we figured out a good way to allow the library to be compatible with the _gdiplus.vcx that ships with Visual FoxPro 9.0? It would be cool if developers could take advantage of existing code base that utilizes the _gdiplus.vcx while enjoying the multitude of classes, features, and improvements provided by the significantly more robust GDIPlusX library.


There is already code in place to allow interaction between GDIPlusX and _GDIPlus FFC classes. If someone is having a compatibility issue, they should report it so we can address it.


CesarChalom wrote:
Bo, did you manage to test the classes that I created for streams ? I'm really not sure if the FLL is really needed, because the performance was exactly the same from the ActiveX created by Calvin Hsia, and in my tests, memory is being released properly... What did you find on that ?


I am still testing. If we can make this work without an FLL and without memory leaks, we should keep it Fox code.

Thanks,
Bo Durban
Oct 11, 2007 at 7:36 AM


binarybo wrote:

... each class DECLAREs the API functions it needs when it initializes. If somewhere along the way, someone issues a CLEAR DLLS or re-DECLAREs the function, the GDIPlusX library could error. We will employ a technique I first saw in the Web Connection framework where we will wrap each API function in a VFP function that auto-DECLAREs the API function when it is first called. I thought this was a pretty clever solution because each successive call will go directly to the API function because it has priority over the UDF. If for some reason the DECLARE is lost, the UDF auto-DECLAREs the API function again. We will also alias each function so there is no parameter conflict with any other DECLARE of the same function. And because these will be in the PRG with the class, the class will always find it. You don’t have to have a “SET PROCEDURE TO”. Here is an example:

FUNCTION xfcGdipGetPageUnit(hGraphics, nUnit)
    DECLARE LONG GdipGetPageUnit IN GDIPLUS.DLL ;
        AS xfcGdipGetPageUnit ;
        LONG hGraphics, LONG @nUnit
    RETURN xfcGdipGetPageUnit(m.hGraphics, @m.nUnit)
ENDFUNC



Nice way to handle the API declares. I will be using this in the ctl32 classes. Thxs!

Carlos Alloatti