Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/windows/leash/LeashUIApplication.cpp
34889 views
1
// -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*-
2
// leash/LeashUIApplication.cpp - Implement IUIApplication for leash
3
//
4
// Copyright (C) 2014 by the Massachusetts Institute of Technology.
5
// All rights reserved.
6
//
7
// Redistribution and use in source and binary forms, with or without
8
// modification, are permitted provided that the following conditions
9
// are met:
10
//
11
// * Redistributions of source code must retain the above copyright
12
// notice, this list of conditions and the following disclaimer.
13
//
14
// * Redistributions in binary form must reproduce the above copyright
15
// notice, this list of conditions and the following disclaimer in
16
// the documentation and/or other materials provided with the
17
// distribution.
18
//
19
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30
// OF THE POSSIBILITY OF SUCH DAMAGE.
31
32
// Implementation of the LeashUIApplication class. In addition
33
// to the minimum requirements for the IUIApplication interface,
34
// it also saves and loads the ribbon state across application
35
// sessions, and initiates a redraw of the parent window when
36
// the ribbon size changes.
37
38
#include <UIRibbon.h>
39
#include <UIRibbonPropertyHelpers.h>
40
#include "kfwribbon.h"
41
#include "LeashUIApplication.h"
42
#include "LeashUICommandHandler.h"
43
44
HWND LeashUIApplication::mainwin;
45
46
// The input hwnd is the window to which to bind the ribbon, i.e.,
47
// the Leash CMainFrame.
48
HRESULT
49
LeashUIApplication::CreateInstance(IUIApplication **out, HWND hwnd)
50
{
51
LeashUIApplication *app = NULL;
52
LeashUICommandHandler *handler;
53
HRESULT ret;
54
55
if (out == NULL)
56
return E_POINTER;
57
*out = NULL;
58
59
app = new LeashUIApplication();
60
ret = LeashUICommandHandler::CreateInstance(&app->commandHandler, hwnd);
61
if (FAILED(ret))
62
goto out;
63
ret = app->InitializeRibbon(hwnd);
64
if (FAILED(ret))
65
goto out;
66
mainwin = hwnd;
67
// Only the Leash-specific handler type has the back-pointer.
68
handler = static_cast<LeashUICommandHandler *>(app->commandHandler);
69
handler->app = app;
70
*out = static_cast<IUIApplication *>(app);
71
app = NULL;
72
ret = S_OK;
73
74
out:
75
if (app != NULL)
76
app->Release();
77
return ret;
78
}
79
80
// Create a ribbon framework and ribbon for the LeashUIApplication.
81
// CoInitializeEx() is required to be called before calling any COM
82
// functions. AfxOleInit(), called from CLeashApp::InitInstance(),
83
// makes that call, but it is only scoped to the calling thread,
84
// and the LeashUIApplication is created from CMainFrame, which is
85
// the frame for the MFC document template. It is unclear if the
86
// Leash main thread will be the same thread which runs the frame
87
// from the document template, so call CoInitializeEx() ourselves
88
// just in case. It is safe to call multiple times (it will return
89
// S_FALSE on subsequent calls).
90
HRESULT
91
LeashUIApplication::InitializeRibbon(HWND hwnd)
92
{
93
HRESULT ret;
94
95
if (hwnd == NULL)
96
return -1;
97
ret = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
98
if (FAILED(ret))
99
return ret;
100
ret = CoCreateInstance(CLSID_UIRibbonFramework, NULL,
101
CLSCTX_INPROC_SERVER,
102
IID_PPV_ARGS(&ribbonFramework));
103
if (FAILED(ret))
104
return ret;
105
ret = ribbonFramework->Initialize(hwnd, this);
106
if (FAILED(ret))
107
return ret;
108
ret = ribbonFramework->LoadUI(GetModuleHandle(NULL),
109
L"KFW_RIBBON_RIBBON");
110
if (FAILED(ret))
111
return ret;
112
return S_OK;
113
}
114
115
// Import ribbon state (minimization state and Quick Access Toolbar
116
// customizations) from a serialized stream stored in the registry.
117
// In particular, the serialized state does not include the state
118
// of checkboxes and other ribbon controls.
119
//
120
// This functionality is not very important, since we do not offer
121
// much in the way of QAT customization. Paired with SaveRibbonState().
122
HRESULT
123
LeashUIApplication::LoadRibbonState(IUIRibbon *ribbon)
124
{
125
HRESULT ret;
126
IStream *s;
127
128
s = SHOpenRegStream2(HKEY_CURRENT_USER, "Software\\MIT\\Kerberos5",
129
"RibbonState", STGM_READ);
130
if (s == NULL)
131
return E_FAIL;
132
ret = ribbon->LoadSettingsFromStream(s);
133
s->Release();
134
return ret;
135
}
136
137
// Serialize the ribbon state (minimization state and Quick Access Toolbar
138
// customizations) to the registry. Paired with LoadRibbonState().
139
HRESULT
140
LeashUIApplication::SaveRibbonState()
141
{
142
HRESULT ret;
143
IStream *s = NULL;
144
IUIRibbon *ribbon = NULL;
145
146
// No ribbon means no state to save.
147
if (ribbonFramework == NULL)
148
return S_OK;
149
// ViewID of 0 is the ribbon itself.
150
ret = ribbonFramework->GetView(0, IID_PPV_ARGS(&ribbon));
151
if (FAILED(ret))
152
return ret;
153
154
s = SHOpenRegStream2(HKEY_CURRENT_USER, "Software\\MIT\\Kerberos5",
155
"RibbonState", STGM_WRITE);
156
if (s == NULL) {
157
ret = E_FAIL;
158
goto out;
159
}
160
ret = ribbon->SaveSettingsToStream(s);
161
162
out:
163
if (s != NULL)
164
s->Release();
165
if (ribbon != NULL)
166
ribbon->Release();
167
return ret;
168
}
169
170
UINT
171
LeashUIApplication::GetRibbonHeight()
172
{
173
return ribbonHeight;
174
}
175
176
ULONG
177
LeashUIApplication::AddRef()
178
{
179
return InterlockedIncrement(&refcnt);
180
}
181
182
ULONG
183
LeashUIApplication::Release()
184
{
185
LONG tmp;
186
187
tmp = InterlockedDecrement(&refcnt);
188
if (tmp == 0) {
189
if (commandHandler != NULL)
190
commandHandler->Release();
191
if (ribbonFramework != NULL)
192
ribbonFramework->Release();
193
delete this;
194
}
195
return tmp;
196
}
197
198
HRESULT
199
LeashUIApplication::QueryInterface(REFIID iid, void **ppv)
200
{
201
if (ppv == NULL)
202
return E_POINTER;
203
204
if (iid == __uuidof(IUnknown)) {
205
*ppv = static_cast<IUnknown*>(this);
206
} else if (iid == __uuidof(IUIApplication)) {
207
*ppv = static_cast<IUIApplication*>(this);
208
} else {
209
*ppv = NULL;
210
return E_NOINTERFACE;
211
}
212
213
AddRef();
214
return S_OK;
215
}
216
217
// This is called by the ribbon framework on events which change the (ribbon)
218
// view, such as creation and resizing. (There may be other non-ribbon views
219
// in the future, but for now, the ribbon is the only one.) With the hybrid
220
// COM/MFC setup used by Leash, the destroy event is not always received,
221
// since the main thread is in the MFC half, and that thread gets the
222
// WM_DESTROY message from the system; the MFC code does not know that it
223
// needs to cleanly destroy the IUIFramework.
224
HRESULT
225
LeashUIApplication::OnViewChanged(UINT32 viewId, UI_VIEWTYPE typeID,
226
IUnknown *view, UI_VIEWVERB verb,
227
INT32 uReasonCode)
228
{
229
IUIRibbon *ribbon;
230
HRESULT ret;
231
232
// A viewId means "the ribbon".
233
if (viewId != 0 || typeID != UI_VIEWTYPE_RIBBON)
234
return E_NOTIMPL;
235
236
switch(verb) {
237
case UI_VIEWVERB_DESTROY:
238
return SaveRibbonState();
239
case UI_VIEWVERB_CREATE:
240
ret = view->QueryInterface(IID_PPV_ARGS(&ribbon));
241
if (FAILED(ret))
242
return ret;
243
ret = LoadRibbonState(ribbon);
244
ribbon->Release();
245
if (FAILED(ret))
246
return ret;
247
// FALLTHROUGH
248
case UI_VIEWVERB_SIZE:
249
ret = view->QueryInterface(IID_PPV_ARGS(&ribbon));
250
if (FAILED(ret))
251
return ret;
252
ret = ribbon->GetHeight(&ribbonHeight);
253
ribbon->Release();
254
if (FAILED(ret))
255
return ret;
256
// Tell the main frame to recalculate its layout and redraw.
257
SendMessage(mainwin, WM_RIBBON_RESIZE, 0, NULL);
258
return S_OK;
259
case UI_VIEWVERB_ERROR:
260
// FALLTHROUGH
261
default:
262
return E_NOTIMPL;
263
}
264
}
265
266
// Provide a command handler to which the command with ID commandId will
267
// be bound. All of our commands get the same handler.
268
//
269
// The typeID argument is just an enum which classifies what type of
270
// command this is, grouping types of buttons together, collections,
271
// etc. Since we only have one command handler, it can safely be ignored.
272
HRESULT
273
LeashUIApplication::OnCreateUICommand(UINT32 commandId, UI_COMMANDTYPE typeID,
274
IUICommandHandler **commandHandler)
275
{
276
return this->commandHandler->QueryInterface(IID_PPV_ARGS(commandHandler));
277
}
278
279
// It looks like this is called by the framework when the window with the
280
// ribbon is going away, to give the application a chance to free any
281
// application-specific resources (not from the framework) that were bound
282
// to a command in OnCreateUICommand.
283
//
284
// We do not have any such resources, so we do not need to implement this
285
// function other than by returning success.
286
HRESULT
287
LeashUIApplication::OnDestroyUICommand(UINT32 commandId, UI_COMMANDTYPE typeID,
288
IUICommandHandler *commandHandler)
289
{
290
return S_OK;
291
}
292
293