Sign in to follow this  

Question about what to consider when making C++ wrapper classes for Win32

This topic is 4205 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a question regarding C++ Wrapper classes. I have some experience with C and classes seem kind of odd to me. What things should I consider in order to create a wrapper, say for Win32 GUI code? Everytime I create a class Win32 code seems to not want to compile and complains about WINAPI and other Win32 objects not being defined. Also is it even possible to truly make a wrapper class since Win32 is older than dirt? Thank you in advance for any replies!

Share this post


Link to post
Share on other sites
Quote:
Also is it even possible to truly make a wrapper class since Win32 is older than dirt?


C is older than the Win32 API. What's your point?

Yes, it is entirely possible to write a wrapper around Win32 API functions. If you are getting errors, its because you are doing something wrong. Possibly missing an #include, not linking with the right libraries, or writing illegal C++ (dispite what you might think, C++ is quite a different language from C).

The other question is, why bother? There are plenty of existing wrappers or, quite frankly, better languages (C# + .NET) for GUI development.

Share this post


Link to post
Share on other sites
Well no need to be rude or a jerk. I am trying to better understand the methodology behind wrapping a class around the Win32 interface, and what things I need to understand to do it. I don't necessarily want to blindly use a class thats already been created because I am not going to understand why it works if I don't try. I find most tutorials "show you how to do it", they don't explain the "why's" regarding why you do it. To me, the class is very odd considering I have only done coding in languages that are non-OOP based and most C++ books do that lame Critter caretaker program which is just confusing as hell.

My point is that the Win32 is antique, it was mainly used for C programming and was not written with a perspective on OOP languages from what I can tell, so is it hard to wrap in a C++ class or nearly impossible to wrap the API completely? As I said, C++ is an enigma and I am trying to understand it since I can program somewhat decently with the Win32 API. I was hoping for rational info if anyone can provide some.

Share this post


Link to post
Share on other sites
If you don't understand OOP, I would reccommend using an OOP library before you try to write one. Perhaps using MFC or wxWidgets. Or better yet giving Java or C# a try.

Share this post


Link to post
Share on other sites
I'm just being blunt.

However, I'm confused. If the "concept" of a class seems foreign or confusing to you (it seems likes that's what you are saying), you aren't going to want to jump into something like trying to build a collection of classes for handling Windows GUI programming. The OO paradigm is much, much more than just using the "class" keyword in C++ instead of "struct," and sticking some member functions in your class.

The desire to want to understand how something works rather than just blindly using it is commendable. However, attempting reimplementation doesn't always lead to understanding, and can very often lead to the acquision of incorrect information, especially when you bite of more than you can chew.

You might want to start with something a little less ambitious than OO Win32 wrappers (which will be fraught with not only the perils of sane object-oriented design, but also the perils of Win32 and the perils of C++). But perhaps more ambitious than whatever this "critter caretaker" example you mentioned is (I have never heard of it before).

There are many reasons why the Win32 API is in C. Some good, some bad. Among them, however, is the fact that C is very, very good at interoperating with other languages (and its pretty easy to do).

Share this post


Link to post
Share on other sites
Learn the language you're going to use first. Wrapping Win32 to get basic functionality up should take 2-4 hours and it does go well with OO. It's all in how you design your classes. I'm not trying to be rude, I'm trying to help.

I was in your shoes a few years ago when I moved from C to C++. Get a good book on C++ and know that language inside and out (it's QUITE different then C compared to what most people think I find).

Start with a simpler project and work with the console to leave out the Windows issue to make life easier too. Walk before you run :)

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I don't like posting here because of the numerous ignorant/immature users like sgalland who are running on empty when it comes to the facts and are quick to accuse others of being rude or a "jerk." I find that anything you say that is contrary to their opinion and that isn't qualified with platitudes is automatically interpreted as a flame by these nitwits.

Share this post


Link to post
Share on other sites
Thank you for the responses, and sorry for the attitude, I read what I wrote and I sounded like a jerk. Anyhoo, what are some good C++ books, I have 3 books, C++ for game programming for beginners, C++ for dummies (worst c++ book written), and C++ in 21 days and frankly the C++ class section are all critter programs or classes that seem impossible to decipher. I for some reason just don't understand the class paradigm although they seem simple in theory, they seem to be a complex subject. Maybe I should just stick with C :)

Share this post


Link to post
Share on other sites
A class is a datatype, in the same way that a C struct is. You can create instances (also referred to as objects in OO parlance; C structs normally just have "instances" when spoken of by C programmers, if they even bother to distinguish concept of the type from the concept of the instantiations) of it in basically the same ways as in C. However, in C++ you can also provide member functions in addition to data members, 'protection' of members (public/private/protected access levels), inheritance (explained below), and some "auto-run" functionality (constructors and destructors): special functions that are run when an object of the class is instantiated and when it is cleaned up (either as a result of delete'ing an object allocated with new, delete[]'ing an array of objects allocated with new[], or because the object was stack-allocated and fell out of scope).

The 'class' keyword in C++ is syntactic sugar; a C++ compiler allows you to add all of these things to 'struct's as well. By typing 'class' instead, you default any inherited bases to inherit privately (you usually want public inheritance, so you have to then specify this), and members to be private (you usually want all or almost all data to be private, and most functions to be public). However, the term also carries semantic baggage: it is idiomatic to use 'struct' for mere collections of data (so typically they only have no member functions except for constructors and a destructor, and don't contain any pointers), and 'class' for types that provide behaviour and thus actually model something.

Inheritance allows for subtyping relationships: you can say that class X IS-A class Y, which is to say, an X object can do anything a Y object can. This is implemented by the compiler by adding all the Y data members to the X "object layout", almost as if you had a data member of the X type - except that you can call X functions on (and access X data members from) the Y directly, rather than having to access the X member. In exchange for this, you have somewhat less flexibility than you get with real "composition" (modelling a HAS-A relationship, by making an actual member of type X). It is quite unusual for it to be a good idea for X to both "be" and "have" a Y; and beware that when you define X, you should NOT redefine members of Y (unless you want *extra* members that happen to have the same name, and even then, things get difficult to manage).

Inheritance also facilitates polymorphism. I could describe this in some detail, but I think the best approach for you would be to read here and here (the latter is a fairly random Google hit that I selected because there's actual code that's fairly illustrative; you might want to just google for 'C "pointer cast polymorphism"' yourself) for a description of how similar functionality gets brutally hacked into C, and then here to see how C++ does the work for you (in a much safer way which is still as efficient as could sanely be expected).

Constructors and destructors are used for setup and cleanup of objects. This facilitates the very powerful C++ idiom of RAII (Resource Acquisition Is Initialization). The idea is that every object is responsible for its own "toys", and puts them away when it's done. The C++ standard library provides several classes that respect these rules. When everyone pitches in like that, it becomes easier for everyone - for example, if you want to make your own class do RAII properly, then it makes good sense to prefer standard library "container" objects over raw arrays or hand-rolled list/graph structures, because the constructors and destructors of the members will be called as well as those for your containing object, greatly reducing your workload. See more here and here.

Actually, hell, just read the whole C++ Faq Lite. It's quite worthwhile.

Share this post


Link to post
Share on other sites
Maybe a code example:

#include "windows.h"
#define WIN32_LEAN_AND_MEAN

class cWindowsGui
{
private:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lCmdLine, int nCmdShow) ;

public:
cWindowsGui();
};

cWindowsGui::cWindowsGui()
{
this.WinMain(HINSTANCE h, HINSTANCE p, LPSTR c, int cs);
}


int WINAPI cWindowsGui::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lCmdLine, int nCmdShow)
{
MessageBox(NULL,"Test Message","Test",MB_OK);
}



When I use this code it tells me that WINAPI, LPSTR, and other Windows.h defined variables are invalid once I initialise them. The problem isn't that I have a book, I guess its that in my 3 C++ books they all have a lame critter example that just doesn't show me what I would call a real world class. I know that Java works differnetly about C++, but this is the only thing I can come up with to write self contained code that follows the OOP paradigm since Java is the only OOP language that I know. I have heard that C++ is not a true OOP from many people and I don't know if this is the cause of the issue, nor the fact I am using MinGW as my compiler, but from what I have seen (and that's not saying much) it should work. As I keep stating, how would I do something like this in the real world to understand C++ classes better?

Share this post


Link to post
Share on other sites
Quote:
Original post by sgalland
Maybe a code example:

#include "windows.h"
#define WIN32_LEAN_AND_MEAN

class cWindowsGui
{
private:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lCmdLine, int nCmdShow) ;

public:
cWindowsGui();
};

cWindowsGui::cWindowsGui()
{
this.WinMain(HINSTANCE h, HINSTANCE p, LPSTR c, int cs);
}


int WINAPI cWindowsGui::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lCmdLine, int nCmdShow)
{
MessageBox(NULL,"Test Message","Test",MB_OK);
}



When I use this code it tells me that WINAPI, LPSTR, and other Windows.h defined variables are invalid once I initialise them. The problem isn't that I have a book, I guess its that in my 3 C++ books they all have a lame critter example that just doesn't show me what I would call a real world class. I know that Java works differnetly about C++, but this is the only thing I can come up with to write self contained code that follows the OOP paradigm since Java is the only OOP language that I know. I have heard that C++ is not a true OOP from many people and I don't know if this is the cause of the issue, nor the fact I am using MinGW as my compiler, but from what I have seen (and that's not saying much) it should work. As I keep stating, how would I do something like this in the real world to understand C++ classes better?


You're missing WinMain, you're using this as a reference, and other things.

Share this post


Link to post
Share on other sites
There is a WinMain defined as its own function, it works if i just drop it into a C++ compiler without using classes. I just can't figure out why it misses the variables defined in windows.h.

Share this post


Link to post
Share on other sites
Here's the obvious one:
What do you benefit from doing C++ wrapper for win32?

Another obvious would be asking that with inverse meaning.

Depending about what you are preferring, you should be able to determine from benefits/defects your strategy for doing the wrapper, and even determine if the benefits overtakes possible drawbacks which you could encounter in doing what you are doing at times.

IMPORTANT: benefits&drawbacks aren't as simple as somebody may think, especially when they include every kind of them, not just material benefits&drawbacks.

Share this post


Link to post
Share on other sites
errs:
1.the (this) key word points to the class it's called in. so it is a pointer , use -> instead of . .
2.define the vars before use and even better initialize them.
3. function winmain should return a value(int).

it works fine now , but you should create an instance of the class for testing ???.


#include "windows.h"
#define WIN32_LEAN_AND_MEAN
class cWindowsGui
{
private:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lCmdLine, int nCmdShow) ;

public:
cWindowsGui();
};

cWindowsGui::cWindowsGui()
{
HINSTANCE h;
HINSTANCE p;
LPSTR c;
int cs;
this->WinMain(h,p,c,cs);
}


int WINAPI cWindowsGui::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lCmdLine, int nCmdShow)
{
MessageBox(NULL,"Test Message","Test",MB_OK);
return 0;
}

Share this post


Link to post
Share on other sites
Well thats a step in the right direction, I read over 3 books on classes and also tutorials and nothing ever said much about putting variables into the constructor or using the pointer operator. I know why my stupid compiler didn't like my initial code, I was linking in the wrong library (I am using codeblocks to compile with... my bad).

How to my main point now I am starting to get somewhere, when you plan to make a class I assume you make all the variables a member or instanced elsewhere in the class rather than only in the function argument list? Just wondering what the thought process is on that. Also any generic tips on planning classes? My guess is this for this type of "wrapper":

Base Namespace would wrap all my classes
Base class will be cWinApp
cWinApp will inherit from a cWinLabel which defines code for a label
cWinApp will inherit from other things such as buttons and crap, etc...

Is this the basic mentality to create this "black box design" that is so fundemental in OOP design? I've been programming for about 3 years in C and feel like a total freaking newb :)

Share this post


Link to post
Share on other sites
No no no no no no no no no.

You can't wrap WinMain into an object. It is the *program entry point*. You couldn't put the program main() in there for a console application either. You might have a function called main() as a member function, but it wouldn't be recognized as the program entry point (and you certainly wouldn't want to try to call the global main() from there).

The compiler gets confused because 'WINAPI' is a *calling convention*, which is incompatible with the calling convention of member functions.

Instead, you want to set up WinMain() so that it instantiates one of your objects and calls some member function on it that performs the game "main loop". Use the constructor to do stuff that happens before the game loop, and destructor to clean up.


#include "windows.h"
#define WIN32_LEAN_AND_MEAN
class Application {
HINSTANCE instance;
HINSTANCE prevInstance;
LPSTR commandLine;
int commandShow;

public:
Application(HINSTANCE instance, HINSTANCE prevInstance,
LPSTR commandLine, int commandShow) :
instance(instance), prevInstance(prevInstance),
commandLine(commandLine), commandShow(commandShow) {
// Do any necessary setup stuff here
}

~Application() {
// Do any necessary cleanup stuff here
}

bool run() {
// Stubs for the real functionality of course :)
update();
render();
pause_until_next_frame();
return !finished();
}
};

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lCmdLine, int nCmdShow) {
Application a(hInstance, hPrevInstance, lCmdLine, nCmdShow);
// setup code is automatically invoked by object creation
while (a.run());
// cleanup code is automatically invoked at end of scope
return 0;
}


You can improve upon this by having the constructor throw an exception (and making sure things done so far are cleaned up) if initialization fails, and catching the exception in the main function. But let's take small steps eh? :)

Share this post


Link to post
Share on other sites
If you want to take a break from coding, I would recommend downloading Microsoft's VC 2005 Express. They released free express versions of their IDEs, but the downside is that you have to download the platform SDK separately. Personally, I'm a lot more productive with visual studio. I hate Borland, and I feel so-so about Code::Blocks and Bloodshed.

I don't know if anybody has mentioned it, but you should read Oluseyi's article on the subject.

Also, you should seriously consider the suggestion of using C#. You don't have to abandon C++ altogether, but learning C++ and OOP at the same time is hard. I've been trying for years, and I don't think I completely get it yet. I don't know if I agree with jpetrie about C# being necessarily better, but most people regard it as a hell of a lot easier to deal with.

Share this post


Link to post
Share on other sites
i totaly blacked out that winmain was the entrypoint , i thought he created a call back function with a close name ;).a neat approach is to place winmain inside your wrapper and create a call-back function e.gWmain , and make winmain
call Wmain (i think that what they did in win32 but with main).

Share this post


Link to post
Share on other sites
Zahlman is 100% correct. You cannot just wrap the winmain function into a class because then the compiler doesnt know where the entry point is.

this is sorta how mine looks like, there are like 100's of ways to do this...

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd)
{
hPrevInst, lpCmdLine, nShowCmd; // makes compiler happy

g_hInst = hInstance;

CWindow window( 640, 480 );

return 0;
}



The only problem with win32 and C++ is the fact u need a relay winproc function


//=========================================================================== Relay Message Handler ====//
LRESULT CALLBACK CWindow::stWinProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
CWindow *pWnd;

if (msg == WM_NCCREATE)
{
// get the pointer to the window from lpCreateParams which was set in CreateWindow
SetWindowLong(hwnd, GWL_USERDATA, (long)((LPCREATESTRUCT(lParam))->lpCreateParams));
}

// get the pointer to the window
pWnd = GetObjectFromWindow(hwnd);

// if we have the pointer, go to the message handler of the window
// else, use DefWindowProc
if (pWnd)
return pWnd->WinProc(hwnd, msg, wParam, lParam);
else
return DefWindowProc(hwnd, msg, wParam, lParam);

}


//=========================================================================== Message Handler ====//
LRESULT CALLBACK CWindow::WinProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY:
{
PostQuitMessage(0);
}break;

default: return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;

}



everything else is basicly straight forward when wrapping win32 in classes

Share this post


Link to post
Share on other sites
I see, so it is not possble to wrap C++ class around the entire Win32 API, thats what I was wondering (meaning the WinMain entry point). And the tutorial link answered another question. Is there any good information out there on how to plan a class? That would be of great assistance. Other than that all my questions have been answered.

Share this post


Link to post
Share on other sites
you can define:
int APIENTRY XMain();
then inside your class.cpp file
int CALLBACK WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow)
{
return XMain();
}

Share this post


Link to post
Share on other sites
Quote:
Original post by sgalland
I see, so it is not possble to wrap C++ class around the entire Win32 API...

You have no idea of the (ever-expanding) scope of the Win32 API.

"Win32" is not a reference to the graphical window object you see and interact with. It is the name of the 32-bit Windows subsystem, and it includes a ton of functionality that has absolutely nothing to do with graphical user interfaces. It is the successor to Win16, and may one day be completely superseded by Win64 (though Microsoft is hoping that WinFX will largely supersede it instead, with Win64 being used only for low-level components).

You have three problems:
  • You don't know Win32
  • You don't know C++
  • You don't know programming

Based on the above, you are the absolute last person who should be writing a Win32 window class wrapper. I wrote one three or four years ago, which is widely referenced, and it's garbage. Fortunately, it was largely for illustrative purposes.

Just use ATL/WTL. You can hold to the notion that using something you don't understand is a bad idea, but that's why there's documentation. Read it. Plus, ATL's CComPtr lets you use DirectX interfaces in RAII, something you'll probably grow into later.

Basically, it comes down to this: do you want to make cool games, or do you want to re-create technology that's been done and represents zero innovation whatsoever?

Share this post


Link to post
Share on other sites
I dont even know why I posted here anymore, I didnt post to get my ass treated like dirt because everyone knows more than me. You are right, I am not a professional programmer, I know enough Windows API code for my purposes, I have only programmed in C, VB, and a little in Java. Hell, I can use most aspects of C++ such as using things like vectors and most other legacy functions. If you just want to be a dick fine, I don't care but I don't need you bashing me in a friggin newbies forum. Who the hell are you?

Share this post


Link to post
Share on other sites
a few things to consider when making a basic win32 wrapper (windows and gdi):
1.) don't wrap anything that doesn't need to be wrapped (Direct3D for example).
2.) don't implement dispatch tables (takes too long) or 1,000 virtual functions (inefficent use of memory, since most derived classes only override 10-20 windows messages) for your windows message routing. just use a single virtual Window/Dialog/SuperClass/SubClass proc. maybe add a virtual WM_COMMAND handler as well.
3.) when wrapping GDI classes, be careful! gdi objects can be selected into multiple contexts, and when you destroy a gdi object that is currently selected into a DC or DCs, what do you do? throw an exception? restore the original object? select a default object? this requires a fair amount of bookeeping (reference counting, a map of objects and dcs they are selected into).
4.) superclass the windows common controls.

other than that, making a basic win32 wrapper isn't too hard and shouldn't take so much time. just don't go all balls out and reinvent MFC.

Share this post


Link to post
Share on other sites
I just wanted to post and state that I am sorry for my anger issues. You are all trying to help me and I get mad when I should realize my iniquities. So I formally ask for your apologies. I intend to let this thread die however, all my questions been answered. I spend my time being nice to everyone since I am in customer support for a major firm who builds servers/does 3rd part Microsoft application support and when it comes to getting any support or attempting to get answers from a community with a wide variety of opinions and idea's I find it frustrating when I work in a highspeed high anxiety enviroment, and I don't need to bring my frustrations on here and dump, its not right. Sorry.

Share this post


Link to post
Share on other sites

This topic is 4205 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this