我自己的个人 MFC

Posted

技术标签:

【中文标题】我自己的个人 MFC【英文标题】:My Own Personal MFC 【发布时间】:2011-08-18 09:47:00 【问题描述】:

我似乎在 msdn 上找不到这个,一直在搜索(如下所述)。

请原谅贴的代码量,我会按顺序粘贴。你真的可以跳过大部分。但我只是想把它全部放在那里,这样我的要求就很清楚了。

假设我想做一个非常简单的 MFC。所以我有以下抽象和具体的类(粘贴在下面),我想要在我非常糟糕的框架中。

我还假设(尽管尚未实现)WinMain 将调用用户定义的主函数(如 Qt)。我需要做什么才能在我尝试编写的所有其他小的蹩脚 Win32 程序中重用我的代码。更清楚地说,我想知道是否将其编译为 DLL 或库。如果是这样,我该怎么做?如何在 DLL 中包含 WinMain 函数?

    #ifndef IAPPLICATION_H_
    #define IAPPLICATION_H_

    #include <Windows.h>

    namespace nApplication
    
        class IController;
        class IWindow;

        class IApplication
        
        public:
            virtual int Run( ) = 0;
            virtual HINSTANCE gethInstance( ) = 0;
            virtual int getnCmdShow( ) = 0;
            virtual IController* getMainControl( ) = 0;
        protected:
            IWindow *main_window;
            IController *main_control;
        private:
            virtual int MessageLoop() = 0;
        ;
    

    #endif /* IAPPLICATION */

-

    #ifndef APPLICATION_H_
    #define APPLICATION_H_

    #include <Windows.h>
    #include "IApplication.h"
    #include "IWindow.h"
    #include "IController.h"
    #include "Controller.h"

    namespace nApplication
    
        class Application : public IApplication
        
        public:
            Application( HINSTANCE hInstance, int nCmdShow );
            virtual ~Application( );
            virtual int Run( );
            virtual int getnCmdShow( )  return mnCmdShow; 
            virtual HINSTANCE gethInstance( )  return mhInstance; 
            virtual IController* getMainControl( )  return main_control; 
        private:
            int mnCmdShow;
            HINSTANCE mhInstance;
            int MessageLoop();
            Application( Application &app );
            Application& operator= ( const Application &app );
        ;

    

    #endif /* IAPPLICATION */

-

    #include "Application.h"
    #include "MainWindow.h"

    namespace nApplication
    
        Application::Application( HINSTANCE hInstance, int nCmdShow )
            : mhInstance( hInstance ), mnCmdShow( nCmdShow )
        
        

    Application::~Application( )
    
    


    int Application::Run( )
    
        main_window = new MainWindow( this );
        main_control = new Controller( this );
        main_window->Init( );
        main_window->Display( );
        MessageLoop( );
        delete main_window;
        return 0;
    

    int Application::MessageLoop()
    
        MSG msg;

        while(GetMessage(&msg, NULL, 0, 0) != 0) 
        
            TranslateMessage(&msg);


        DispatchMessage(&msg);
        
        return (int)msg.wParam;
    


-

    #ifndef IWINDOW_H_
    #define IWINDOW_H_

    #include <Windows.h>
    #include "IController.h"

    namespace nApplication
    
        class IWindow
        
        public:
            virtual void Init() = 0;
            virtual void Display( ) = 0;


    private:
    ;
    
    #endif /* IWINDOW_H_ */

-

    #ifndef MAINWINDOW_H_
    #define MAINWINDOW_H_

    #include <windows.h>
    #include "IWindow.h"
    #include "IController.h"
    #include "IApplication.h"

    namespace nApplication
    
        class MainWindow : public IWindow
        
        public:
            MainWindow( IApplication *iApp);
            ~MainWindow();
            void Init();
            void Display( );
        private:
            WNDCLASSEX wc;
            HWND hWnd;
            IApplication *iApp;
        ;
    

    #endif //MAINWINDOW_H_

-

    #include "MainWindow.h"

    namespace nApplication
    
        namespace 
        
            LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
            
                HDC hDC;
                PAINTSTRUCT ps;

                static IController *cntrl;
                cntrl = (IController*)::GetWindowLongPtr(hWnd, GWL_USERDATA);

                if(uMsg == WM_NCCREATE)
                
                    cntrl = (IController*)(((CREATESTRUCT*)lParam)->lpCreateParams);
                    ::SetWindowLongPtr(hWnd, GWL_USERDATA, (LONG_PTR)cntrl);
                    cntrl->CheckStatus();
                    return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
                

                switch(uMsg) 
                
                    case WM_CREATE:
                    
                    
                    case WM_PAINT:
                                
                        hDC = BeginPaint( hWnd, &ps );
                        TextOut( hDC, 10, 10, TEXT("Hello, Windows!"), 15 );
                        EndPaint( hWnd, &ps );
                        return 0;
                    
                    case WM_DESTROY:
                    
                        PostQuitMessage( 0 );
                        return 0;
                    
                    default:
                    
                        return DefWindowProc( hWnd, uMsg, wParam, lParam );
                    
                
            
        

        MainWindow::MainWindow( IApplication* iApp ) : iApp( iApp )
        
            wc.cbSize        = sizeof(WNDCLASSEX);
            wc.style         = 0;
            wc.lpfnWndProc   = MainWndProc;
            wc.cbClsExtra    = 0;
            wc.cbWndExtra    = 0;
            wc.hInstance     = iApp->gethInstance( );
            wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
            wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
            wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
            wc.lpszMenuName  = TEXT( "GenericAppMenu");
            wc.lpszClassName = TEXT( "myWindowClass" );
            wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
        

        MainWindow::~MainWindow()
        
        

        void MainWindow::Init()
        
            if( !RegisterClassEx(&wc) )
            
                MessageBox(NULL, TEXT( "Window Registration Failed!" ), TEXT( "Error!" ), MB_ICONEXCLAMATION | MB_OK);
                exit(0);
            
        

        void MainWindow::Display( )
        
            hWnd = ::CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("myWindowClass"), 
            TEXT("The title of my window"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 
            240, 120, NULL, NULL, iApp->gethInstance( ), iApp->getMainControl( ) );

            if(hWnd == NULL)
            
                ::MessageBox( NULL, TEXT( "Window Creation Failed!" ), 
                    TEXT( "Error!" ), MB_ICONEXCLAMATION | MB_OK );
                exit(0);
            

        ::ShowWindow( hWnd, iApp->getnCmdShow( ) );
        ::UpdateWindow(hWnd);
    


-

        #ifndef ICONTROLLER_H_
        #define ICONTROLLER_H_

        #include <windows.h>

        namespace nApplication
        
            class IController
            
            public:
                virtual int CheckStatus() = 0;
            ;
    

    #endif ICONTROLLER_H_

-

    #ifndef CONTROLLER_H_
    #define CONTROLLER_H_

    #include <windows.h>
    #include "IController.h"
    #include "IApplication.h"

    namespace nApplication
    
        class Controller : public IController
        
        public:
            Controller( IApplication *iApp );
            virtual ~Controller();
            virtual int CheckStatus();
        private:
            Controller( Controller &c );
            Controller& operator= ( Controller &c );
            IApplication *iApp;
        ;
    

    #endif //CONTROLLER_H_

-

    #include "Controller.h"

    namespace nApplication
    
        Controller::Controller( IApplication *iApp ) : iApp( iApp )
        

        

        Controller::~Controller()
        
        

        int Controller::CheckStatus()
        
            return 0;
        
    

-

#include <windows.h>
#include "Application.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

    nApplication::Application app( hInstance, nCmdShow );
    return app.Run( );


-

main.exe : main.cpp 
    cl /EHsc main.cpp Application.cpp Controller.cpp MainWindow.cpp user32.lib gdi32.lib
    del *.obj
#/link /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup

【问题讨论】:

【参考方案1】:

如果你正在创建一个库,你没有WinMain,你有一个用于动态库的DllMain,或者没有用于静态库。

在您的情况下,您需要 export dll 中的所有类功能,然后在使用您的库的任何应用程序中,您需要包含项目的标头并链接到 .lib库,然后在您需要 GUI 功能的应用程序中使用它:

nApplication::Application app( hInstance, nCmdShow );
return app.Run( );

当然,这会忽略所有细节,例如注册事件回调和设置这些行,但是 Qt 是免费和开源的,您可能想在重新发明***之前研究一下,或者帮助自己制作***圆一点。

【讨论】:

我在 Qt 表单上有两个线程来解决这个问题,那里的成员说 WinMain 通过链接到类似于 MFC 的 Qts DLL 被“包含”在其中。例如,请参阅此处的最后几篇帖子,developer.qt.nokia.com/forums/viewthread/8908/#51775。当我正在研究源代码时,我仍然有点困惑。这是我正在努力理解的第一个开源项目。这是我做我正在做的事情的主要动机。 @Matthew:Qt 的工作方式略有不同,因为它是为多平台 UI 开发人员构建的:它使用 main 作为程序入口点(在您的代码中),但在寡妇上,它将创建自己的自己的伪'WinMain'(虽然它实际上不需要,它只需要确保在没有请求时不创建控制台) 我现在有两个相互矛盾的解释。我知道nmake Makefile 中的#/link /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup 允许您在非控制台应用程序中将入口点指定为main()。但是,当您设置 WndClassEx 时,您需要一个 hInstance,如果您使用 main,则不提供该实例。没有其他方法可以创建一个窗口。此外,如果您查看 Qt 的源代码,您会发现 WinMain 实际上调用了您的 main 函数。所以 main 不是程序的入口点,它只是对非 Windows 程序员的一种方便。在被称为入口的linux中并非如此。 @Matthew: GetModuleHandle(NULL) 如果从您的主线程(也就是启动的应用程序)调用,会为您获取 hInstance,还有其他一些获取它的方法。如果从您的主线程调用实例线程(又名启动的应用程序),还有其他一些获取它的方法。

以上是关于我自己的个人 MFC的主要内容,如果未能解决你的问题,请参考以下文章

VS2013生成Release版本MFC程序在其他机器上运行

我自己的 C++ 框架(类似 MFC),我可以创建子窗口,但在 WM_CREATE 时无法创建编辑框

MFC combox 多选

MFC技巧一:单文档中将系统菜单栏替换为自己建立的菜单栏(转)

MFC和Qt优缺点 (MFC几乎没有优点全面下风)

覆盖 CObList MFC 的复制构造函数