Jason Mills
Jason Mills

Reputation: 615

Mysterious multiple declarations

I have a file called "controls.h" that declares the handles for buttons that will be used in a Win32 app.

#ifndef  CONTROLS_H
#define CONTROLS_H
#include "Window.h"

HWND hwnd_Font_btn;
HWND hwnd_Color_btn;

#pragma region UI_FUNCTION_DEC
bool DrawUI(HWND parenthwnd);
#pragma endregion
#endif

These handles and the function declaration is used in a file called "controls.cpp"

#include "controls.h"

bool DrawUI(HWND parenthwnd)
{
    hwnd_Font_btn = CreateWindowEx(NULL, L"BUTTON", L"Select Font", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 
        10, 10, 100, 25, parenthwnd, NULL, (HINSTANCE)GetWindowLong(parenthwnd, GWL_HINSTANCE), NULL);
    hwnd_Color_btn = CreateWindowEx(NULL, L"BUTTON", L"Select Color", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
        10, 45, 100, 25, parenthwnd, NULL, (HINSTANCE)GetWindowLong(parenthwnd, GWL_HINSTANCE), NULL);
    return true;
}

"Controls.h" is then included in "main.cpp" and then DrawUI is called. However, I can't compile the code because Visual Studio says that the handles are declared in multiple locations.

Error   1   error LNK2005: "struct HWND__ * hwnd_Font_btn" (?hwnd_Font_btn@@3PAUHWND__@@A) already defined in controls.obj  D:\Query\Query\main.obj Query
Error   2   error LNK2005: "struct HWND__ * hwnd_Color_btn" (?hwnd_Color_btn@@3PAUHWND__@@A) already defined in controls.obj    D:\Query\Query\main.obj Query

I simply don't see the problem. I admit, I am inexperienced at programming, but Visual Studio's search function shows that these are only used in the header and controls.cpp file.

Can you help me track down the problem?

Upvotes: 0

Views: 110

Answers (2)

Martin Liversage
Martin Liversage

Reputation: 106856

To declare a global variable in a header file you need to prefix it with extern. You then need to define the value of the variable in a single source file (not header file).

In controls.h:

extern HWND hwnd_Font_btn;

In controls.cpp:

HWND hwnd_Font_btn;

When you omit the extern in the header file you define the variable in each source file that includes the header file and you are not allowed to define multiple variables with the same name.

You can also think of it like this:

Declaring the variable using extern tells the linker that somewhere else in the object files there will be a variable having the declared type and name.

Not using extern actually defines the variable including an initial value allowing the linker to reference the memory location associated with the variable.

Upvotes: 2

Drew Dormann
Drew Dormann

Reputation: 63830

Every instance of the line:

#include "controls.h"

"Pastes" the entirety of "controls.h" at that location in your code.

That makes these lines in that header...

HWND hwnd_Font_btn;
HWND hwnd_Color_btn;

... violate the One Definition Rule.

Change them to:

extern HWND hwnd_Font_btn;
extern HWND hwnd_Color_btn;

And then define them once in one cpp file.

Upvotes: 0

Related Questions