Disclaimer: I'm only getting started in C, so it's likely that I'm missing something obvious, or not thinking the right way! :)
How exactly would I go about using GDI+ in pure C?
As I understand it, GDI+ has wrapped objects made for C++, but underneath it lies a flat API which is accessible through gdiplusflat.h
, a C-friendly header.
My problem is that when I #include it, I get the following errors:
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\gdiplusflat.h(30) : error C2143: syntax error : missing '{' before '__stdcall'
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\gdiplusflat.h(31) : error C2146: syntax error : missing ')' before identifier 'brushMode'
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\gdiplusflat.h(31) : error C2061: syntax error : identifier 'brushMode'
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\gdiplusflat.h(31) : error C2059: syntax error : ';'
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\gdiplusflat.h(31) : error C2059: syntax error : ','
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\gdiplusflat.h(31) : error C2059: syntax error : ')'
and 100 more...
Now, I think these errors are due to GpStatus
not being defined because peeking into GdiPlusFlat.h
shows that all the functions are of the style:
// WINGDIAPI is #defined as __stdcall
GpStatus WINGDIPAPI
GdipCreatePath(GpFillMode brushMode, GpPath **path);
GpStatus WINGDIPAPI
GdipCreatePath2(GDIPCONST GpPointF*, GDIPCONST BYTE*, INT, GpFillMode,
GpPath **path);
GpStatus WINGDIPAPI
GdipCreatePath2I(GDIPCONST GpPoint*, GDIPCONST BYTE*, INT, GpFillMode,
GpPath **path);
etc...
The problem is that GpStatus
is a typedef to Status
in GdiPlusGpStubs.h
(a C++ header), and Status
is itself an enum defined in GdiPlusTypes.h
(also a C++ header). I tried defining the enum myself, but for some reason the compiler wouldn't take it!
So... how does one exactly use GDI+ functions in C? Should I just load gdiplus.dll dynamically?
The problem is that gdiplusflat.h really needs many more gdi*.h header files included before it. But many of these header files that have the needed typedef declarations referenced by gdiplusflat.h also contain "class" declarations and other C++ keywords. The C compiler will error out when it sees these lines.
You have two choices.
Simple. Accept the fact that C++ is essentially a superset of C. Then just rename your ".c" file you are trying to compile to have a ".cpp" extension. Your C code will get compiled as C++, but that likely won't change a line of code you write. Then #include gdiplus.h before you #include gdiplusflat.h
Harder. depends on typedef definitions in other header files. The problem is that many of these header files have "class" definitions and C++ keywords that the C compiler will error out on. You'll have to manually port over many of the C declarations into your own header file that gets included before gdiplusflat.h. Here's my feeble attempt. It's not quite done. It gets half of the compilation errors out. But I got too tired and just went with option #1. You could finish it, but option 1 above is so much easier.
x
enum Status
{
Ok = 0,
GenericError = 1,
InvalidParameter = 2,
OutOfMemory = 3,
ObjectBusy = 4,
InsufficientBuffer = 5,
NotImplemented = 6,
Win32Error = 7,
WrongState = 8,
Aborted = 9,
FileNotFound = 10,
ValueOverflow = 11,
AccessDenied = 12,
UnknownImageFormat = 13,
FontFamilyNotFound = 14,
FontStyleNotFound = 15,
NotTrueTypeFont = 16,
UnsupportedGdiplusVersion = 17,
GdiplusNotInitialized = 18,
PropertyNotFound = 19,
PropertyNotSupported = 20,
#if (GDIPVER >= 0x0110)
ProfileNotFound = 21,
#endif //(GDIPVER >= 0x0110)
};
typedef Status GpStatus;
enum FillMode
{
FillModeAlternate, // 0
FillModeWinding // 1
};
typedef FillMode GpFillMode;
struct GpPath {};
typedef float REAL;
struct GpPointF
{
REAL x;
REAL y;
};
struct GpPoint
{
int x;
int y;
};
#include <gdiplusflat.h>