0
votes

I added an item to a system menu in a dialg based app, item is shown in a menu, but when I click it, nothing happend. Here's the code:

#define IDM_CLIP    17

BOOL CCalculatorControlDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    CMenu* pSysMenu = GetSystemMenu(FALSE); 
    if (pSysMenu != NULL)
    {
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        CString strClip;
        strClip.LoadString(IDS_CLIPBOX);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
            pSysMenu->AppendMenu(MF_STRING, IDM_CLIP, strClip);
        }       
    }

    SetIcon(m_hIcon, TRUE);         
    SetIcon(m_hIcon, FALSE);        

    m_Calculator1.SetNumFormat("%0.2f");        

    LOGFONT lf;
    m_Calculator1.GetResultWndFont(&lf);
    strcpy(lf.lfFaceName, "Brittanic Bold");
    m_Calculator1.SetResultsWndFont(&lf);

    m_Calculator1.GetButtonFont(&lf);
    strcpy(lf.lfFaceName, "Tahoma");
    m_Calculator1.SetButtonFont(&lf);

    m_Calculator1.SetResultsWndBkClr(RGB(128,128,128));

    m_Calculator1.SetResultsWndTxtClr(RGB(255,255,255));

    return FALSE;  
}

void CCalculatorControlDlg::OnSysCommand(UINT nID, LPARAM lParam)
{   
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }   
    else if((nID & 0xFFF0) == IDM_CLIP)
    {
        m_Calculator1.OnEditCopy();
    }
    else
    {
        CDialog::OnSysCommand(nID, lParam);
    }
}

About dialog is added autommatically by the framework and I added IDM_CLIP. m_Calculator1.OnEditCopy() is function from my CCalculatorCtrl class which is coping text to clipboard. I also included CCalculatorCtrl.h file in my CalculatorControlDlg.cpp file, where I'm editing system menu. Here is OnEditCopy method, which btw works with button control...

This is the method I'm calling in CCalculatorControlDlg class.

void CCalculatorCtrl::OnEditCopy()
{
    if ( !OpenClipboard() )
    {
        AfxMessageBox( _T("Cannot open the Clipboard") );
        return;
    }
    // Remove the current Clipboard contents 
    if( !EmptyClipboard() )
    {
        AfxMessageBox( _T("Cannot empty the Clipboard") );
        return;
    }
    // Get the currently selected data
    HGLOBAL hGlob = GlobalAlloc(GMEM_FIXED, 64);
    strcpy_s((char*)hGlob, 64, m_strCurrentEntry);
    // For the appropriate data formats... 
    if ( ::SetClipboardData( CF_TEXT, hGlob ) == NULL )
    {
        CString msg;
        msg.Format(_T("Unable to set Clipboard data, error: %d"), GetLastError());
        AfxMessageBox( msg );
        CloseClipboard();
        GlobalFree(hGlob);
        return;
    }
    AfxMessageBox( _T("Copy to clipboard successful!"));
    CloseClipboard();
}

I hope I'm understandable... Thanks in advance.

2

2 Answers

3
votes

In method

void CCalculatorControlDlg::OnSysCommand(UINT nID, LPARAM lParam)

The line

else if((nID & 0xFFF0) == IDM_CLIP)

cannot be right, you are masking 0x11 (hex for 17) against 0xfff0. The result is 16.

(nID & 0xFFF0) is never the value 17 which is IDM_CLIP.

Use another id for IDM_CLIP.

2
votes

It should be fairly obvious based on the code what is happening; remember that 17 is 0x11

The problem is that when you do (nID & 0xFFF0) the result is 0x0011 & 0xFFF0 which yields: 0x0010.

So the solution is to fix IDM_CLIP to have the appropriate value. As you've seen, it can't be just anything. From the MSDN page on CWnd::OnSysCommand says: “In WM_SYSCOMMAND messages, the four low-order bits of the nID parameter are used internally by Windows. When an application tests the value of nID, it must combine the value 0xFFF0 with the nID value by using the bitwise-AND operator to obtain the correct result.”

It should be obvious based on the that the value you choose should not have any of the low 4 bits set.