This is why the Embarcadero RAD Studio RTL WinApi.GDIPOBJ.pas unit, at the bottom of the file initialization section, checks “if not IsLibrary” to initialize GDI+ only when the unit is used by an executable application.
The problem is, if you have a DLL that contains chart controls, and if GDI+ has not been correctly initialized, an Access Violation exception will be raised from code inside the Windows GDI+ gdiplus.dll !
The solution is quite easy. In your EXE application, before calling any DLL function, add this code to initialize GDI+ :
It is also recommended (although it doesn’t seem mandatory), to uninitialize GDI+, as one of your EXE last steps:
The next TeeChart release (very soon !) will include a small fix to improve this situation: if GDI+ is not initialized for any reason, it will fallback to “old” GDI graphics instead, avoiding the exception.
Click here to download a simple test project made in Delphi with RAD XE5 that includes an EXE and a DLL. The DLL contains a Form1 with a Chart1. The EXE main unit initializes GDI+ and calls the DLL to show the chart.
While part of the Steema team was at the Mobile World Congress and WIPJam events in Barcelona, getting acquainted with the novelties on the mobile sector, some of us remained at the office in Girona working on some vintage stuff, let’s call it.
Over the years, one of the recurring questions with TeeChart Pro VCL/FMX has been how to create a transparent chart. We have an old Delphi demo project which accomplishes this. It consists of an image in a form and a chart over it. The goal is to make the chart transparent so that the image can be seen through the chart background. This is achieved by first making the chart back wall transparent and then, generating a bitmap the size of the chart from the background image at the chart location and drawing it on the TChart canvas. This process produces a chart like that:
which still is an interactive chart which responds to mouse action: clicks, zoom, panning, etc.
Pretty simple in Delphi, huh? Now let’s complicate things a little bit. We were faced with the question of how to do the same with TeeChart ActiveX. Actually, I don’t know why this didn’t come up before or, if it had been asked for, I was not aware of it. Anyway, this wouldn’t have sounded that complicated if it hadnn’t been because it ended up being a Frankenstein project, since it needed to be TeeChart Pro ActiveX in VB.NET. So a nice COM/.NET mix. Well, this may not make a Frankenstein but wait, the sophistication doesn’t end here. As you may already know, TeeChart Pro ActiveX is a COM wrapper of the TeeChart Pro VCL/FMX version, so an intriguing mixture of Delphi (VCL) code with ActiveX objects and .NET methods/properties. It doesn’t sound that straightforward now, does it?
Ok, let’s break things into different parts and will see how the original Delphi code was literally ported to VB with TeeChart ActiveX. First of all, setting the chart panel to be transparent gets somewhat complicated when mixing ActiveX and .NET worlds:
That tricky conversion is the only remarkable part of initial chart settings. The substantial code is in the OnBeforeDrawChart event though. That’s how it looks like in Delphi:
procedure TForm1.Chart1BeforeDrawChart(Sender: TObject);
if not Assigned(Back) then
if Chart1.Color=clNone then
All that fuss for about 10 lines of code!? Well, first I should admit that Steema’s .NET language of choice is C#. So I have some difficulties converting C# to VB. Luckily, most of them are solved using Carlos Aguilar’s VB to (and from) C# code translator. You’ll also notice that I’m not an expert on code formatting in WordPress either. I must admit this is my very first article and found that Posting Source Code suggested solution doesn’t work very well for me. I hate poorly indented code so any help on this will be appreciated.
Ok, back on track, I needed to find out which is the equivalent method of Delphi’s CopyRect, which basically copies a part of an image into another image canvas. This can be done with System.Drawing.Graphics.DrawImage method. It has several overloads so I had to find out the one that does the same as CopyRect in Delphi. The most similar overload I could find is this. With a little help from a search engine I found that that simple Delphi call would turn out to be another 10 line method in VB:
Private Function CopyRect(ByVal srcBitmap As Bitmap, _
ByVal destRect As Rectangle, ByVal srcRect As Rectangle) As Bitmap
' Create the new bitmap and associated graphics object
Dim bmp As New Bitmap(srcRect.Width, srcRect.Height)
Dim g As Graphics = Graphics.FromImage(bmp)
'Draws the specified portion of the specified Image at the specified location and with the specified size.
g.DrawImage(srcBitmap, destRect, srcRect, GraphicsUnit.Pixel)
' Clean up
' Return the bitmap
It would look like I was halfway done but I found that I was completely wrong. ActiveX controls don’t have ClientRect property that Delphi controls have. I also had to manually create BoundsRect. Nothing complicated but something the almighty Delphi also did for me:
Dim ClientRect As Rectangle = New Rectangle(0, 0, AxTChart1.Width, AxTChart1.Height)
Dim ChartBounds As Rectangle = New Rectangle(AxTChart1.Location.X, AxTChart1.Location.Y, _
So now that all the elements are in place, I just needed to paint the resulting bitmap to TeeChart’s canvas. But wait, another ActiveX vs .NET trick was still waiting for me. Calling Canvas.Draw on TeeChart ActiveX with a .NET Framework native System.Drawing.Bitmap was showing a warning about an image format conversion issue. Besides of that, I decided to go ahead but the warning turned to a run-time error. I had to convert the .NET bitmap to a stdole.IPictureDisp. Thanks to this article I learned that I had to create an additional class derived from AxHost to have access to some private methods of this class that would do the conversion for me. I copied the class, converted it to VB with the mentioned code translator and I was all set to paint the image into TeeChart’s canvas:
If AxTChart1.Panel.Color = Convert.ToUInt32(ColorTranslator.ToOle(Color.Transparent)) Then
Dim backImage As stdole.IPictureDisp = AxHostConverter.ImageToPictureDisp(Back)
AxTChart1.Canvas.Draw(0, 0, backImage)
Now all code was complete and I could run and see the result. I went for it and, to my deception, I found that the image from the picture box was always in the original size; it didn’t come out with the stretching method I was using:
Once again, Delphi handled this nicely without having to implement any additional code. So, time to scratch my head a little bit more and thanks to internet, I found that I had to create an intermediate image with the stretched image dimensions which resulted in this method:
Private Function GetStretchedImage(ByVal image As Image) As Bitmap
If PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage Then
Dim bmp As Bitmap = New Bitmap(PictureBox1.Width, PictureBox1.Height)
Dim g As Graphics = Graphics.FromImage(bmp)
g.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
g.DrawImage(image, New Rectangle(Point.Empty, bmp.Size))
Phew! This finally produced the result I expected and what was so simple to do in Delphi:
These pages are intended to bring together comments and articles from various contributors in the Steema team with the goal of 1) adding value to the basic information beyond the standard Steema newsfeed, forums and product documentation and 2) to humanise a little the interface that our web presence presents to the “inter-world”.