785 lines
23 KiB
C++
785 lines
23 KiB
C++
|
//
|
||
|
// uisupport.cpp
|
||
|
//
|
||
|
// User interface support for WinTrust
|
||
|
//
|
||
|
#include "stdpch.h"
|
||
|
#include "common.h"
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Support for the 'bad trust' dialog
|
||
|
|
||
|
CBadTrustDialog::CBadTrustDialog(RRNIN*prrn, RRNOUT*prro, HWND pParent /*=NULL*/)
|
||
|
{
|
||
|
m_fFirst = TRUE;
|
||
|
m_rrn = *prrn;
|
||
|
m_prro = prro;
|
||
|
|
||
|
// Initialize values for the other-than-ok case
|
||
|
m_prro->rrn = RRN_NO;
|
||
|
m_prro->fWildPublisher = FALSE;
|
||
|
m_prro->fWildAgency = FALSE;
|
||
|
|
||
|
m_hWnd = NULL;
|
||
|
m_hWndParent = pParent;
|
||
|
|
||
|
m_hbrBackground = NULL;
|
||
|
}
|
||
|
|
||
|
CBadTrustDialog::~CBadTrustDialog()
|
||
|
{
|
||
|
if (m_hbrBackground)
|
||
|
{
|
||
|
DeleteObject(m_hbrBackground);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HBRUSH CBadTrustDialog::OnCtlColorEdit(HDC hdcEdit, HWND hwndEdit)
|
||
|
{
|
||
|
if (hwndEdit == WindowOf(IDC_BADTRUSTBANTER2))
|
||
|
{
|
||
|
SetBkColor(hdcEdit, GetSysColor(COLOR_BTNFACE)); // text background color
|
||
|
return m_hbrBackground; // brush for edit control background
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void SizeControlToFitText(HWND hwndEdit)
|
||
|
//
|
||
|
// Size this multi-line edit control to fit the text contained therein
|
||
|
//
|
||
|
{
|
||
|
// get the DC for the edit control
|
||
|
HDC hdc = GetDC(hwndEdit);
|
||
|
|
||
|
// get the metrics of the font used in the control
|
||
|
HFONT hfont = (HFONT)SendMessage(hwndEdit, WM_GETFONT, 0,0);
|
||
|
HFONT hfontPrev = (HFONT)SelectObject(hdc, hfont);
|
||
|
TEXTMETRIC tm;
|
||
|
GetTextMetrics(hdc, &tm);
|
||
|
SelectObject(hdc, hfontPrev);
|
||
|
|
||
|
// release the dc
|
||
|
ReleaseDC(hwndEdit, hdc);
|
||
|
|
||
|
// calculate the new height needed
|
||
|
int cline = SendMessage(hwndEdit, EM_GETLINECOUNT, 0, 0);
|
||
|
int h = cline * tm.tmHeight;
|
||
|
|
||
|
//re-size the edit control
|
||
|
RECT rc;
|
||
|
GetWindowRect(hwndEdit, &rc);
|
||
|
SetWindowPos(hwndEdit, NULL, 0, 0, Width(rc), h, SWP_NOZORDER | SWP_NOMOVE);
|
||
|
}
|
||
|
|
||
|
void CBadTrustDialog::OnInitDialog()
|
||
|
{
|
||
|
//
|
||
|
// Get the background brush for our edit controls
|
||
|
//
|
||
|
m_hbrBackground = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
|
||
|
|
||
|
// Load the icon
|
||
|
LPSTR idi;
|
||
|
switch (m_rrn.hrValid)
|
||
|
{
|
||
|
case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
|
||
|
case TRUST_E_NOSIGNATURE:
|
||
|
idi = IDI_EXCLAMATION;
|
||
|
break;
|
||
|
default:
|
||
|
idi = IDI_HAND;
|
||
|
break;
|
||
|
}
|
||
|
HICON hicon = LoadIcon(NULL, idi);
|
||
|
::SendDlgItemMessage(m_hWnd, IDC_BADTRUSTICON, STM_SETICON, (WPARAM)hicon, (LPARAM)0);
|
||
|
|
||
|
// Set the window title
|
||
|
{
|
||
|
TCHAR sz[128];
|
||
|
WideCharToMultiByte(CP_ACP, 0, m_rrn.wszDialogTitle, -1, (LPSTR)sz, 128, NULL, NULL);
|
||
|
::SetWindowText(GetWindow(), sz);
|
||
|
}
|
||
|
|
||
|
// Set the banter text
|
||
|
int cchBanter2;
|
||
|
{
|
||
|
const int cchMax = INTERNET_MAX_URL_LENGTH+64;
|
||
|
TCHAR sz[cchMax];
|
||
|
|
||
|
// Set the top level banter
|
||
|
::LoadString(hinst, IDS_BADTRUSTBANTER1, &sz[0], cchMax);
|
||
|
::SetWindowText(WindowOf(IDC_BADTRUSTBANTER1), &sz[0]);
|
||
|
|
||
|
// Set the program name
|
||
|
{
|
||
|
//
|
||
|
// The 'program' name we see can in fact often be a full URL. URLs
|
||
|
// can be very long, up to 1024 or so.
|
||
|
//
|
||
|
if (m_rrn.wszProgramName)
|
||
|
{
|
||
|
WideCharToMultiByte(CP_ACP, 0, m_rrn.wszProgramName, -1, &sz[0], cchMax, NULL, NULL);
|
||
|
}
|
||
|
else
|
||
|
::LoadString(hinst, IDS_UNKNOWNPROGRAM, &sz[0], cchMax);
|
||
|
|
||
|
TCHAR szF[cchMax];
|
||
|
::FormatMessage(hinst, &szF[0], cchMax, IDS_BADTRUSTBANTER2, &sz[0]);
|
||
|
|
||
|
::SetWindowText(WindowOf(IDC_BADTRUSTBANTER2), &szF[0]);
|
||
|
cchBanter2 = lstrlen(&szF[0]);
|
||
|
|
||
|
//
|
||
|
// This control is read-only. Note that the text on the control
|
||
|
// can be copied using the context menu in the control.
|
||
|
//
|
||
|
SendMessage(WindowOf(IDC_BADTRUSTBANTER2), EM_SETREADONLY, (WPARAM)TRUE, 0);
|
||
|
}
|
||
|
|
||
|
// Set the trailing banter
|
||
|
UINT ids;
|
||
|
switch (m_rrn.hrValid)
|
||
|
{
|
||
|
case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
|
||
|
case TRUST_E_NOSIGNATURE:
|
||
|
ids = IDS_BADTRUSTBANTER31;
|
||
|
break;
|
||
|
case CERT_E_EXPIRED:
|
||
|
case CERT_E_VALIDIYPERIODNESTING:
|
||
|
ids = IDS_BADTRUSTBANTER32;
|
||
|
break;
|
||
|
case NTE_BAD_SIGNATURE:
|
||
|
ids = IDS_BADTRUSTBANTER33;
|
||
|
break;
|
||
|
default:
|
||
|
ids = IDS_BADTRUSTBANTER34;
|
||
|
break;
|
||
|
}
|
||
|
::LoadString(hinst, ids, &sz[0], cchMax);
|
||
|
::SetWindowText(WindowOf(IDC_BADTRUSTBANTER3), &sz[0]);
|
||
|
|
||
|
}
|
||
|
|
||
|
// Position the controls so that all are visible
|
||
|
{
|
||
|
UINT spacing = GetSystemMetrics(SM_CYFIXEDFRAME) * 2;
|
||
|
RECT rc1, rc2, rc3;
|
||
|
int h;
|
||
|
POINT pt;
|
||
|
|
||
|
//
|
||
|
// Where on the screen is the client area of the dialog?
|
||
|
//
|
||
|
pt.x = 0;
|
||
|
pt.y = 0;
|
||
|
ClientToScreen(GetWindow(), &pt);
|
||
|
|
||
|
//
|
||
|
// Find first text box location
|
||
|
//
|
||
|
GetWindowRect(WindowOf(IDC_BADTRUSTBANTER1), &rc1);
|
||
|
|
||
|
//
|
||
|
// Adjust second text box size
|
||
|
//
|
||
|
SizeControlToFitText(WindowOf(IDC_BADTRUSTBANTER2));
|
||
|
//
|
||
|
// Adjust second text box location
|
||
|
//
|
||
|
GetWindowRect(WindowOf(IDC_BADTRUSTBANTER2), &rc2);
|
||
|
rc2.top = rc1.bottom + spacing;
|
||
|
::SetWindowPos(WindowOf(IDC_BADTRUSTBANTER2), NULL,
|
||
|
rc2.left - pt.x, rc2.top - pt.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
||
|
GetWindowRect(WindowOf(IDC_BADTRUSTBANTER2), &rc2);
|
||
|
|
||
|
//
|
||
|
// Adjust third text box location
|
||
|
//
|
||
|
GetWindowRect(WindowOf(IDC_BADTRUSTBANTER3), &rc3);
|
||
|
h = Height(rc3);
|
||
|
rc3.top = rc2.bottom + spacing;
|
||
|
rc3.bottom = rc3.top + h;
|
||
|
::SetWindowPos(WindowOf(IDC_BADTRUSTBANTER3), NULL,
|
||
|
rc3.left - pt.x, rc3.top - pt.y, Width(rc3), Height(rc3), SWP_NOZORDER);
|
||
|
|
||
|
//
|
||
|
// Adjust the button locations
|
||
|
//
|
||
|
RECT rcOk, rcCancel, rcDetails;
|
||
|
GetWindowRect(WindowOf(IDOK), &rcOk);
|
||
|
GetWindowRect(WindowOf(IDCANCEL), &rcCancel);
|
||
|
GetWindowRect(WindowOf(IDC_DETAILS), &rcDetails);
|
||
|
rcOk.top = rc3.bottom + spacing;
|
||
|
rcCancel.top = rcOk.top;
|
||
|
rcDetails.top = rcOk.top;
|
||
|
::SetWindowPos(WindowOf(IDOK), NULL, rcOk.left-pt.x, rcOk.top-pt.y,0,0, SWP_NOZORDER|SWP_NOSIZE);
|
||
|
::SetWindowPos(WindowOf(IDCANCEL), NULL, rcCancel.left-pt.x, rcCancel.top-pt.y,0,0, SWP_NOZORDER|SWP_NOSIZE);
|
||
|
::SetWindowPos(WindowOf(IDC_DETAILS), NULL, rcDetails.left-pt.x, rcDetails.top-pt.y,0,0, SWP_NOZORDER|SWP_NOSIZE);
|
||
|
GetWindowRect(WindowOf(IDOK), &rcOk);
|
||
|
GetWindowRect(WindowOf(IDCANCEL), &rcCancel);
|
||
|
GetWindowRect(WindowOf(IDC_DETAILS), &rcDetails);
|
||
|
|
||
|
//
|
||
|
// Adjust the overall dialog box size
|
||
|
//
|
||
|
RECT rcMe;
|
||
|
::GetWindowRect(GetWindow(), &rcMe); // screen coords
|
||
|
rcMe.bottom = rcOk.bottom + spacing + GetSystemMetrics(SM_CYFIXEDFRAME);
|
||
|
::SetWindowPos(GetWindow(), NULL, 0,0,Width(rcMe),Height(rcMe), SWP_NOZORDER | SWP_NOMOVE);
|
||
|
|
||
|
//
|
||
|
// Center ourselves in the parent window
|
||
|
//
|
||
|
HWND hwndParent = ::GetParent(GetWindow());
|
||
|
if (hwndParent == NULL)
|
||
|
hwndParent = ::GetDesktopWindow();
|
||
|
RECT rcParent;
|
||
|
::GetWindowRect(GetWindow(), &rcMe); // screen coords
|
||
|
::GetWindowRect(hwndParent, &rcParent); // screen coords
|
||
|
|
||
|
POINT ptParent = Center(rcParent);
|
||
|
POINT ptMe = Center(rcMe);
|
||
|
pt.x = ptParent.x - ptMe.x;
|
||
|
pt.y = ptParent.y - ptMe.y;
|
||
|
|
||
|
::SetWindowPos
|
||
|
(
|
||
|
GetWindow(),
|
||
|
NULL,
|
||
|
pt.x,
|
||
|
pt.y,
|
||
|
0,
|
||
|
0,
|
||
|
SWP_NOZORDER | SWP_NOSIZE
|
||
|
);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure we're on the screen
|
||
|
//
|
||
|
EnsureOnScreen(GetWindow());
|
||
|
|
||
|
//
|
||
|
// Bring ourselves to the attention of the user
|
||
|
//
|
||
|
SetForegroundWindow(GetWindow());
|
||
|
}
|
||
|
|
||
|
BOOL CALLBACK BadTrustDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
CBadTrustDialog* This = (CBadTrustDialog*)GetWindowLong(hwnd, GWL_USERDATA);
|
||
|
|
||
|
switch (uMsg)
|
||
|
{
|
||
|
|
||
|
case WM_HELP:
|
||
|
{
|
||
|
// Define an array of dword pairs,
|
||
|
// where the first of each pair is the control ID,
|
||
|
// and the second is the context ID for a help topic,
|
||
|
// which is used in the help file.
|
||
|
static const DWORD aMenuHelpIDs[] =
|
||
|
{
|
||
|
IDC_BADTRUSTBANTER1, 3,
|
||
|
IDC_BADTRUSTBANTER2, 3,
|
||
|
IDC_BADTRUSTBANTER3, 3,
|
||
|
0, 0
|
||
|
};
|
||
|
|
||
|
LPHELPINFO lphi;
|
||
|
lphi = (LPHELPINFO)lParam;
|
||
|
if (lphi->iContextType == HELPINFO_WINDOW) // must be for a control
|
||
|
{
|
||
|
WinHelp
|
||
|
(
|
||
|
(HWND)(lphi->hItemHandle),
|
||
|
"WINTRUST.HLP",
|
||
|
HELP_WM_HELP,
|
||
|
(DWORD)(LPVOID)aMenuHelpIDs
|
||
|
);
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
case WM_PAINT:
|
||
|
{
|
||
|
if (This->m_fFirst)
|
||
|
{
|
||
|
// Set the 'No' button to be the default
|
||
|
This->m_fFirst = FALSE;
|
||
|
::SendDlgItemMessage(hwnd, IDOK, BM_SETSTYLE, BS_PUSHBUTTON, TRUE);
|
||
|
::SendMessage (hwnd, DM_SETDEFID, IDCANCEL, 0);
|
||
|
::SendDlgItemMessage(hwnd, IDCANCEL, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE);
|
||
|
::SetFocus(GetDlgItem(hwnd,IDCANCEL));
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
case WM_INITDIALOG:
|
||
|
{
|
||
|
// First time in we need to set it
|
||
|
This = (CBadTrustDialog*)lParam;
|
||
|
This->m_hWnd = hwnd;
|
||
|
SetWindowLong(hwnd, GWL_USERDATA, (LONG)This);
|
||
|
This->OnInitDialog();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_COMMAND:
|
||
|
{
|
||
|
WORD wNotifyCode = HIWORD(wParam); // notification code
|
||
|
UINT wID = LOWORD(wParam); // item, control, or accelerator identifier
|
||
|
HWND hwndCtl = (HWND) lParam; // handle of control
|
||
|
|
||
|
if (wNotifyCode == BN_CLICKED)
|
||
|
{
|
||
|
if (wID == IDOK)
|
||
|
This->OnOK();
|
||
|
else if (wID == IDCANCEL)
|
||
|
This->OnCancel();
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_CTLCOLOREDIT:
|
||
|
case WM_CTLCOLORSTATIC:
|
||
|
{
|
||
|
LRESULT l = DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||
|
HDC hdcEdit = (HDC) wParam; // handle of display context
|
||
|
HWND hwndEdit = (HWND) lParam; // handle of static control
|
||
|
HBRUSH hbr = This->OnCtlColorEdit(hdcEdit, hwndEdit);
|
||
|
if (hbr)
|
||
|
return (BOOL)hbr;
|
||
|
return l;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void Exec
|
||
|
(
|
||
|
LPCWSTR wsz
|
||
|
)
|
||
|
{
|
||
|
CHAR sz[MAX_PATH];
|
||
|
WideCharToMultiByte(CP_ACP,0,wsz,-1,sz,MAX_PATH,NULL,NULL);
|
||
|
|
||
|
HCURSOR hcursPrev = ::SetCursor(LoadCursor(NULL,IDC_WAIT));
|
||
|
|
||
|
//
|
||
|
// Attempt to find the hyperlinking library. It will always be
|
||
|
// present in IE3, but on NT sans IE3, it will not be
|
||
|
//
|
||
|
HMODULE urlmonHandle = (HMODULE)LoadLibrary( TEXT("urlmon.dll") );
|
||
|
|
||
|
if (NULL == urlmonHandle)
|
||
|
{
|
||
|
//
|
||
|
// The hyperlink module is unavailable, go to fallback plan
|
||
|
//
|
||
|
/*
|
||
|
* This works in test cases, but causes deadlock problems when used from withing
|
||
|
* the Internet Explorer itself. The dialog box is up (that is, IE is in a modal
|
||
|
* dialog loop) and in comes this DDE request...).
|
||
|
*/
|
||
|
ShellExecute(
|
||
|
NULL, // handle to parent window
|
||
|
"open", // pointer to string that specifies operation to perform
|
||
|
sz, // pointer to filename or folder name string
|
||
|
NULL, // pointer to string that specifies executable-file parameters
|
||
|
NULL, // pointer to string that specifies default directory
|
||
|
SW_SHOWNORMAL // whether file is shown when opened
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// The hyperlink module is there. Use it
|
||
|
//
|
||
|
if (SUCCEEDED(CoInitialize(NULL))) // Init OLE if no one else has
|
||
|
{
|
||
|
//
|
||
|
// Voodoo magic.
|
||
|
//
|
||
|
// Due to some goo about threading, 16-32 interop, and the beauty
|
||
|
// of the win95 architecture and its interaction with RPC, COM needs
|
||
|
// a chance to chew on a couple of messages before it can properly
|
||
|
// CoUninitialize after CoInitialize'ing. Sometimes it will fault,
|
||
|
// sometimes not if you don't give it that chance.
|
||
|
//
|
||
|
// Nat Brown
|
||
|
//
|
||
|
MSG msg;
|
||
|
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); // peek but not remove
|
||
|
|
||
|
typedef VOID (WINAPI *PFNHlinkSimpleNavigateToString)(
|
||
|
/* [in] */ LPCWSTR szTarget, // required - target document - null if local jump w/in doc
|
||
|
/* [in] */ LPCWSTR szLocation, // optional, for navigation into middle of a doc
|
||
|
/* [in] */ LPCWSTR szTargetFrameName,// optional, for targeting frame-sets
|
||
|
/* [in] */ IUnknown *pUnk, // required - we'll search this for other necessary interfaces
|
||
|
/* [in] */ IBindCtx *pbc, // optional. caller may register an IBSC in this
|
||
|
/* [in] */ IBindStatusCallback *,
|
||
|
/* [in] */ DWORD grfHLNF, // flags
|
||
|
/* [in] */ DWORD dwReserved // for future use, must be NULL
|
||
|
);
|
||
|
|
||
|
PFNHlinkSimpleNavigateToString procAddr;
|
||
|
|
||
|
procAddr = (PFNHlinkSimpleNavigateToString)GetProcAddress(urlmonHandle, TEXT("HlinkSimpleNavigateToString"));
|
||
|
|
||
|
if (procAddr) // let's not crash if something's screwy
|
||
|
{
|
||
|
(*procAddr)(
|
||
|
wsz, // target
|
||
|
NULL, // location
|
||
|
NULL, // target frame name
|
||
|
NULL, // punk
|
||
|
NULL, // bind context
|
||
|
NULL, // bind status callback
|
||
|
0, // grfHLNF
|
||
|
0 // reserved
|
||
|
);
|
||
|
}
|
||
|
/*
|
||
|
//
|
||
|
// For Beta1, we'll just assume that the application that must handle the link
|
||
|
// is in fact the Internet Explorer, so we manually launch another instance,
|
||
|
// and programmatically have it open the referenced URL.
|
||
|
//
|
||
|
// For RTM, we need to actually service this using the to-be-fixed hyperlink
|
||
|
// design, which will (according to SatonA) soon have an architected solution
|
||
|
// to the problem.
|
||
|
//
|
||
|
//
|
||
|
// Create an instance of the Internet Explorer
|
||
|
//
|
||
|
IInternetExplorer* pExplorer;
|
||
|
HRESULT hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_SERVER,
|
||
|
IID_IInternetExplorer, (LPVOID*)&pExplorer);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
//
|
||
|
// Convert the URL string to a BSTR
|
||
|
//
|
||
|
BSTR bstr = SysAllocString(wsz);
|
||
|
if (bstr)
|
||
|
{
|
||
|
//
|
||
|
// Ask the explorer to open the link
|
||
|
//
|
||
|
VARIANT v;
|
||
|
VariantInit(&v);
|
||
|
hr = pExplorer->Navigate(bstr, &v, &v, &v, &v, &v);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
//
|
||
|
// Explorer successfully opened it; show it
|
||
|
//
|
||
|
pExplorer->put_Visible(-1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Explorer couldn't open it (like for txt files)
|
||
|
// In future, do something else!
|
||
|
//
|
||
|
}
|
||
|
|
||
|
SysFreeString(bstr);
|
||
|
}
|
||
|
|
||
|
pExplorer->Release();
|
||
|
}
|
||
|
|
||
|
*/
|
||
|
|
||
|
CoUninitialize();
|
||
|
}
|
||
|
FreeLibrary ( urlmonHandle );
|
||
|
}
|
||
|
SetCursor(hcursPrev);
|
||
|
}
|
||
|
|
||
|
/////
|
||
|
|
||
|
void ExecLink
|
||
|
(
|
||
|
CERT_LINK& link
|
||
|
)
|
||
|
{
|
||
|
switch (link.tag)
|
||
|
{
|
||
|
case CERT_LINK_TYPE_URL:
|
||
|
Exec(link.wszUrl);
|
||
|
break;
|
||
|
case CERT_LINK_TYPE_FILE:
|
||
|
Exec(link.wszFile);
|
||
|
break;
|
||
|
case CERT_LINK_TYPE_MONIKER:
|
||
|
// REVIEW: ignore for now
|
||
|
case CERT_LINK_TYPE_NONE:
|
||
|
/* do nothing */;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// A hook callback class that adds the cert_link as appropriate
|
||
|
//
|
||
|
|
||
|
// EXTERN_C const GUID CDECL IID_IRunOrNotHook = IID_IRunOrNotHook_Data;
|
||
|
|
||
|
class CClickHook : public IRunOrNotHook {
|
||
|
public:
|
||
|
CClickHook();
|
||
|
STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj);
|
||
|
STDMETHOD_(ULONG,AddRef)(THIS);
|
||
|
STDMETHOD_(ULONG,Release)(THIS);
|
||
|
STDMETHOD(OnLinkClick)(THIS_ DWORD rrn, CERT_LINK*); // should this click dismiss the dialog?
|
||
|
STDMETHOD(GetToolTipText)(DWORD rrn, CERT_LINK* plinkIn, LPOLESTR* pwsz);
|
||
|
|
||
|
ULONG m_refs;
|
||
|
};
|
||
|
|
||
|
////
|
||
|
|
||
|
CClickHook::CClickHook()
|
||
|
{
|
||
|
m_refs = 1; // nb: starting ref cnt of one
|
||
|
}
|
||
|
|
||
|
////
|
||
|
|
||
|
ULONG CClickHook::AddRef()
|
||
|
{
|
||
|
return ++m_refs;
|
||
|
}
|
||
|
|
||
|
////
|
||
|
|
||
|
ULONG CClickHook::Release()
|
||
|
{
|
||
|
ULONG refs = --m_refs;
|
||
|
if (refs == 0)
|
||
|
{
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
return refs;
|
||
|
}
|
||
|
|
||
|
////
|
||
|
|
||
|
HRESULT CClickHook::QueryInterface
|
||
|
(
|
||
|
REFIID iid,
|
||
|
LPVOID* ppv
|
||
|
)
|
||
|
{
|
||
|
*ppv = NULL;
|
||
|
while (TRUE)
|
||
|
{
|
||
|
if (iid == IID_IUnknown || iid == IID_IRunOrNotHook)
|
||
|
{
|
||
|
*ppv = (LPVOID)((IRunOrNotHook*)this);
|
||
|
break;
|
||
|
}
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
((IUnknown*)*ppv)->AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
////
|
||
|
|
||
|
HRESULT CClickHook::OnLinkClick
|
||
|
//
|
||
|
// User clicked on a link. Service the click, and answer
|
||
|
// whether the dialog should be dismissed or not
|
||
|
//
|
||
|
(
|
||
|
DWORD rrn,
|
||
|
CERT_LINK* plink
|
||
|
)
|
||
|
{
|
||
|
if (rrn==RRN_CLICKED_PROGRAMINFO || rrn==RRN_CLICKED_AGENCYINFO)
|
||
|
{
|
||
|
ExecLink(*plink);
|
||
|
return S_FALSE; // don't dismiss
|
||
|
}
|
||
|
return S_OK; // dismiss dialog
|
||
|
}
|
||
|
|
||
|
HRESULT CClickHook::GetToolTipText
|
||
|
//
|
||
|
// Get the tool tip text associated with the given link
|
||
|
//
|
||
|
(
|
||
|
DWORD rrn,
|
||
|
CERT_LINK* plink,
|
||
|
LPOLESTR* pwsz
|
||
|
)
|
||
|
{
|
||
|
*pwsz = NULL;
|
||
|
switch (plink->tag)
|
||
|
{
|
||
|
case CERT_LINK_TYPE_URL:
|
||
|
*pwsz = CopyTaskMem(plink->wszUrl);
|
||
|
break;
|
||
|
case CERT_LINK_TYPE_FILE:
|
||
|
*pwsz = CopyTaskMem(plink->wszFile);
|
||
|
break;
|
||
|
case CERT_LINK_TYPE_MONIKER: // REVIEW: ignore for now
|
||
|
case CERT_LINK_TYPE_NONE:
|
||
|
/* do nothing */;
|
||
|
*pwsz = NULL;
|
||
|
}
|
||
|
|
||
|
return *pwsz ? S_OK : E_FAIL;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
BOOL UserOverride
|
||
|
(
|
||
|
HWND hwnd, // window to be modal to
|
||
|
LPCWSTR wszTitle, // dialog title to use; may be NULL.
|
||
|
LPCWSTR wszFileName, // file name in question (more correctly: display name)
|
||
|
ISignerInfo * pSigner, // access to the signer information
|
||
|
ICertificateStore* pStore, // access to our certificate store
|
||
|
BOOL fValid, // whether the cert chain processing is valid
|
||
|
HRESULT hrInvalid, // if not valid, then this tells why
|
||
|
BOOL fTestingOnly, // whether it was valid for testing purposes only
|
||
|
BOOL fTrustTesting, // whether we are to enable the ability to trust the testing root
|
||
|
BOOL fCommercial, // commercial or individual publisher
|
||
|
IX509* p509Publisher, // the cert of the publisher
|
||
|
IX509* p509Agency, // the cert of the agency
|
||
|
IPersonalTrustDB* pTrustDB // the trust database
|
||
|
) {
|
||
|
fValid = fValid && pSigner && pStore;
|
||
|
|
||
|
//
|
||
|
// Instantiate a hook so that we can launch the hyperlinks (if
|
||
|
// the user clicks on them) w/o dismissing the dialog
|
||
|
//
|
||
|
CClickHook* phook = new CClickHook();
|
||
|
if (!phook)
|
||
|
{
|
||
|
fValid = FALSE;
|
||
|
hrInvalid = E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Dig out the default dialog title if we aren't given
|
||
|
// something better to use by our caller
|
||
|
//
|
||
|
if (!wszTitle)
|
||
|
{
|
||
|
CHAR sz[40];
|
||
|
::LoadStringA(hinst, IDS_DEFAULTAPPNAME, (LPSTR)sz, 40);
|
||
|
int cch = lstrlen(sz)+1;
|
||
|
wszTitle = (LPCWSTR)_alloca(cch * sizeof(WCHAR));
|
||
|
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)sz, -1, (LPWSTR)wszTitle, cch);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Should we or should we not include those little check boxes
|
||
|
// on the dialog that control personal trust?
|
||
|
//
|
||
|
BOOL fUseChecks = p509Publisher && p509Agency && pTrustDB;
|
||
|
|
||
|
//
|
||
|
// Put up the silly dialog
|
||
|
//
|
||
|
RRNOUT rro;
|
||
|
CERT_LINK link;
|
||
|
BOOL fResult = FALSE;
|
||
|
if (GetInfoAndDoDialog(hwnd,
|
||
|
pSigner,
|
||
|
pStore,
|
||
|
wszTitle,
|
||
|
wszFileName, // use as default program name
|
||
|
RUNORNOT_SEAL_ALWAYS,
|
||
|
FALSE, // endorsements
|
||
|
fValid,
|
||
|
hrInvalid,
|
||
|
fTestingOnly,
|
||
|
fCommercial,
|
||
|
fUseChecks,
|
||
|
phook, // call back hook for dismissal
|
||
|
&rro,
|
||
|
&link))
|
||
|
{
|
||
|
//
|
||
|
// We only take an explict 'yes' as trusted. An explicit 'no'
|
||
|
// is, of course, not trusted. The other clickable things leave
|
||
|
// the dialog up and running.
|
||
|
//
|
||
|
fResult = (rro.rrn == RRN_YES);
|
||
|
|
||
|
//
|
||
|
// Update the personal trust database if appropriate
|
||
|
//
|
||
|
if (rro.fWildPublisher)
|
||
|
{
|
||
|
pTrustDB->AddTrustCert(p509Publisher, 0, FALSE);
|
||
|
}
|
||
|
if (rro.fWildAgency)
|
||
|
{
|
||
|
pTrustDB->AddTrustCert(p509Agency, 1, FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
phook->Release();
|
||
|
|
||
|
return fResult;
|
||
|
|
||
|
}
|
||
|
|
||
|
/////
|
||
|
|
||
|
void EnsureOnScreen(HWND hwnd)
|
||
|
//
|
||
|
// Ensure the window is on the screen
|
||
|
//
|
||
|
{
|
||
|
RECT rcScreen, rcWindow;
|
||
|
if (SystemParametersInfo(SPI_GETWORKAREA, 0, &rcScreen, 0)
|
||
|
&& GetWindowRect(hwnd, &rcWindow))
|
||
|
{
|
||
|
int dx = 0;
|
||
|
int dy = 0;
|
||
|
|
||
|
if (rcWindow.top < rcScreen.top)
|
||
|
dy = rcScreen.top - rcWindow.top; // move down
|
||
|
else if (rcWindow.bottom > rcScreen.bottom)
|
||
|
dy = rcScreen.bottom - rcWindow.bottom; // move up
|
||
|
|
||
|
if (rcWindow.left < rcScreen.left)
|
||
|
dx = rcScreen.left - rcWindow.left; // move right
|
||
|
else if (rcWindow.right > rcScreen.right)
|
||
|
dx = rcScreen.right - rcWindow.right; // move left
|
||
|
|
||
|
if (dx || dy)
|
||
|
{
|
||
|
SetWindowPos(hwnd,
|
||
|
NULL,
|
||
|
rcWindow.left+dx,
|
||
|
rcWindow.top+dy,
|
||
|
0,0,
|
||
|
SWP_NOSIZE | SWP_NOZORDER
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|