GacUIソースコードの概要(一)


GacUIソースコードの概要(一)
本明細書で説明するGacUIソースコードは、https://github.com/vczh-libraries/GacUI.
GacUIでは、`WinMain`の開始後、最初に実行される関数は`SetupWindowsDirect 2 DRenderer`:
int SetupWindowsDirect2DRenderer()
{
    CoInitializeEx(NULL, COINIT_MULTITHREADED);
    HINSTANCE hInstance=(HINSTANCE)GetModuleHandle(NULL);
    WinDirect2DApplicationDirect2DObjectProvider objectProvider;
    SetWindowsDirect2DObjectProvider(&objectProvider);
    return WinMainDirect2D(hInstance, &RendererMainDirect2D);
}

D 2 D 1 Factory、DWriteFactory etc.などの多くのfactoryは、`WinDirect 2 DApplicationDirect 2 DObjectProvider`によって取得できますが、これらのリソースは`WinDirect 2 DApplicationDirect 2 DObjectProvider`に格納されていないことに注意してください.次に`WinMainDirect 2 D`に目を向けます.
int WinMainDirect2D(HINSTANCE hInstance, void(*RendererMain)())
{
    EnableCrossKernelCrashing();
    // create controller
    INativeController* controller=CreateWindowsNativeController(hInstance);
    SetCurrentController(controller);
    {
        // install listener
        Direct2DWindowsNativeControllerListener listener;
        controller->CallbackService()->InstallListener(&listener);
        direct2DListener=&listener;
        // main
        RendererMain();
        // uninstall listener
        direct2DListener=0;
        controller->CallbackService()->UninstallListener(&listener);
    }
    // destroy controller
    DestroyWindowsNativeController(controller);
    return 0;
}

まず、`CreateWindowsNativeController`を呼び出してControllerを得ました.このControllerはGacUIの核心と言えます.でも焦らないで、まず`SetCurrentController`が何をしたか見てみましょう.
INativeController* currentController=0;

INativeController* GetCurrentController()
{
    return currentController;
}

void SetCurrentController(INativeController* controller)
{
    currentController=controller;
}

GacUIには、グローバル変数`currentController`があることがわかります.このControllerがどこで神聖なのか見てみましょう.
class WindowsController : public Object, public virtual INativeController, public virtual INativeWindowService
{
protected:
            WinClass                            windowClass;
            WinClass                            godClass;
            HINSTANCE                           hInstance;
            HWND                                godWindow;
            Dictionary      windows;
            INativeWindow*                      mainWindow;
            HWND                                mainWindowHandle;

            WindowsCallbackService              callbackService;
            WindowsResourceService              resourceService;
            WindowsAsyncService                 asyncService;
            WindowsClipboardService             clipboardService;
            WindowsImageService                 imageService;
            WindowsScreenService                screenService;
            WindowsInputService                 inputService;
            WindowsDialogService                dialogService;

次のことがわかります.
  • ウィンドウのWinClassおよびGodWindowWindowClassを管理する.
  • また、Serviceのような多くのInputServiceを管理し、入力を処理する.ClipBoardService、クリップボードを処理する.
  • は、Dictionaryを処理するときに、WndProcに従って対応するhWndを迅速に見つけるために、WinFormを維持する.

  • `WinClass`は`WNDCLASEX`のパッケージですが、ここに注意してください.
    WindowsController(HINSTANCE _hInstance)
                        :hInstance(_hInstance)
                        ,windowClass(L"VczhWindow", false, false, WndProc, _hInstance)
                        ,godClass(L"GodWindow", false, false, GodProc, _hInstance)
                        ,...

    `VczhWindow`のウィンドウプロセスが`WndProc`に登録されていることがわかります.
    LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
                WindowsController* controller=dynamic_cast(GetCurrentController());
                if(controller)
                {
                    LRESULT result=0;
                    if(controller->HandleMessage(hwnd, uMsg, wParam, lParam, result))
                    {
                        return result;
                    }
                }
                return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

    すなわち、メッセージが来ると、先に述べたグローバルストレージのControllerを取得し、本格的なメッセージ処理をControllerに渡す.Controllerでは、最後に`WinForm`にメッセージを転送することがわかります.
        WindowsForm* window=windows.Values().Get(index);
        skipDefaultProcedure=window->HandleMessage(hwnd, uMsg, wParam, lParam, result);

    `WinForm`はメッセージを受け取るとListenerに転送されます.
    case WM_MBUTTONDBLCLK:
    {
                NativeWindowMouseInfo info=ConvertMouse(wParam, lParam, false, nonClient);
                for(vint i=0;iMiddleButtonDoubleClick(info);
                }
    }
    break;

    メッセージはそのまま転送されました!
    そしてDirect2DWindowsNativeControllerListenerDirect2D、3Dに必要ないくつかのFactory:
    class Direct2DWindowsNativeControllerListener : public Object, public INativeControllerListener
    {
    public:
            Dictionary>        nativeWindowListeners;
            ComPtr                                                        d2dFactory;
            ComPtr                                                      dwrite;
            ComPtr                                                        d3d11Device;
            ...

    `direct 2 Dlistener`については、言うまでもなく、グローバル変数です(JavaerはいわゆるSingletonを使用していないと批判するかもしれません:)
    そして、`renderMain()`を呼び出すと、`RenderMainDirect 2 D`がまた`GuiApplicationMain`、`GuiApplicationMain`自体が`GuiApplicationInitialize`を呼び出すようになり、いよいよ走り出す時が来たようです!
    void GuiApplicationInitialize()
                {
                    Ptr<:itheme> theme;
                    {
                        WString osVersion=GetCurrentController()->GetOSVersion();
                        vint index=osVersion.IndexOf(L';');
                        if (index == -1)
                        {
                            theme=new win8::Win8Theme;
                        }
                        else
                        {
                            WString osMainVersion=osVersion.Sub(0, index);
                            if(osMainVersion==L"Windows 8" || osMainVersion==L"Windows Server 2012")
                            {
                                theme=new win8::Win8Theme;
                            }
                            else
                            {
                                theme=new win7::Win7Theme;
                            }
                        }
                    }
    
                    GetCurrentController()->InputService()->StartTimer();
                    GuiApplication app;
                    application=&app;
    
                    GetPluginManager()->Load();
                    GetGlobalTypeManager()->Load();
                    theme::SetCurrentTheme(theme.Obj());
                    GuiMain();
                    theme::SetCurrentTheme(0);
                    DestroyPluginManager();
                    DestroyGlobalTypeManager();
                    ThreadLocalStorage::DisposeStorages();
                }
            }
        }
    }
  • まず、システムバージョンに基づいてテーマを選択します(現在GacUIはWindows 10と互換性がありません.VerifyVersionInfoはまたマイクロソフトに廃棄されたためです...).
  • からTimer.TimerInputServiceが担当する:
  • void WindowsInputService::StartTimer()
                {
                    if(!IsTimerEnabled())
                    {
                        SetTimer(ownerHandle, 1, 16, NULL);
                        isTimerEnabled=true;
                    }
                }
    
                void WindowsInputService::StopTimer()
                {
                    if(IsTimerEnabled())
                    {
                        KillTimer(ownerHandle, 1);
                        isTimerEnabled=false;
                    }
                }
    
    Timerメッセージの処理はCallbackServiceが担当します.
    void WindowsCallbackService::InvokeGlobalTimer()
    {
            for(vint i=0;iGlobalTimer();
            }
    }

    ちなみにGacUIのレンダリングはWM_PAINTではなく、このTimerを使用して16 msごとにトリガーされます.
  • の古い手口は、GuiApplicationを定義し、全体のapplicationを設定します.
  • は、GuiMainを実行する.通常、GuiMainには、
  • が表示されます.
    GetApplication()->Run(&window);

    このRunは非常に率直です.
    void GuiApplication::Run(GuiWindow* _mainWindow)
    {
                if(!mainWindow)
                {
                    mainWindow=_mainWindow;
                    GetCurrentController()->WindowService()->Run(mainWindow->GetNativeWindow());
                    mainWindow=0;
                }
    }

    ControllerのRunが呼び出されます.
    
    void Run(INativeWindow* window)
    {
            mainWindow=window;
            mainWindowHandle=GetWindowsForm(window)->GetWindowHandle();
            mainWindow->Show();
            MSG message;
            while(GetMessage(&message, NULL, 0, 0))
            {
                TranslateMessage(&message);
                DispatchMessage(&message);
                asyncService.ExecuteAsyncTasks();
            }
    }

    ああ、やっとプログラムがRunになった.