Click to See Complete Forum and Search --> : GDI+ via dynamic linking


dc_2000
February 21st, 2006, 03:23 AM
Hi all:


I'm new to GDI+. Can someone tell me if it's possible to use GDI+ via dynamic linking. If yes, then how?

My problem is that I need to use it in my program for a simple drawing, which has nothing to do with the main purpose of the program, but it statically links it to GDIPLUS.DLL, which won't let it run on earlier versions of Windows.

And one more thing, I'm not using MFC.

Thanks in advance.

ovidiucucu
February 21st, 2006, 10:25 AM
First of all you have to add
#pragma comment(lib, "gdiplus.lib")
somewhere in your source code. Be sure "gdiplus.lib" location is added in "Directories" option, else write full path and file name in pragma comment.
Second, include <gdiplus.h>.
If your API has not defined ULONG_PTR, then define it yourself. Also include <objbase.h> before gdiplus.h:

#include <windows.h>
// ....
// ...
typedef unsigned __int32 ULONG_PTR;

#include <objbase.h>
#include <gdiplus.h>
#pragma comment(lib, "gdiplus.lib")
using namespace Gdiplus;
// ...
// ...

Further you have to initialize GDI+ by calling GdiplusStartup.
Next, enjoy...

Note also that you have to redistribute gdiplus.dll if the target system is older than Windows XP (best place for it is in your application directory).

Attached here is a "Hello World" Win32 appication transformed in a GDI+ one. ;)
Search for "// GDI+ stuff" comments to see what I have added.


PS. Just asside remark: I have never heard until now about an application "statically linked with GDI+".

ovidiucucu
February 21st, 2006, 10:43 AM
[...] but it statically links it to GDIPLUS.DLL, which won't let it run on earlier versions of Windows.
And to clarify a little.
An application is always dinamically linked to a DLL, as long as DLL means Dynamic-Link Library.

However I hope that my previous hints can help you to solve the problem.

dc_2000
February 21st, 2006, 11:33 AM
Thanks for your example & explanation. What I actually meant by "dynamic" linking is this:

Consider this situation -- you need to call SetSuspendState() API available on Windows 98 and later. You can call it two ways:

(1) Static Linking
//In the header
#include <Powrprof.h>
...

//When in use
SetSuspendState(TRUE, TRUE, TRUE);

(2) Dynamic Linking
//During code initialization
HMODULE hPwrProf;
FARPROC pfnSetSuspendState = NULL;
hPwrProf = LoadLibrary("powrprof.dll");
if(hPwrProf)
{
pfnSetSuspendState = GetProcAddress(hPwrProf, "SetSuspendState");
}

...

//When in use
if(pfnSetSuspendState)
(reinterpret_cast<BOOLEAN (WINAPI *)(BOOLEAN, BOOLEAN, BOOLEAN)>
(pfnSetSuspendState))(TRUE, TRUE, TRUE);

The principle difference is that code #1, although being simpler to program, will make the whole app incompatible with Windows 95 -- when someone attempts to load it there they'll see an error message, something like this: "A required DLL file, PowrProf.dll was not found."

That is what I am trying to avoid with GDI+. Any suggestions???

ovidiucucu
February 21st, 2006, 12:37 PM
Anyway and anyhow, no matter if you use LoadLibrary + GetProcAddress or something else GDI+ does not work on Windows 95 platform.
Anyway and anyhow, no matter if [...]
GDIPLUS.DLL is included Windows XP and the Windows Server 2003.
You have to redistribute (ship with your application) GDIPLUS.DLL for: Windows NT 4.0 SP6, Windows 2000, Windows 98, and Windows ME.

I have almost quoted that from HERE (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdicpp/GDIPlus/GDIPlus.asp).

Do as I said, deliver GDIPLUS.DLL together with your application (put it in the application folder), and all will be OK (except in case of Windows 95).
Anyhow, LoadLibrary + GetProcAddress do not help you anyway if GDIPLUS.DLL is not on the computer.

dc_2000
February 21st, 2006, 02:26 PM
Well, I agree that GDI+ won't work on Windows 95 but my point is that even if I supply that GDIPLUS.DLL in a folder for my app the static linking with GDI+ won't let the whole app run on Windows 95 and a user will see a simple system error message -- which is not good!

You see the app has nothing to do with graphics and GDI+, all I need it for is to save a logo as a PNG or TIFF file. If this functionality is not present on Windows 95 I still want my app to run. You see my point?

ovidiucucu
February 22nd, 2006, 02:42 AM
Well, on your way, you can use GDI+ Flat API (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdicpp/GDIPlus/GDIPlusreference/flatapi.asp) with LoadLibrary/GetProcAddress. Eventually, you can build your own "Win95 safe" classes around them.
Here is a little example of loading an image from a file:

typedef GpStatus (WINGDIPAPI* pfnLoadImageFromFile)
(GDIPCONST WCHAR* , GpImage**);

GpImage* pImage = NULL;
HMODULE hModule = LoadLibrary("gdiplus.dll");
if(NULL != hModule)
{
pfnLoadImageFromFile pFn
= (pfnLoadImageFromFile)GetProcAddress(hModule,
"GdipLoadImageFromFile");
if(NULL != pFn)
{
GpStatus status = pFn(L"c:\\courage.png", &pImage);
if(Ok == status)
{
// say "I'm lucky"
}
}
FreeLibrary(hModule);
}

However, it's not guaranteed that gdiplus.dll it's present or not on whatever computer.
On Windows 95, initially it's not, but never know, somebody can put it there.
In that case both LoadLibrary and GetProcAddress will succeed and the result is not predictable (most possible your program will harmfully crash).
So, I would like to suggest safer alternatives:

Determine Windows Version and Edition (http://www.codeguru.com/cpp/misc/misc/system/article.php/c8973/). If results an OS which does not support GDI+ do not call GDI+ stuff.
Build different project configurations for GDI+ supported and not. In "Preprocessor directives" project settings field add for example GDIPLUS_SUPPORTED constant for the configuration which must support GDI+. Then, in your code

#ifdef GDIPLUS_SUPPORTED
// GDI+ stuff here
#endif

dc_2000
February 22nd, 2006, 04:17 PM
Yeah, thanks. I thought to do it this way.

dc_2000
March 1st, 2006, 12:46 AM
Hey, just for the information I was able to compile GDI+ project via dynamic linking to GDIPLUS.DLL. I updated your sample code and attached it here.

The way to link to GDI+ dynamically is to simply "unwrap" Gdiplus class methods by stepping into them with debugger, and also not to use "gdiplus.lib" while linking.

One interesting thing is that this sample worked under Windows 95 for me (provided I copy GDIPLUS.DLL into the app's folder.)

ovidiucucu
March 1st, 2006, 03:38 AM
Usually a software manufacturer has some good reasons to not recommend whatever product for whatever target operating system.
However, in your particular case of using only a small subset of functions, if it works on Windows 95, that's good (cannot test it but I believe you ;)).
And I can bet there is no reason to not work also the "static" linking at build time.

BTW. Nice example.;)

MrViggy
March 1st, 2006, 10:29 AM
Just an FYI guys, the MSVC linker has an option called '/DELAYLOAD:{dll name}'. Basically, this tells the app NOT to load implicitly linked DLLs at app startup time. It loads the DLL when a function from that DLL is needed.

Viggy

ovidiucucu
March 1st, 2006, 10:40 AM
Just an FYI guys, ...
If it's just FOI, we'll keep it secret. Promise. :D ;)

dc_2000
March 1st, 2006, 02:27 PM
And I can bet there is no reason to not work [on Windows 95] as the "static" linking at build time.
Agree. But again, the main purpose of compiling code like in this sample is to get rid of GDIPLUS.DLL dependency in case it is insignificant for the project. Moreover the DLL itself is 1.5 MB in size and I don't know if I would want to include it in the installation.

Now regarding delayed loading of DLLs. I understand that this is an "easy fix" -- simply add two linker directives and it's done. Here is the major downside: You cannot control error messages that will be shown for the user, and your app won't know if DLL is loaded or not.

Moreover in the updated sample I attached here, the static built with delayed loading of gdiplus.dll crashes on Windows 95 for me. Try it yourself. (I could not isolate that dll in Windows XP, so I assume it will always work there.)

To build it as "static" linking to GDI+ un-comment the following line in StdAfx.h file:

//#define DELAY_LOAD_GDIPLUS

MrViggy
March 1st, 2006, 03:11 PM
I believe the correct terminology is "implicit" linking (this is when you link with the proxy .lib), and "explicit" linking.

Well, my point was more of do the same thing your doing now (wrap all calls to GDI+ objects), but you can remove all the calls to "LoadLibrary" and "GetProcAddress". Maybe. I've never done this, so, YMMV.

Viggy