Path: blob/main/crypto/krb5/src/windows/leash/LeashUIApplication.cpp
34889 views
// -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*-1// leash/LeashUIApplication.cpp - Implement IUIApplication for leash2//3// Copyright (C) 2014 by the Massachusetts Institute of Technology.4// All rights reserved.5//6// Redistribution and use in source and binary forms, with or without7// modification, are permitted provided that the following conditions8// are met:9//10// * Redistributions of source code must retain the above copyright11// notice, this list of conditions and the following disclaimer.12//13// * Redistributions in binary form must reproduce the above copyright14// notice, this list of conditions and the following disclaimer in15// the documentation and/or other materials provided with the16// distribution.17//18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS21// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE22// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,23// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES24// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR25// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,27// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)28// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED29// OF THE POSSIBILITY OF SUCH DAMAGE.3031// Implementation of the LeashUIApplication class. In addition32// to the minimum requirements for the IUIApplication interface,33// it also saves and loads the ribbon state across application34// sessions, and initiates a redraw of the parent window when35// the ribbon size changes.3637#include <UIRibbon.h>38#include <UIRibbonPropertyHelpers.h>39#include "kfwribbon.h"40#include "LeashUIApplication.h"41#include "LeashUICommandHandler.h"4243HWND LeashUIApplication::mainwin;4445// The input hwnd is the window to which to bind the ribbon, i.e.,46// the Leash CMainFrame.47HRESULT48LeashUIApplication::CreateInstance(IUIApplication **out, HWND hwnd)49{50LeashUIApplication *app = NULL;51LeashUICommandHandler *handler;52HRESULT ret;5354if (out == NULL)55return E_POINTER;56*out = NULL;5758app = new LeashUIApplication();59ret = LeashUICommandHandler::CreateInstance(&app->commandHandler, hwnd);60if (FAILED(ret))61goto out;62ret = app->InitializeRibbon(hwnd);63if (FAILED(ret))64goto out;65mainwin = hwnd;66// Only the Leash-specific handler type has the back-pointer.67handler = static_cast<LeashUICommandHandler *>(app->commandHandler);68handler->app = app;69*out = static_cast<IUIApplication *>(app);70app = NULL;71ret = S_OK;7273out:74if (app != NULL)75app->Release();76return ret;77}7879// Create a ribbon framework and ribbon for the LeashUIApplication.80// CoInitializeEx() is required to be called before calling any COM81// functions. AfxOleInit(), called from CLeashApp::InitInstance(),82// makes that call, but it is only scoped to the calling thread,83// and the LeashUIApplication is created from CMainFrame, which is84// the frame for the MFC document template. It is unclear if the85// Leash main thread will be the same thread which runs the frame86// from the document template, so call CoInitializeEx() ourselves87// just in case. It is safe to call multiple times (it will return88// S_FALSE on subsequent calls).89HRESULT90LeashUIApplication::InitializeRibbon(HWND hwnd)91{92HRESULT ret;9394if (hwnd == NULL)95return -1;96ret = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);97if (FAILED(ret))98return ret;99ret = CoCreateInstance(CLSID_UIRibbonFramework, NULL,100CLSCTX_INPROC_SERVER,101IID_PPV_ARGS(&ribbonFramework));102if (FAILED(ret))103return ret;104ret = ribbonFramework->Initialize(hwnd, this);105if (FAILED(ret))106return ret;107ret = ribbonFramework->LoadUI(GetModuleHandle(NULL),108L"KFW_RIBBON_RIBBON");109if (FAILED(ret))110return ret;111return S_OK;112}113114// Import ribbon state (minimization state and Quick Access Toolbar115// customizations) from a serialized stream stored in the registry.116// In particular, the serialized state does not include the state117// of checkboxes and other ribbon controls.118//119// This functionality is not very important, since we do not offer120// much in the way of QAT customization. Paired with SaveRibbonState().121HRESULT122LeashUIApplication::LoadRibbonState(IUIRibbon *ribbon)123{124HRESULT ret;125IStream *s;126127s = SHOpenRegStream2(HKEY_CURRENT_USER, "Software\\MIT\\Kerberos5",128"RibbonState", STGM_READ);129if (s == NULL)130return E_FAIL;131ret = ribbon->LoadSettingsFromStream(s);132s->Release();133return ret;134}135136// Serialize the ribbon state (minimization state and Quick Access Toolbar137// customizations) to the registry. Paired with LoadRibbonState().138HRESULT139LeashUIApplication::SaveRibbonState()140{141HRESULT ret;142IStream *s = NULL;143IUIRibbon *ribbon = NULL;144145// No ribbon means no state to save.146if (ribbonFramework == NULL)147return S_OK;148// ViewID of 0 is the ribbon itself.149ret = ribbonFramework->GetView(0, IID_PPV_ARGS(&ribbon));150if (FAILED(ret))151return ret;152153s = SHOpenRegStream2(HKEY_CURRENT_USER, "Software\\MIT\\Kerberos5",154"RibbonState", STGM_WRITE);155if (s == NULL) {156ret = E_FAIL;157goto out;158}159ret = ribbon->SaveSettingsToStream(s);160161out:162if (s != NULL)163s->Release();164if (ribbon != NULL)165ribbon->Release();166return ret;167}168169UINT170LeashUIApplication::GetRibbonHeight()171{172return ribbonHeight;173}174175ULONG176LeashUIApplication::AddRef()177{178return InterlockedIncrement(&refcnt);179}180181ULONG182LeashUIApplication::Release()183{184LONG tmp;185186tmp = InterlockedDecrement(&refcnt);187if (tmp == 0) {188if (commandHandler != NULL)189commandHandler->Release();190if (ribbonFramework != NULL)191ribbonFramework->Release();192delete this;193}194return tmp;195}196197HRESULT198LeashUIApplication::QueryInterface(REFIID iid, void **ppv)199{200if (ppv == NULL)201return E_POINTER;202203if (iid == __uuidof(IUnknown)) {204*ppv = static_cast<IUnknown*>(this);205} else if (iid == __uuidof(IUIApplication)) {206*ppv = static_cast<IUIApplication*>(this);207} else {208*ppv = NULL;209return E_NOINTERFACE;210}211212AddRef();213return S_OK;214}215216// This is called by the ribbon framework on events which change the (ribbon)217// view, such as creation and resizing. (There may be other non-ribbon views218// in the future, but for now, the ribbon is the only one.) With the hybrid219// COM/MFC setup used by Leash, the destroy event is not always received,220// since the main thread is in the MFC half, and that thread gets the221// WM_DESTROY message from the system; the MFC code does not know that it222// needs to cleanly destroy the IUIFramework.223HRESULT224LeashUIApplication::OnViewChanged(UINT32 viewId, UI_VIEWTYPE typeID,225IUnknown *view, UI_VIEWVERB verb,226INT32 uReasonCode)227{228IUIRibbon *ribbon;229HRESULT ret;230231// A viewId means "the ribbon".232if (viewId != 0 || typeID != UI_VIEWTYPE_RIBBON)233return E_NOTIMPL;234235switch(verb) {236case UI_VIEWVERB_DESTROY:237return SaveRibbonState();238case UI_VIEWVERB_CREATE:239ret = view->QueryInterface(IID_PPV_ARGS(&ribbon));240if (FAILED(ret))241return ret;242ret = LoadRibbonState(ribbon);243ribbon->Release();244if (FAILED(ret))245return ret;246// FALLTHROUGH247case UI_VIEWVERB_SIZE:248ret = view->QueryInterface(IID_PPV_ARGS(&ribbon));249if (FAILED(ret))250return ret;251ret = ribbon->GetHeight(&ribbonHeight);252ribbon->Release();253if (FAILED(ret))254return ret;255// Tell the main frame to recalculate its layout and redraw.256SendMessage(mainwin, WM_RIBBON_RESIZE, 0, NULL);257return S_OK;258case UI_VIEWVERB_ERROR:259// FALLTHROUGH260default:261return E_NOTIMPL;262}263}264265// Provide a command handler to which the command with ID commandId will266// be bound. All of our commands get the same handler.267//268// The typeID argument is just an enum which classifies what type of269// command this is, grouping types of buttons together, collections,270// etc. Since we only have one command handler, it can safely be ignored.271HRESULT272LeashUIApplication::OnCreateUICommand(UINT32 commandId, UI_COMMANDTYPE typeID,273IUICommandHandler **commandHandler)274{275return this->commandHandler->QueryInterface(IID_PPV_ARGS(commandHandler));276}277278// It looks like this is called by the framework when the window with the279// ribbon is going away, to give the application a chance to free any280// application-specific resources (not from the framework) that were bound281// to a command in OnCreateUICommand.282//283// We do not have any such resources, so we do not need to implement this284// function other than by returning success.285HRESULT286LeashUIApplication::OnDestroyUICommand(UINT32 commandId, UI_COMMANDTYPE typeID,287IUICommandHandler *commandHandler)288{289return S_OK;290}291292293