Handmade Hero » Forums » Code » Compiling with Windows.h
Randy Gaul
25 posts
#7104 Compiling without Windows.h
1 year, 3 months ago Edited by Randy Gaul on June 1, 2016, 4:56 a.m.

I'm trying to compile without including Windows.h from this idea by mmozieko. Making miniwin.h went quite smoothly (but took forever). Once I hit compile I get linker errors for every single function I used to use, specifically functions in gdi32.lib, user32.lib and kernel32.lib.

I thought the job of an important library was to cover the hassle of manually loading function pointers via GetProcAddress. In my command line I am specifying:

1
cl ... /link user32.lib kernel32.lib opengl32.lib gdi32.lib

Does anyone know why including Windows.h affects the import libs success? Is there any way to mimic this inside of one's own custom miniwin.h header? If not, is the only solution to manually load all functions through GetProcAddress, and if so is there a way to avoid this sort of nastiness?
ratchetfreak
298 posts
#7106 Compiling with Windows.h
1 year, 3 months ago

There are most likely lib statements that signal to the linker that a certain lib is needed.
mmozeiko
Mārtiņš Možeiko
1476 posts
1 project
#7108 Compiling with Windows.h
1 year, 3 months ago Edited by Mārtiņš Možeiko on June 1, 2016, 1:04 p.m.

Including windows.h is only for compiler. When compiler compiles code that calls functions (yours or Windows API ones, doesn't matter), then it simply puts function name in object file. Basically "this code calls function named X".

When linker creates executable (or dll) from object files, then it needs to know where are all the functions. If function X is in other object file, then linker puts call to its address. But when linker doesn't know where is X (like VirtualAlloc in kernel32.dll) then you need to specify import library. Those *.lib files are for linker to know which functions are in which dll files. Because it needs to generate code that inform OS than your exe/dll file will need function X in Y.dll file.

Using import libraries is perfectly fine and there really is no good reason to not to use them.
Randy Gaul
25 posts
#7109 Compiling with Windows.h
1 year, 3 months ago Edited by Randy Gaul on June 1, 2016, 2:32 p.m.

mmozeiko
Including windows.h is only for compiler. When compiler compiles code that calls functions (yours or Windows API ones, doesn't matter), then it simply puts function name in object file. Basically "this code calls function named X".

When linker creates executable (or dll) from object files, then it needs to know where are all the functions. If function X is in other object file, then linker puts call to its address. But when linker doesn't know where is X (like VirtualAlloc in kernel32.dll) then you need to specify import library. Those *.lib files are for linker to know which functions are in which dll files. Because it needs to generate code that inform OS than your exe/dll file will need function X in Y.dll file.

Using import libraries is perfectly fine and there really is no good reason to not to use them.


Thanks for the reply. I'm trying to explain that I want to use the import libs, however only specifying them on the command line like I've shown is not enough. I have copy + pasted out every symbol from Windows.h into a custom header, and have specified all required import libs on the command line (shown in original post), and still cannot properly link. Including Windows.h seems to signal to the linker some information somehow:

ratchetfreak
There are most likely lib statements that signal to the linker that a certain lib is needed.


So I'm asking, what do I need to do in order to compile + link without including Windows.h? I've searched inside of various Windows headers for "pragma comment", but cannot seem to find anything special. Perhaps MSVC is doing some special-case magic when compiling Windows.h. So, what additional steps should I be taking to properly use import libs for libraries like opengl32.lib, user32.lib, gdi32.lib, and kernel32.lib?
Randy Gaul
25 posts
#7112 Compiling with Windows.h
1 year, 3 months ago Edited by Randy Gaul on June 1, 2016, 4:59 p.m.

Figured it out! I had just forgot to wrap the entire file in an
1
extern "C"
declaration. Thank you for reading the thread, both of you :)
mmozeiko
Mārtiņš Možeiko
1476 posts
1 project
#7115 Compiling with Windows.h
1 year, 3 months ago Edited by Mārtiņš Možeiko on June 1, 2016, 10:28 p.m.

Next time show exact error message from linker ("error LNK2019: unresolved external symbol: _blahblah"). Then we would instantly know what is the exact problem :)
PassiveCoder
9 posts

Friendly old programmer from the days of the BBC and Amiga

#7178 Compiling with Windows.h
1 year, 3 months ago

I rather like this idea, the last time I checked the pre-processor output the windows guff made me feel a little ill.

I'd like to do this and removing the C runtime, I just had a quick bash at it but tripped up fairly quickly.

Here's my MiniWin.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Bloatless version of windows.h, just including the things from windows.h that I need

extern "C"

struct HINSTANCE__
{
   int unused;
};
typedef struct HINSTANCE__* HINSTANCE;

typedef char* LPSTR;

#define WINAPI  __stdcall

int WINAPI
WinMain (
         HINSTANCE hInstance,
         HINSTANCE hPrevInstance,
         LPSTR     lpCmdLine,
         int       nShowCmd
        );


typedef const wchar_t* LPCWSTR;

typedef HINSTANCE HMODULE;

HMODULE WINAPI GetModuleHandle(LPCWSTR lpModuleName);

void __stdcall ExitProcess(unsigned int uExitCode);


Then when I try and build a simple (do nothing) program I get the following build errors:

1
2
Main_win32.obj : error LNK2019: unresolved external symbol "struct HINSTANCE__ * __cdecl GetModuleHandle(wchar_t const *)" ([email protected]@[email protected]@[email protected]) referenced in function "void __cdecl WinMainCRTStartup(void)" ([email protected]@YAXXZ)
Main_win32.obj : error LNK2019: unresolved external symbol "void __cdecl ExitProcess(unsigned int)" ([email protected]@[email protected]) referenced in function "void __cdecl WinMainCRTStartup(void)" ([email protected]@YAXXZ)


I'm guessing this is because the code signatures of the functions in my header don't match those in kernel32.lib
I suspect the problem is that I cut some corners grabbing code from windows.h as going into that is like going down the rabbit hole!

Any ideas? (is there a way of checking what the code signatures are in the lib?)
ta,
Passive

Lets make CPU orientated programming a thing :)
ZaKlaus
Dominik Madarász
10 posts
1 project
I'm Dominik, a developer always loving to explore new ways of programming. ...
#7179 Compiling with Windows.h
1 year, 3 months ago Edited by Dominik Madarász on June 8, 2016, 2:17 p.m. Reason: typo

You need to wrap the code inside of extern "C" scope:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
extern "C"
{
	struct HINSTANCE__
	{
		int unused;
	};
	typedef struct HINSTANCE__* HINSTANCE;

	typedef char* LPSTR;

#define WINAPI  __stdcall

	int WINAPI
		WinMain(
			HINSTANCE hInstance,
			HINSTANCE hPrevInstance,
			LPSTR     lpCmdLine,
			int       nShowCmd
		);


	typedef const wchar_t* LPCWSTR;

	typedef HINSTANCE HMODULE;

	HMODULE WINAPI GetModuleHandle(LPCWSTR lpModuleName);

	void __stdcall ExitProcess(unsigned int uExitCode);
}


Or you could just write extern "C" inline way:

1
2
extern "C" HMODULE WINAPI GetModuleHandle(LPCWSTR lpModuleName);
extern "C" void __stdcall ExitProcess(unsigned int uExitCode);


Your extern "C" written in code would apply only to your HINSTANCE__ struct.
PassiveCoder
9 posts

Friendly old programmer from the days of the BBC and Amiga

#7180 Compiling with Windows.h
1 year, 3 months ago

Oh my goodness, how embarrassing!
That was it, also I had to define GetModuleHandle as GetModuleHandleA

1
2
  HMODULE WINAPI GetModuleHandleA(LPCWSTR lpModuleName);
  #define GetModuleHandle GetModuleHandleA


Then its built! Resulting in a 2k exe with a preprocessor output clear of windows guff, yay :)
(It also compiles in 1 second rather than 3 now, joy).

Thanks.

Lets make CPU orientated programming a thing :)
mmozeiko
Mārtiņš Možeiko
1476 posts
1 project
#7184 Compiling with Windows.h
1 year, 3 months ago Edited by Mārtiņš Možeiko on June 8, 2016, 8:07 p.m.

That's wrong. It should be GetModuleHandleW, because you are using LPCWSTR argument. That is wide string, so you need to use W suffix. Otherwise you'll get an crash or wrong result if you'll pass non-NULL string.
PassiveCoder
9 posts

Friendly old programmer from the days of the BBC and Amiga

#7187 Compiling with Windows.h
1 year, 3 months ago

oh nice catch, thanks mmozeiko

Lets make CPU orientated programming a thing :)
Randy Gaul
25 posts
#7190 Compiling with Windows.h
1 year, 3 months ago Edited by Randy Gaul on June 9, 2016, 2:03 a.m.

When I did this I didn't bother replicating the macros, and instead hard-coded with A suffixes. So I used GetModuleHandleA directly. You can see Casey do this in his videos. I believe it's a nice idea when you start writing your own miniwin.h header, since getting rid of the macro makes it very hard to make mistakes (which can otherwise result in very difficult to track crashes).

Example:

1
2
3
WINUSERAPI BOOL WINAPI PeekMessageA(LPMSG lpMsg, HWND hWnd, INT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg);
WINUSERAPI BOOL WINAPI TranslateMessage(CONST MSG *lpMsg);
WINUSERAPI LRESULT WINAPI DispatchMessageA(CONST MSG *lpMsg);
PassiveCoder
9 posts

Friendly old programmer from the days of the BBC and Amiga

#7197 Compiling with Windows.h
1 year, 3 months ago

I like that even more, good thinking.

Lets make CPU orientated programming a thing :)
mmozeiko
Mārtiņš Možeiko
1476 posts
1 project
#7201 Compiling with Windows.h
1 year, 3 months ago

That's how Casey is using real windows.h - he directly calls W or A functions. No need for macros.