Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I compile a Window API program using cl?

I am trying to compile a simple C Windows API program using the Windows SDK Command Prompt.

Here an excerpt from the program:

#include <Windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{

[...]

    RegisterClass(&wc);
    hwnd = CreateWindow("test", NULL, 0, 0, 0, 0, 0, NULL, NULL, hInstance, NULL);

[...]

When I compile it using

cl test.c

in the Windows SDK Command Promt, it gives me a lot of linker errors like these:

test.obj : error LNK2019: unresolved external symbol __imp_CreateWindowExA referenced in function WinMain
test.obj : error LNK2019: unresolved external symbol __imp_RegisterClassA referenced in function WinMain
like image 228
AndreKR Avatar asked Feb 08 '12 17:02

AndreKR


People also ask

How do you compile with CL?

To compile your program, enter cl hello. c at the developer command prompt. If you get an error such as "'cl' is not recognized as an internal or external command, operable program or batch file," error C1034, or error LNK1104, your developer command prompt is not set up correctly.


2 Answers

There are at least two problems.

  1. The linker is telling you that there is an "unresolved external symbol". That means it can't find a definition for the function(s) that you tried to call. In this case, there are two such undefined functions: CreateWindowExA and RegisterClassA.

    Obviously the definition for those functions is not to be found in your code, but rather in the Windows API libraries, so you'll need to inform the linker of where it can find those definitions.

    The SDK comes with stubs (*.lib) files, which contain information used by the linker so that it can find the proper function definitions in the Windows DLLs at runtime. You need to instruct the linker where it can find those *.lib files.

    There are a couple of different strategies for doing so:

    1. The simple (albeit non-portable) way is to insert a #pragma statement into your source file that instructs the compiler to leave a comment recognized by the linker. For example,

      #pragma comment(lib, "user32")
      

      automatically links to user32.lib, which is the stub file for user32.dll.

    2. Alternatively, you can pass the parameters on the command line to cl.exe. This gets awfully complicated in a hurry, though, if you're not using MSBuild or some kind of make file. In this case, you would need to modify your command line to (at minimum):

      cl test.c user32.lib
      

    Both of these options naturally assumes that your Windows SDK directory was added to the path. I'm pretty sure the installer does that for you automatically, but I'm not positive. If it doesn't, or you've removed these files from your path, you'll need to use fully-qualified paths to the *.lib files on the command line.

    Reading the documentation for the possible compiler options is a good place to start. Or better yet, if you're unfamiliar with Windows programming, using an environment like Visual Studio that puts all of this stuff together for you automatically. Once you understand what's going on, look to see what the command line that Visual Studio runs is, and dissect it bit-by-bit.

  2. Next problem is that you're compiling without Unicode defined, and because ANSI is the default, all of the macros inside the Windows header files are resolving to call the A suffixed versions of all the SDK functions. This is probably not what you want. Windows has been fully Unicode now for over a decade, and all new applications should be built as Unicode. The Unicode versions have a W suffix appended to their name.

    Again, you can instruct the compiler to build with Unicode explicitly by either adding lines to your source file, or adding parameters to your command line.

    In this case, the simplest way is probably just to add

     #define UNICODE
    

    to the top of your source file before #include <windows.h>. Just as we saw above, from the Visual Studio environment, UNICODE is automatically defined for you unless you explicitly change your project settings to target something else.

like image 102
Cody Gray Avatar answered Nov 17 '22 08:11

Cody Gray


Those functions live in user32.lib. You need to supply that to the cl tool.

cl test.c ""C:\Program Files\Microsoft SDKs\Windows\v6.0A\Lib\user32.lib"
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.307
Copyright (C) Microsoft Corporation.  All rights reserved.

test.c
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test.exe
test.obj
"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Lib\user32.lib"
like image 26
fdk1342 Avatar answered Nov 17 '22 09:11

fdk1342