0

I have just tried to add a second DDX_CBWordIndex to my header file:

#pragma once
#include "stdafx.h"

template<typename E>
void AFXAPI DDX_RadioEnum(CDataExchange* pDX, int nIDC, E& value)
{
    if (pDX == nullptr)
        return;

    // (1) Prepare the control for data exchange
    pDX->PrepareCtrl(nIDC);
    HWND hWndCtrl;
    pDX->m_pDlgWnd->GetDlgItem(nIDC, &hWndCtrl);

    // (2) Make sure this routine is associated with the first
    // radio button in a radio button group
    ASSERT(::GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP);
    // And verify, that it is indeed a radio button
    ASSERT(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON);

    // (3) Iterate over all radio buttons in this group
    using value_t = std::underlying_type_t<E>;
    value_t rdbtn_index{};
    do {
        if (::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON) {
            // (4) Control is a radio button
            if (pDX->m_bSaveAndValidate) {
                // (5) Transfer data from UI to class member
                if (::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0) {
                    value = static_cast<E>(rdbtn_index);
                }
            }
            else {
                // (6) Transfer data from class member to UI
                ::SendMessage(hWndCtrl, BM_SETCHECK,
                    (static_cast<E>(rdbtn_index) == value), 0L);
            }
            ++rdbtn_index;
        }
        else {
            // (7) Not a radio button -> Issue warning
            TRACE(traceAppMsg, 0,
                "Warning: skipping non-radio button in group.\n");
        }
        // (8) Move to next control in tab order
        hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT);

    }
    // (9) Until there are no more, or we moved to the next group
    while (hWndCtrl != nullptr && !(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP));
}

template<typename E>
void AFXAPI DDX_CBIndexEnum(CDataExchange* pDX, int nIDC, E& value)
{
    pDX->PrepareCtrl(nIDC);
    HWND hWndCtrl;
    pDX->m_pDlgWnd->GetDlgItem(nIDC, &hWndCtrl);
    if (pDX->m_bSaveAndValidate)
        value = static_cast<E>(::SendMessage(hWndCtrl, CB_GETCURSEL, 0, 0L));
    else
        ::SendMessage(hWndCtrl, CB_SETCURSEL, static_cast<WPARAM>(value), 0L);
}


void AFXAPI DDX_CBWordIndex(CDataExchange* pDX, int nIDC, WORD& index)
{
    pDX->PrepareCtrl(nIDC);
    HWND hWndCtrl;
    pDX->m_pDlgWnd->GetDlgItem(nIDC, &hWndCtrl);
    if (pDX->m_bSaveAndValidate)
        index = (WORD)::SendMessage(hWndCtrl, CB_GETCURSEL, 0, 0L);
    else

        ::SendMessage(hWndCtrl, CB_SETCURSEL, (WPARAM)index, 0L);
}

I am using #pragma once. But this will not compile:

7>ImportFromCLMExplorerDlg.obj : error LNK2005: "void __cdecl DDX_CBWordIndex(class CDataExchange *,int,unsigned short &)"

(?DDX_CBWordIndex@@YAXPEAVCDataExchange@@HAEAG@Z) already defined in AssignHistoryDlg.obj 7>OtherSettingsAutomaticBackupPage.obj : error LNK2005: "void __cdecl DDX_CBWordIndex(class CDataExchange *,int,unsigned short &)" (?DDX_CBWordIndex@@YAXPEAVCDataExchange@@HAEAG@Z) already defined in AssignHistoryDlg.obj 7>ChristianLifeMinistryPersonalCopiesDlg.obj : error LNK2005: "void __cdecl DDX_CBWordIndex(class CDataExchange *,int,unsigned short &)" (?DDX_CBWordIndex@@YAXPEAVCDataExchange@@HAEAG@Z) already defined in AssignHistoryDlg.obj 7>ChristianLifeMinistryEditorDlg.obj : error LNK2005: "void __cdecl DDX_CBWordIndex(class CDataExchange *,int,unsigned short &)" (?DDX_CBWordIndex@@YAXPEAVCDataExchange@@HAEAG@Z) already defined in AssignHistoryDlg.obj 7>ChristianLifeMinistryStudentMaterialDlg.obj : error LNK2005: "void __cdecl DDX_CBWordIndex(class CDataExchange *,int,unsigned short &)" (?DDX_CBWordIndex@@YAXPEAVCDataExchange@@HAEAG@Z) already defined in AssignHistoryDlg.obj 7>ClearAssignmentsDlg.obj : error LNK2005: "void __cdecl DDX_CBWordIndex(class CDataExchange *,int,unsigned short &)" (?DDX_CBWordIndex@@YAXPEAVCDataExchange@@HAEAG@Z) already defined in AssignHistoryDlg.obj 7>InsertDateDlg.obj : error LNK2005: "void __cdecl DDX_CBWordIndex(class CDataExchange *,int,unsigned short &)" (?DDX_CBWordIndex@@YAXPEAVCDataExchange@@HAEAG@Z) already defined in AssignHistoryDlg.obj 7>OptionsDlg.obj : error LNK2005: "void __cdecl DDX_CBWordIndex(class CDataExchange *,int,unsigned short &)" (?DDX_CBWordIndex@@YAXPEAVCDataExchange@@HAEAG@Z) already defined in AssignHistoryDlg.obj 7>OtherSettingsUpdatePage.obj : error LNK2005: "void __cdecl DDX_CBWordIndex(class CDataExchange *,int,unsigned short &)" (?DDX_CBWordIndex@@YAXPEAVCDataExchange@@HAEAG@Z) already defined in AssignHistoryDlg.obj 7>SpecialEventBethelSpeakerServiceTalkDlg.obj : error LNK2005: "void __cdecl DDX_CBWordIndex(class CDataExchange *,int,unsigned short &)" (?DDX_CBWordIndex@@YAXPEAVCDataExchange@@HAEAG@Z) already defined in AssignHistoryDlg.obj 7>SpecialEventVideoconferenceInfoDlg.obj : error LNK2005: "void __cdecl DDX_CBWordIndex(class CDataExchange *,int,unsigned short &)" (?DDX_CBWordIndex@@YAXPEAVCDataExchange@@HAEAG@Z) already defined in AssignHistoryDlg.obj 7>SMCustomizeDlg.obj : error LNK2005: "void __cdecl DDX_CBWordIndex(class CDataExchange *,int,unsigned short &)" (?DDX_CBWordIndex@@YAXPEAVCDataExchange@@HAEAG@Z) already defined in AssignHistoryDlg.obj 7>SpecialEventDlg.obj : error LNK2005: "void __cdecl DDX_CBWordIndex(class CDataExchange *,int,unsigned short &)" (?DDX_CBWordIndex@@YAXPEAVCDataExchange@@HAEAG@Z) already defined in AssignHistoryDlg.obj 7>SpecialEventManager.obj : error LNK2005: "void __cdecl DDX_CBWordIndex(class CDataExchange *,int,unsigned short &)" (?DDX_CBWordIndex@@YAXPEAVCDataExchange@@HAEAG@Z) already defined in AssignHistoryDlg.obj 7>UpdateCalendarDlg.obj : error LNK2005: "void __cdecl DDX_CBWordIndex(class CDataExchange *,int,unsigned short &)" (?DDX_CBWordIndex@@YAXPEAVCDataExchange@@HAEAG@Z) already defined in AssignHistoryDlg.obj

I don't understand why it complains because the function is only defined once.

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
  • Now I think about it, the `DDX_CBIndexEnum` would cover `WORD` I guess. But i want that just for enums. I would liek this specific `WORD` DDX routine. – Andrew Truckle Feb 10 '22 at 16:09
  • I can simply use `DDX_CBIndexEnum` with my combo index `WORD` variables but the name is misleading for the use case. So how can I add that second scenario? – Andrew Truckle Feb 10 '22 at 16:14
  • 4
    The `#pragma once` only means that the header won't be included multiple times by the ***same*** translation unit. Your definition of `DDX_CBWordIndex` will be made in *every* TU that includes the header you have it in. You can make it `static` and/or `inline` but, better, give the declaration in the header and the definition in a source file. – Adrian Mole Feb 10 '22 at 16:23
  • @AdrianMole But I do not have this issue with the other two DDX routines in this header file. Is my assumption right that the logic of the other one being a templated function means that it already caters for this secondary function I am trying to add to the header? – Andrew Truckle Feb 10 '22 at 16:27
  • The other two are not functions - they are function templates. Functions based on those templates are only instanced when they are used/needed in source code. – Adrian Mole Feb 10 '22 at 16:28
  • @AdrianMole I confirm that prefixing the function declaration with static works. – Andrew Truckle Feb 10 '22 at 16:32
  • @AdrianMole I am not too sure how to go about using a header with source when templated functions are also involved. – Andrew Truckle Feb 10 '22 at 16:33
  • 4
    Keep the function templates in the header, and move the function body of the regular function into its own compilation unit. – IInspectable Feb 10 '22 at 16:41
  • @IInspectable Working! Awesome. – Andrew Truckle Feb 10 '22 at 16:50

0 Answers0