Как настроить системное меню формы Windows? - PullRequest
0 голосов
/ 15 апреля 2019

Я хочу добавить меню «О программе» в контекстное меню строки заголовка в моем приложении.

Я сделал много поисков по интернету и нашел эту замечательную тему Как настроить системное меню формы Windows? , но для Visual C ++ нет решения. Я пытался адаптировать решения из упомянутой темы, но что-то идет не так. Я вижу, что в контекстном меню появляется что-то новое, но нет пункта «О программе».

Вот мой код:

#pragma once
#include <string>

namespace context_menu {

    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;
    using namespace System::Runtime::InteropServices;
    using std::string;

    // P/Invoke constants
    const int WM_SYSCOMMAND = 0x112;
    const int MF_STRING = 0x0;
    const int MF_SEPARATOR = 0x800;

    // P/Invoke declarations
    [DllImport("user32.dll", CharSet = System::Runtime::InteropServices::CharSet::Auto, SetLastError = true)]
    extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

    [DllImport("user32.dll", CharSet = System::Runtime::InteropServices::CharSet::Auto, SetLastError = true)]
    extern bool AppendMenu(IntPtr hMenu, int uFlags, int uIDNewItem, string lpNewItem);

    [DllImport("user32.dll", CharSet = System::Runtime::InteropServices::CharSet::Auto, SetLastError = true)]
    extern bool InsertMenu(IntPtr hMenu, int uPosition, int uFlags, int uIDNewItem, string lpNewItem);


    /// <summary>
    /// Summary for Form1
    ///
    /// WARNING: If you change the name of this class, you will need to change the
    ///          'Resource File Name' property for the managed resource compiler tool
    ///          associated with all .resx files this class depends on.  Otherwise,
    ///          the designers will not be able to interact properly with localized
    ///          resources associated with this form.
    /// </summary>
    public ref class Form1 : public System::Windows::Forms::Form
    {
    // ID for the About item on the system menu
    private: static int SYSMENU_ABOUT_ID = 0x1;
    public:
        Form1(void)
        {
            InitializeComponent();
            //
            //TODO: Add the constructor code here
            //
        }

    protected:
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        ~Form1()
        {
            if (components)
            {
                delete components;
            }
        }

    private:
        /// <summary>
        /// Required designer variable.
        /// </summary>
        System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        void InitializeComponent(void)
        {
            this->SuspendLayout();
            // 
            // Form1
            // 
            this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
            this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
            this->ClientSize = System::Drawing::Size(284, 261);
            this->Name = L"Form1";
            this->Text = L"Form1";
            this->ResumeLayout(false);
        }
#pragma endregion

    protected: virtual System::Void OnHandleCreated( System::EventArgs^ e ) override {
                System::Windows::Forms::Form::OnHandleCreated( e );
                // Get a handle to a copy of this form's system (window) menu
                IntPtr sysMenuHandle = GetSystemMenu( this->Handle, false );
                // Add a separator
                AppendMenu( sysMenuHandle, MF_SEPARATOR, 0, "" );
                // Add the About menu item
                AppendMenu( sysMenuHandle, MF_STRING, SYSMENU_ABOUT_ID, "&About…\n" );
            }

    protected: virtual System::Void WndProc( Message % m ) override {
                System::Windows::Forms::Form::WndProc( m );
                // Show test message
                if( ( m.Msg == WM_SYSCOMMAND ) && ( (int)m.WParam == SYSMENU_ABOUT_ID ) )
                {
                    MessageBox::Show( "Custom About Dialog" );
                }
            }
    };
}

А вот мой результат .

EDIT

Согласно ответу @David Yaw я добавил #include <Windows.h> и удалил весь ненужный код. Мне нужно было решить некоторые мелкие проблемы, и через некоторое время оно скомпилировалось. Но потом появились ошибки компоновщика:

1>context_menu.obj : error LNK2028: unresolved token (0A00001A) "extern "C" int __stdcall AppendMenuW(struct HMENU__ *,unsigned int,unsigned int,wchar_t const *)" (?AppendMenuW@@$$J216YGHPAUHMENU__@@IIPB_W@Z) referenced in function "protected: virtual void __clrcall context_menu::Form1::OnHandleCreated(class System::EventArgs ^)" (?OnHandleCreated@Form1@context_menu@@$$FM$AAMXP$AAVEventArgs@System@@@Z)
1>context_menu.obj : error LNK2028: unresolved token (0A00001B) "extern "C" struct HMENU__ * __stdcall GetSystemMenu(struct HWND__ *,int)" (?GetSystemMenu@@$$J18YGPAUHMENU__@@PAUHWND__@@H@Z) referenced in function "protected: virtual void __clrcall context_menu::Form1::OnHandleCreated(class System::EventArgs ^)" (?OnHandleCreated@Form1@context_menu@@$$FM$AAMXP$AAVEventArgs@System@@@Z)
1>context_menu.obj : error LNK2019: unresolved external symbol "extern "C" int __stdcall AppendMenuW(struct HMENU__ *,unsigned int,unsigned int,wchar_t const *)" (?AppendMenuW@@$$J216YGHPAUHMENU__@@IIPB_W@Z) referenced in function "protected: virtual void __clrcall context_menu::Form1::OnHandleCreated(class System::EventArgs ^)" (?OnHandleCreated@Form1@context_menu@@$$FM$AAMXP$AAVEventArgs@System@@@Z)
1>context_menu.obj : error LNK2019: unresolved external symbol "extern "C" struct HMENU__ * __stdcall GetSystemMenu(struct HWND__ *,int)" (?GetSystemMenu@@$$J18YGPAUHMENU__@@PAUHWND__@@H@Z) referenced in function "protected: virtual void __clrcall context_menu::Form1::OnHandleCreated(class System::EventArgs ^)" (?OnHandleCreated@Form1@context_menu@@$$FM$AAMXP$AAVEventArgs@System@@@Z)

И что теперь?

Код:

#pragma once
#include <Windows.h>
#include <string>

namespace context_menu {

    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;
    using namespace System::Runtime::InteropServices;
    using std::string;

    /// <summary>
    /// Summary for Form1
    ///
    /// WARNING: If you change the name of this class, you will need to change the
    ///          'Resource File Name' property for the managed resource compiler tool
    ///          associated with all .resx files this class depends on.  Otherwise,
    ///          the designers will not be able to interact properly with localized
    ///          resources associated with this form.
    /// </summary>
    public ref class Form1 : public System::Windows::Forms::Form
    {
    // ID for the About item on the system menu
    private: static int SYSMENU_ABOUT_ID = 0x1;


    public:
        Form1(void)
        {
            InitializeComponent();
            //
            //TODO: Add the constructor code here
            //
        }

    protected:
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        ~Form1()
        {
            if (components)
            {
                delete components;
            }
        }

    private:
        /// <summary>
        /// Required designer variable.
        /// </summary>
        System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        void InitializeComponent(void)
        {
            this->SuspendLayout();
            // 
            // Form1
            // 
            this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
            this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
            this->ClientSize = System::Drawing::Size(284, 261);
            this->Name = L"Form1";
            this->Text = L"Form1";
            this->ResumeLayout(false);

        }
#pragma endregion

    protected: virtual System::Void OnHandleCreated( System::EventArgs^ e ) override {
                // Basic function call
                System::Windows::Forms::Form::OnHandleCreated( e );
                // Pointer to this
                HWND hWnd = static_cast<HWND>( this->Handle.ToPointer() );
                // Get a handle to a copy of this form's system (window) menu
                HMENU sysMenuHandle = GetSystemMenu( hWnd, false );
                // Add a separator
                AppendMenu( sysMenuHandle, MF_SEPARATOR, 0, L"" );
                // Add the About menu item
                AppendMenu( sysMenuHandle, MF_STRING, SYSMENU_ABOUT_ID, L"&About…\n" );
            }

    protected: virtual System::Void WndProc( Message % m ) override {
                // Basic function call
                System::Windows::Forms::Form::WndProc( m );
                // komunikat
                if( ( m.Msg == WM_SYSCOMMAND ) && ( (int)m.WParam == SYSMENU_ABOUT_ID ) )
                {
                    MessageBox::Show( "Custom About Dialog" );
                }
            }
    };
}

1 Ответ

0 голосов
/ 15 апреля 2019

Вы уже в C ++, вам не нужно P / Invoke. Просто #include <Windows.h> и вызовите функции напрямую.

[DllImport("user32.dll", CharSet = System::Runtime::InteropServices::CharSet::Auto, SetLastError = true)]
extern bool AppendMenu(IntPtr hMenu, int uFlags, int uIDNewItem, string lpNewItem);
                                                                 ^^^^^^

string - это другой класс в C #, чем в C ++ / CLI. Так как что-то появляется, но это не правильно, я думаю, что весьма вероятно, что строка не передается должным образом.

Если вы переключитесь на прямой вызов функций C, проверка типа для строкового параметра поможет вам правильно передать этот параметр.


Все это говорит о стандартном предупреждении: хотя, безусловно, можно написать основную часть вашего приложения на C ++ / CLI или даже написать GUI на C ++ / CLI с использованием WinForms, это не рекомендуется. C ++ / CLI предназначен для сценариев взаимодействия: когда C # или другой код .Net должен взаимодействовать с неуправляемым C ++, C ++ / CLI может обеспечить перевод между ними. Из-за этого C ++ / CLI обладает всеми сложностями C ++, всеми сложностями C # и некоторыми собственными сложностями. Для первичной разработки рекомендуется использовать C # с WinForms или WPF, если вам нужен управляемый код, или C ++ с MFC, если вы хотите неуправляемого.

...