Getting screen resolution in C, w/o "windows.h" - c

Just working on a small project using SDL2...
System info: Windows
App info: using C (pure C, no c++), mingw-x64 & SDL2.
Now;
Firstly, SDL.h requires the main function to be renamed as WinMain.
On the other hand, when getting the screen resolution, I tended to use the GetSystemMetrics function, which requires windows.h to be included in the pre-processor section and at this point, WinMain in my code conflicts with WinMain declared previously in winbase.h. When I'm using both (SDL.h and windows.h), compiler responds:
previous declaration of 'WinMain' was here: int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd);
That's because, WinMain is declared somewhere in the winbase.h, which is auto-included via windows.h.
Is there a way to get the screen resolution w/o using GetSystemMetrics / windows.h? Any other ideas?

Ok! I've realized what I was doing wrong...
For the linking phase, I was using the following libraries and the linker was complaining about the WinMain function not to be found.
-lSDL2main
-lSDL2
Then I added the mingw32 library as shown below and the problem got solved (the order of the libraries does matter I think).
-lmingw32
-lSDL2main
-lSDL2

Related

Entry point in Visual C++ 6.0

I am working on a legacy program, the executable is coded in C using just the Windows API, with Visual C++ 6.0.
Since all default libraries are removed, I cannot use WinMain() as normal. How can I specify a new entry point, I cannot find the option anywhere. I know this is possible as I have done it on Visual Studio C++ 2010.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MessageBoxA(NULL,"Hello World!","info",0);
return 0;
}
Error.
LINK : error LNK2001: unresolved external symbol _WinMainCRTStartup
Release/calcy.exe : fatal error LNK1120: 1 unresolved externals
I found it just after posting the question. Add this below header files.
#pragma comment(linker, "/ENTRY:main")

Issues running WinMain in C

Currently I'm having issues with WinMain in C (specifically in Visual Studio).
For instance...
#include <stdio.h>
#include <Windows.h>
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR lpCmdLine, INT nCmdShow)
{
return(0);
}
1>------ Build started: Project: GameB, Configuration: Debug x64 ------
1>LIBCMTD.lib(exe_main.obj) : error LNK2019: unresolved external symbol main referenced in function "int __cdecl invoke_main(void)" (?invoke_main##YAHXZ)
1>E:\James\VisualStudio\CProjects\GameB\x64\Debug\GameB.exe : fatal error LNK1120: 1 unresolved externals
1>Done building project "GameB.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Just this basic set-up gives me an "inconsistent annotation for WinMain" warning. I have been searching for any help for 2 days and the the closest I come to an answer is people talking about WinMain in the context of C++. I have a feeling this is a problem with Visual Studio as I was originally just using VS Code and managed to get an app (one that generated a pop-up window) to compile and run.
You just set up your winmain wrong. This should work:
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow);
or
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR lpCmdLine, INT nCmdShow)
{
return 0;
}
Don't forget to #include <Windows.h> and change subsystem to windows.
To use the WinMain program entry point, you need to tell the linker to target the "Windows" subsystem, rather than building a console application. Otherwise, the linker will look for (and fail to find) the standard main entry point for C programs.
In the Solution Explorer, right-click on your project and select "Properties". Then navigate to the "Linker -> System" page and select "Windows (/SUBSYSTEM:WINDOWS)" as the target:
On your "inconsistent annotation" warning, see this Q/A: Inconsistent annotation for 'WinMain'
Also, as noted in the answer by SNO, you should add the WINAPI attribute to your WinMain function.
You need to set subsystem from Console to Windows in settings, by right clicking your project in the solution explorer, selecting properties, and going to Linker->System and setting SubSystem to Windows(/SUBSYSTEM:WINDOWS).

INITCOMMONCONTROLSEX was not declared in this scope

When I compile
#include<windows.h>
#include <commctrl.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
INITCOMMONCONTROLSEX ex;
return 0;
}
with
g++ 1.cpp -w -g -lgdi32 -lcomctl32 -o 1.exe
I get the error
1.cpp: In function 'int WinMain(HINSTANCE, HINSTANCE, LPSTR, int)':
1.cpp:8:2: error: 'INITCOMMONCONTROLSEX' was not declared in this scope
INITCOMMONCONTROLSEX ex;
^.
I suspect I am getting this error because in commctrl.h, following #if condition is not true.
#if (_WIN32_IE >= 0x0300)
typedef struct tagINITCOMMONCONTROLSEX {
DWORD dwSize;
DWORD dwICC;
} INITCOMMONCONTROLSEX,*LPINITCOMMONCONTROLSEX;
#endif
I tried compiling
#define _WIN32_IE 0x0300
#include<windows.h>
#include <commctrl.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
INITCOMMONCONTROLSEX ex;
return 0;
}
and this works fine, I don't get any errors. I looked up MSDN but there's nothing written about adding #define _WIN32_IE 0x0300 there.
Questions :
What is the purpose of _WIN32_IE ?
Do I really need to hardcode its value when MSDN writes nothing about doing so ?
The initial version of comctl32 shipped with Windows 95/Windows NT. From then on each release up to Windows 7 got a new updated version but these new versions first shipped as part of Internet Explorer. Internet Explorer 3, 4, 5, 6 and 7 usually included new versions of comctl32, shlwapi and shell32.
This is mostly ancient history these days but you still need to declare which version of Windows and IE you are targeting to unlock certain features.
Adding #define _WIN32_IE 0x0300 to your code unlocks the features introduced in IE 3.0 and your program will only run on Windows 95 ORS 2 or later, Windows 95 RTM will need IE3 or 4 to be installed.
You don't care about Windows 95 (hopefully) but the same type of #if check applies to many other newer features as well and not all of them are correctly documented on MSDN because they probably assume that you are using a Visual Studio project that is less than 20 years old.
Unfortunately the minimum OS version listed on MSDN is wrong and cannot be trusted. Microsoft has removed 99% of the information about versions before 2000 and they seem to ignore anything before 2003/Vista these days.
What is the purpose of _WIN32_IE?
The extended common controls library shipped with Internet Explorer before it became a standard part of Windows. If you set the macros to tell the SDK which version of Windows you're targeting, then the SDK will probably set the IE version for you.
The fact that you had to do this for functionality this old suggests that you're using an old version of Visual Studio and/or the SDK. You might want to consider updating.
Note that, for these common controls, you probably also want to make sure you enable Windows Visual Styles.
Do I really need to hardcode its value when MSDN writes nothing about doing so?
You should set WINVER and _WIN32_WINNT per the MSDN guidelines. Depending on the version of Visual Studio you have, you might be able to set it with a project property. You can also do it with the /D option on the compiler command line, or in a header file that's included before any Windows headers. If you use a pre-compiled header, you could do it at the top of that file.

What's the equivalent of gcc's -mwindows option in cmake?

I'm following the tuto:
http://zetcode.com/tutorials/gtktutorial/firstprograms/
It works but each time I double click on the executable,there is a console which I don't want it there.
How do I get rid of that console?
I tried this:
add_executable(Cmd WIN32 cmd.c)
But got this fatal error:
MSVCRTD.lib(crtexew.obj) : error LNK2019: unresolved external symbol _WinMain#16 referenced in function ___tmainCRTStartup
Cmd.exe : fatal error LNK1120: 1 unresolved externals
While using gcc directly works:
gcc -o Cmd cmd.c -mwindows ..
I'm guessing it has something to do with the entry function: int main( int argc, char *argv[]),but why gcc works?
How can I make it work with cmake?
UPDATE
Let me paste the source code here for convenience:
#include <gtk/gtk.h>
int main( int argc, char *argv[])
{
GtkWidget *window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_show(window);
gtk_main();
return 0;
}
UPDATE2
Why gcc -mwindows works but add_executable(Cmd WIN32 cmd.c) not?
Maybe that's not the equivalent for -mwindows in cmake?
add_executable(Cmd WIN32 cmd.c)
Tells CMake this is a Windows program, and it looks for WinMain instead of main. If you want to see the flags being used you can run make VERBOSE=1. The question might be how do you define WinMain for gtk apps? I know with Qt, you link in a library that defines it for you.
You can set these linker flags to have a main() entry point and no console:
SET(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} /subsystem:windows /ENTRY:mainCRTStartup")
For more info, see this answer for the linker flags, and this answer for how to set flags in cmake.
For CMake 3.13 and newer you can use
target_link_options(target PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup")
If you want your program to run in console mode (ie a main function), you have to specify it in your project's properties in MSVC. What you're using right now is a project in windowed mode (ie a WinMain function, which you don't have, hence the error).
But if you don't want to get the ugly console window, you want to use the windowed mode (ie transform your main function into a propper WinMain function). This way your normal window is all that will show.
edit: As an aside, you really shouldn't name your program "cmd", that's the name of Windows' command interpreter.
According to the CMake documentation for using the WIN32 flag with ADD_EXECUTABLE:
When this property is set to true the executable when linked on Windows will be created with a WinMain() entry point instead of of just main().This makes it a GUI executable instead of a console application. See the CMAKE_MFC_FLAG variable documentation to configure use of MFC for WinMain executables.
However, your program's entry point is main() and not WinMain(). What you should do, instead, is omit the WIN32 flag, but you need to link against libgtk. So, you would use TARGET_LINK_LIBRARIES:
FIND_PACKAGE(GTK2 2.6 REQUIRED gtk)
INCLUDE_DIRECTORIES(${GTK2_INCLUDE_DIRS})
LINK_DIRECTORIES(${GTK2_LIBRARIES})
ADD_EXECUTABLE(myprogramname source1 source2 ... sourceN)
TARGET_LINK_LIBRARIES(myprogramname ${GTK2_LIBRARIES})
While the accepted answer works for MinGW, it won't work for MSVC when you don't define a WinMain. No answer is cross-toolchain compatible IMHO.
Fix Subsystem
add_executable(my_exe WIN32 main.c)
basically passes -mwindows if MinGW compiler is used or /SUBSYSTEM:WINDOWS if MSVC. This sets the subsystem field in PE header of the generated executable to 2 i.e. IMAGE_SUBSYSTEM_WINDOWS_GUI. This instructs Windows to not provide a separate console window for this executable.
Fix Entry Point on MSVC
When MSVC receives /SUBSYSTEM:WINDOWS, its runtime expects1 a WinMain, not main, to be defined unlike MinGW's (which works with any one defined). If you want to continue to use main, fix the entry point:
target_link_options(my_exe PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/ENTRY:mainCRTStartup>
)
1: Yes, OS first calls C runtime and it's the C runtime which calls your executable's entry point
Fix Subsystem Per-config
add_executable(my_exe WIN32 ... internally sets the executable's WIN32_EXECUTABLE property. This gives another, more useful way to do it:
add_executable(my_exe main.c) # look ma, no WIN32!
set_target_properties(my_exe PROPERTIES WIN32_EXECUTABLE 1)
This is useful when you want to do it only for some configurations. I personally enable this only on Release builds, while having a console window on Debug builds is useful.
# No console window for non-debug builds
set_target_properties(my_exe PROPERTIES WIN32_EXECUTABLE
$<AND:$<PLATFORM_ID:Windows>,$<NOT:$<CONFIG:Debug,RelWithDebInfo>>>
)
Verify
# Generate Ninja files for GCC
cmake -B build_g -G "Ninja Multi-Config"
# Generate Visual Studio project and solution for MSVC
cmake -B build_v -G "Visual Studio 17 2022"
# Build with verbosity
cmake --build build_g --config Release -v
This should show the actual build commands with parameters in full verbosity. Useful to verify if -mwindows or /SUBSYSTEM:WINDOWS is passed for the right build configurations.

Link error for Windows functions

I'm trying to test if standard library (kernel32.dll) have one of the function.
Code snippet for test:
extern void CreateProcessA (void);
int
main (void)
{
CreateProcessA ();
return 0;
}
The code compiles and links as follow:
cl /c test.c
link test.obj kernel32.lib
This code can be compiled well with Visual C++, but cannot link:
test.obj : error LNK2019: unresolved external symbol _CreateProcessA referenced in function _main
But function CreateProcessA does exists in kernel32.dll, you no?
How to link it properly?
P.S. I don't want to run this code, just check that function exists (if code compiles and links - function exists).
To see if the function exists, you use
dumpbin /exports kernel32.dll | findstr CreateProcess
You didn't even use the right prototype, so of course the linker can't find the correct function. The naming convention is completely off, and CreateProcess is really a macro (that expands to either CreateProcessA or W depending on UNICODE).
(You don't need to link against kernel32.lib explicitly as that's already done by default by cl.exe)
Instead of declaring the prototype yourself, #include <windows.h>.
Kernel32.dll exports the function as "CreateProcessA", note the missing leading underscore. The only way to convince the linker to use that export is by linking kernel32.lib, an import library supplied by the Windows SDK.
You'll then run into the next problem, the import library declares the export as _CreateProcess#40. This is a name decoration applied by the __stdcall calling convention. That calling convention was explicitly designed to catch your mistake, you didn't declare the function properly. The #40 part of the name indicates the number of bytes needed in the stack frame to pass the arguments.
So, to make it work you should #include <windows.h> to get the proper function declaration and link kernel32.lib to get the proper export name.
Right now you are declaring your own version of CreateProcess(). Since you did not provide the body (code), the linker doesnt know where to check to find the function to execute.
In order to call CreateProcess from kernel32.lib, you need to include the proper headers
#include <windows.h>
If the compiler doesnt know windows.h then probably Platform SDK for windows isnt installed correctly.
you will also need to link with the proper lib
#pragma comment(lib, "kernel32.lib")
You should also read the documentation about createprocess since it takes a gazillion of parametetrs
BOOL WINAPI CreateProcess(
__in_opt LPCTSTR lpApplicationName,
__inout_opt LPTSTR lpCommandLine,
__in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in BOOL bInheritHandles,
__in DWORD dwCreationFlags,
__in_opt LPVOID lpEnvironment,
__in_opt LPCTSTR lpCurrentDirectory,
__in LPSTARTUPINFO lpStartupInfo,
__out LPPROCESS_INFORMATION lpProcessInformation
);
You should search for CreateProcess examples across the interwebs and maybe consider switching to c++ since you're on windows
For starters, put in a proper header file for the prototypes, <windows.h>, as this is a Windows source, add the kernel32.lib for your linker, remove that prototype as it is incorrect. Your main function is debatable as to whether you are creating a command line program or a windows program - if it is the latter, that should read 'WinMain'.
If you look in the MSDN for the function 'CreateProcess', scroll down and you will see the 'Library', that is the hint to tell you which library you need to link for it to work properly.
Hope this helps,
Best regards,
Tom.
I think this is a bad idea, but if you want to do it, you need to link with the kernel32.lib export library.
You must include windows.h in order to get the correct prototype:
#include <windows.h>
int
main (void)
{
CreateProcess(); // will cause warning due to incorrect parameter list
return 0;
}
Is there a particular reason you don't want to include windows.h?
Using MinGW one can use the "-mwindows" flag. Example:
gcc.exe -c -g -MMD -MP -MF build/Debug/MinGW-Windows/newmain.o.d -o build/Debug/MinGW-Windows/newmain.o newmain.c
gcc.exe -o dist/Debug/MinGW-Windows/hwprint_dll build/Debug/MinGW-Windows/newmain.o -mwindows
This will include stuff like gdi32.a, kernel32.a, user32.a and ws2_32.a.

Resources