679 lines
17 KiB
C++
679 lines
17 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1997 - 1999
|
|
//
|
|
// File: firstpin.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
|
|
#include "firstpin.h"
|
|
#include "folder.h"
|
|
#include "idlhelp.h"
|
|
#include "msgbox.h"
|
|
#include "cscst.h"
|
|
#include "syncmgr.h"
|
|
#include "strings.h"
|
|
//
|
|
// Base class for all "first pin" wizard pages.
|
|
// Contains the single dialog proc used for all pages. Specialization
|
|
// for individual pages is achieved through deriviation and implementing
|
|
// virtual functions.
|
|
//
|
|
class CWizardPage
|
|
{
|
|
public:
|
|
enum { WM_WIZARDFINISHED = (WM_USER + 1) };
|
|
|
|
CWizardPage(HINSTANCE hInstance,
|
|
UINT idDlgTemplate,
|
|
UINT idsHdrTitle,
|
|
UINT idsHdrSubtitle,
|
|
DWORD dwPgFlags,
|
|
DWORD dwBtnFlags);
|
|
|
|
virtual ~CWizardPage(void);
|
|
|
|
UINT GetDlgTemplate(void) const
|
|
{ return m_idDlgTemplate; }
|
|
UINT GetHeaderTitle(void) const
|
|
{ return m_idsHdrTitle; }
|
|
UINT GetHeaderSubtitle(void) const
|
|
{ return m_idsHdrSubtitle; }
|
|
DWORD GetPageFlags(void) const
|
|
{ return m_dwPgFlags; }
|
|
DWORD GetBtnFlags(void) const
|
|
{ return m_dwBtnFlags; }
|
|
DLGPROC GetDlgProc(void) const
|
|
{ return DlgProc; }
|
|
|
|
virtual BOOL OnInitDialog(WPARAM wParam, LPARAM lParam)
|
|
{ return TRUE; }
|
|
|
|
virtual BOOL OnPSNSetActive(void);
|
|
|
|
virtual BOOL OnPSNWizFinish(void)
|
|
{ SetWindowLong(m_hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); return FALSE; }
|
|
|
|
virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam)
|
|
{ return FALSE; }
|
|
|
|
virtual BOOL OnWizardFinished(void) { return FALSE; }
|
|
|
|
protected:
|
|
HINSTANCE m_hInstance;
|
|
HWND m_hwndDlg;
|
|
HFONT m_hTitleFont; // Used only by cover and finish pages.
|
|
UINT m_cyTitleFontHt; // Title font height in pts.
|
|
|
|
int FontPtsToHt(HWND hwnd, int pts);
|
|
BOOL FormatTitleFont(UINT idcTitle);
|
|
|
|
private:
|
|
UINT m_idDlgTemplate; // Dialog resource template.
|
|
UINT m_idsHdrTitle; // String ID for pg header title.
|
|
UINT m_idsHdrSubtitle; // String ID for pg header subtitle.
|
|
DWORD m_dwBtnFlags; // PSB_WIZXXXXX flags.
|
|
DWORD m_dwPgFlags; // PSP_XXXX flags.
|
|
|
|
static INT_PTR CALLBACK DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
};
|
|
|
|
|
|
//
|
|
// Welcome page.
|
|
//
|
|
class CWizardPgWelcome : public CWizardPage
|
|
{
|
|
public:
|
|
CWizardPgWelcome(HINSTANCE hInstance,
|
|
UINT idDlgTemplate,
|
|
UINT idsHdrTitle,
|
|
UINT idsHdrSubtitle,
|
|
DWORD dwPgFlags,
|
|
DWORD dwBtnFlags
|
|
) : CWizardPage(hInstance,
|
|
idDlgTemplate,
|
|
idsHdrTitle,
|
|
idsHdrSubtitle,
|
|
dwPgFlags,
|
|
dwBtnFlags)
|
|
{ }
|
|
|
|
|
|
BOOL OnInitDialog(WPARAM wParam, LPARAM lParam);
|
|
};
|
|
|
|
//
|
|
// Pinning page.
|
|
//
|
|
class CWizardPgPin : public CWizardPage
|
|
{
|
|
public:
|
|
CWizardPgPin(HINSTANCE hInstance,
|
|
UINT idDlgTemplate,
|
|
UINT idsHdrTitle,
|
|
UINT idsHdrSubtitle,
|
|
DWORD dwPgFlags,
|
|
DWORD dwBtnFlags
|
|
) : CWizardPage(hInstance,
|
|
idDlgTemplate,
|
|
idsHdrTitle,
|
|
idsHdrSubtitle,
|
|
dwPgFlags,
|
|
dwBtnFlags) { }
|
|
|
|
BOOL OnInitDialog(WPARAM wParam, LPARAM lParam);
|
|
BOOL OnWizardFinished(void);
|
|
};
|
|
|
|
//
|
|
// Offline page.
|
|
//
|
|
class CWizardPgOffline : public CWizardPage
|
|
{
|
|
public:
|
|
CWizardPgOffline(HINSTANCE hInstance,
|
|
UINT idDlgTemplate,
|
|
UINT idsHdrTitle,
|
|
UINT idsHdrSubtitle,
|
|
DWORD dwPgFlags,
|
|
DWORD dwBtnFlags
|
|
) : CWizardPage(hInstance,
|
|
idDlgTemplate,
|
|
idsHdrTitle,
|
|
idsHdrSubtitle,
|
|
dwPgFlags,
|
|
dwBtnFlags) { }
|
|
|
|
BOOL OnInitDialog(WPARAM wParam, LPARAM lParam);
|
|
BOOL OnPSNWizFinish(void);
|
|
BOOL OnWizardFinished(void);
|
|
};
|
|
|
|
//
|
|
// Class encapsulating the functionality of the entire wizard.
|
|
// It contains member instances of each of the page types.
|
|
//
|
|
class CFirstPinWizard
|
|
{
|
|
public:
|
|
CFirstPinWizard(HINSTANCE hInstance, HWND hwndParent);
|
|
|
|
HRESULT Run(void);
|
|
|
|
private:
|
|
enum { PG_WELCOME,
|
|
PG_PIN,
|
|
PG_OFFLINE,
|
|
PG_NUMPAGES };
|
|
|
|
HINSTANCE m_hInstance;
|
|
HWND m_hwndParent;
|
|
CWizardPgWelcome m_PgWelcome;
|
|
CWizardPgPin m_PgPin;
|
|
CWizardPgOffline m_PgOffline;
|
|
CWizardPage *m_rgpWizPages[PG_NUMPAGES];
|
|
};
|
|
|
|
|
|
//
|
|
// CWizardPage members --------------------------------------------------------
|
|
//
|
|
CWizardPage::CWizardPage(
|
|
HINSTANCE hInstance,
|
|
UINT idDlgTemplate,
|
|
UINT idsHdrTitle,
|
|
UINT idsHdrSubtitle,
|
|
DWORD dwPgFlags,
|
|
DWORD dwBtnFlags
|
|
) : m_hInstance(hInstance),
|
|
m_idDlgTemplate(idDlgTemplate),
|
|
m_idsHdrTitle(idsHdrTitle),
|
|
m_idsHdrSubtitle(idsHdrSubtitle),
|
|
m_dwPgFlags(dwPgFlags),
|
|
m_dwBtnFlags(dwBtnFlags),
|
|
m_cyTitleFontHt(12),
|
|
m_hwndDlg(NULL),
|
|
m_hTitleFont(NULL)
|
|
{
|
|
//
|
|
// Get the title font height from a resource string. That way localizers can
|
|
// play with the font dimensions if necessary.
|
|
//
|
|
TCHAR szFontHt[20];
|
|
if (0 < LoadString(m_hInstance, IDS_FIRSTPIN_FONTHT_PTS, szFontHt, ARRAYSIZE(szFontHt)))
|
|
{
|
|
m_cyTitleFontHt = StrToInt(szFontHt);
|
|
}
|
|
}
|
|
|
|
|
|
CWizardPage::~CWizardPage(
|
|
void
|
|
)
|
|
{
|
|
if (NULL != m_hTitleFont)
|
|
{
|
|
DeleteObject(m_hTitleFont);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// PSN_SETACTIVE handler.
|
|
//
|
|
BOOL
|
|
CWizardPage::OnPSNSetActive(
|
|
void
|
|
)
|
|
{
|
|
PropSheet_SetWizButtons(GetParent(m_hwndDlg), m_dwBtnFlags);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Dialog proc used by all pages in this wizard.
|
|
//
|
|
INT_PTR CALLBACK
|
|
CWizardPage::DlgProc(
|
|
HWND hwnd,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
CWizardPage *pPage = (CWizardPage *)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
|
|
BOOL bResult = FALSE;
|
|
switch(uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
PROPSHEETPAGE *ppsp = (PROPSHEETPAGE *)lParam;
|
|
pPage = (CWizardPage *)ppsp->lParam;
|
|
|
|
TraceAssert(NULL != pPage);
|
|
SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pPage);
|
|
pPage->m_hwndDlg = hwnd;
|
|
bResult = pPage->OnInitDialog(wParam, lParam);
|
|
break;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
if (NULL != pPage)
|
|
bResult = pPage->OnCommand(wParam, lParam);
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
switch(((LPNMHDR)lParam)->code)
|
|
{
|
|
case PSN_SETACTIVE:
|
|
bResult = pPage->OnPSNSetActive();
|
|
break;
|
|
|
|
case PSN_WIZFINISH:
|
|
bResult = pPage->OnPSNWizFinish();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case PSM_QUERYSIBLINGS:
|
|
if (CWizardPage::WM_WIZARDFINISHED == wParam)
|
|
bResult = pPage->OnWizardFinished();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Helper function to convert a font point size to a height value
|
|
// used in a LOGFONT structure.
|
|
//
|
|
int
|
|
CWizardPage::FontPtsToHt(
|
|
HWND hwnd,
|
|
int pts
|
|
)
|
|
{
|
|
int ht = 10;
|
|
HDC hdc = GetDC(hwnd);
|
|
if (NULL != hdc)
|
|
{
|
|
ht = -MulDiv(pts, GetDeviceCaps(hdc, LOGPIXELSY), 72);
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
return ht;
|
|
}
|
|
|
|
|
|
//
|
|
// The title text on the cover and finish pages is enlarged and bold.
|
|
// This code modifies the text in the dialog accordingly.
|
|
// On return, m_hTitleFont contains the handle to the title font.
|
|
//
|
|
BOOL
|
|
CWizardPage::FormatTitleFont(
|
|
UINT idcTitle
|
|
)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
HWND hwndTitle = GetDlgItem(m_hwndDlg, idcTitle);
|
|
HFONT hFont = (HFONT)SendMessage(hwndTitle, WM_GETFONT, 0, 0);
|
|
if (NULL != hFont)
|
|
{
|
|
if (NULL == m_hTitleFont)
|
|
{
|
|
LOGFONT lf;
|
|
if (GetObject(hFont, sizeof(lf), &lf))
|
|
{
|
|
lf.lfHeight = FontPtsToHt(hwndTitle, m_cyTitleFontHt);
|
|
m_hTitleFont = CreateFontIndirect(&lf);
|
|
}
|
|
}
|
|
if (NULL != m_hTitleFont)
|
|
{
|
|
SendMessage(hwndTitle, WM_SETFONT, (WPARAM)m_hTitleFont, 0);
|
|
bResult = TRUE;
|
|
}
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
|
|
//
|
|
// CWizardPgWelcome members -----------------------------------------------------
|
|
//
|
|
//
|
|
// WM_INITDIALOG handler.
|
|
//
|
|
BOOL
|
|
CWizardPgWelcome::OnInitDialog(
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
FormatTitleFont(IDC_TXT_FIRSTPIN_WELCOME_TITLE);
|
|
return CWizardPage::OnInitDialog(wParam, lParam);
|
|
}
|
|
|
|
|
|
//
|
|
// CWizardPgPin members -------------------------------------------------------
|
|
//
|
|
//
|
|
// WM_INITDIALOG handler.
|
|
//
|
|
BOOL
|
|
CWizardPgPin::OnInitDialog(
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
HRESULT hr = IsRegisteredForSyncAtLogonAndLogoff();
|
|
CheckDlgButton(m_hwndDlg,
|
|
IDC_CBX_FIRSTPIN_AUTOSYNC,
|
|
S_OK == hr ? BST_CHECKED : BST_UNCHECKED);
|
|
|
|
return CWizardPage::OnInitDialog(wParam, lParam);
|
|
}
|
|
|
|
//
|
|
// PSN_WIZFINISH handler.
|
|
//
|
|
BOOL
|
|
CWizardPgPin::OnWizardFinished(
|
|
void
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
RegisterSyncMgrHandler(TRUE);
|
|
if (BST_CHECKED == IsDlgButtonChecked(m_hwndDlg, IDC_CBX_FIRSTPIN_AUTOSYNC))
|
|
{
|
|
const DWORD dwFlags = SYNCMGRREGISTERFLAG_CONNECT | SYNCMGRREGISTERFLAG_PENDINGDISCONNECT;
|
|
|
|
hr = RegisterForSyncAtLogonAndLogoff(dwFlags, dwFlags);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
SetSyncMgrInitialized();
|
|
}
|
|
else
|
|
{
|
|
CscMessageBox(m_hwndDlg,
|
|
MB_OK | MB_ICONERROR,
|
|
Win32Error(HRESULT_CODE(hr)),
|
|
m_hInstance,
|
|
IDS_ERR_REGSYNCATLOGONLOGOFF);
|
|
}
|
|
}
|
|
return CWizardPage::OnWizardFinished();
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// CWizardPgOffline members ---------------------------------------------------
|
|
//
|
|
//
|
|
// WM_INITDIALOG handler.
|
|
//
|
|
BOOL
|
|
CWizardPgOffline::OnInitDialog(
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
//
|
|
// If policy allows configuration of the reminders, check the "enable reminders"
|
|
// checkbox.
|
|
//
|
|
CConfig& config = CConfig::GetSingleton();
|
|
bool bNoConfigReminders;
|
|
bool bNoCacheViewer = config.NoCacheViewer();
|
|
|
|
config.NoReminders(&bNoConfigReminders);
|
|
|
|
CheckDlgButton(m_hwndDlg, IDC_CBX_REMINDERS, !bNoConfigReminders);
|
|
EnableWindow(GetDlgItem(m_hwndDlg, IDC_CBX_REMINDERS), !bNoConfigReminders);
|
|
|
|
CheckDlgButton(m_hwndDlg, IDC_CBX_FIRSTPIN_FLDRLNK, BST_UNCHECKED);
|
|
EnableWindow(GetDlgItem(m_hwndDlg, IDC_CBX_FIRSTPIN_FLDRLNK), !bNoCacheViewer);
|
|
|
|
return CWizardPage::OnInitDialog(wParam, lParam);
|
|
}
|
|
|
|
|
|
//
|
|
// PSN_WIZFINISH handler.
|
|
//
|
|
BOOL
|
|
CWizardPgOffline::OnPSNWizFinish(
|
|
void
|
|
)
|
|
{
|
|
//
|
|
// Send PSM_QUERYSIBLINGS to all of the pages with
|
|
// wParam set to WM_WIZARDFINISHED. This will trigger
|
|
// a call to the virtual function OnWizardFinished()
|
|
// allowing each page to respond to the successful completion
|
|
// of the wizard.
|
|
//
|
|
PropSheet_QuerySiblings(GetParent(m_hwndDlg),
|
|
CWizardPage::WM_WIZARDFINISHED,
|
|
0);
|
|
//
|
|
// Now handle for this page.
|
|
//
|
|
OnWizardFinished();
|
|
return CWizardPage::OnPSNWizFinish();
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// PSN_WIZFINISH handler.
|
|
//
|
|
BOOL
|
|
CWizardPgOffline::OnWizardFinished(
|
|
void
|
|
)
|
|
{
|
|
bool bEnableReminders = (BST_CHECKED == IsDlgButtonChecked(m_hwndDlg, IDC_CBX_REMINDERS));
|
|
DWORD dwValue;
|
|
DWORD dwErr;
|
|
|
|
dwValue = bEnableReminders ? 0 : 1;
|
|
|
|
dwErr = SHSetValue(HKEY_CURRENT_USER,
|
|
REGSTR_KEY_OFFLINEFILES,
|
|
REGSTR_VAL_NOREMINDERS,
|
|
REG_DWORD,
|
|
&dwValue,
|
|
sizeof(dwValue));
|
|
|
|
if (bEnableReminders)
|
|
{
|
|
PostToSystray(PWM_RESET_REMINDERTIMER, 0, 0);
|
|
}
|
|
|
|
if (BST_CHECKED == IsDlgButtonChecked(m_hwndDlg, IDC_CBX_FIRSTPIN_FLDRLNK))
|
|
{
|
|
COfflineFilesFolder::CreateLinkOnDesktop(m_hwndDlg);
|
|
}
|
|
|
|
return CWizardPage::OnWizardFinished();
|
|
}
|
|
|
|
|
|
//
|
|
// CFirstPinWizard members ----------------------------------------------------
|
|
//
|
|
CFirstPinWizard::CFirstPinWizard(
|
|
HINSTANCE hInstance,
|
|
HWND hwndParent
|
|
) : m_hInstance(hInstance),
|
|
m_hwndParent(hwndParent),
|
|
m_PgWelcome(hInstance,
|
|
IDD_FIRSTPIN_WELCOME,
|
|
0,
|
|
0,
|
|
PSP_DEFAULT,
|
|
PSWIZB_NEXT),
|
|
m_PgPin(hInstance,
|
|
IDD_FIRSTPIN_PIN,
|
|
0,
|
|
0,
|
|
PSP_DEFAULT,
|
|
PSWIZB_NEXT | PSWIZB_BACK),
|
|
m_PgOffline(hInstance,
|
|
IDD_FIRSTPIN_OFFLINE,
|
|
0,
|
|
0,
|
|
PSP_DEFAULT,
|
|
PSWIZB_FINISH | PSWIZB_BACK)
|
|
{
|
|
//
|
|
// Store pointers to each page in an array. Makes creating the
|
|
// prop sheet easier in Run().
|
|
//
|
|
m_rgpWizPages[0] = &m_PgWelcome;
|
|
m_rgpWizPages[1] = &m_PgPin;
|
|
m_rgpWizPages[2] = &m_PgOffline;
|
|
}
|
|
|
|
|
|
//
|
|
// Creates the wizard and runs it.
|
|
// The wizard runs modally.
|
|
//
|
|
// Returns:
|
|
//
|
|
// S_OK = User completed wizard and pressed "Finish".
|
|
// S_FALSE = User pressed "Cancel" in wizard.
|
|
// Other = Error creating wizard.
|
|
//
|
|
HRESULT
|
|
CFirstPinWizard::Run(
|
|
void
|
|
)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
PROPSHEETHEADER psh;
|
|
PROPSHEETPAGE psp;
|
|
HPROPSHEETPAGE rghpage[ARRAYSIZE(m_rgpWizPages)];
|
|
|
|
ZeroMemory(&psh, sizeof(psh));
|
|
ZeroMemory(rghpage, sizeof(rghpage));
|
|
|
|
psh.dwSize = sizeof(psh);
|
|
psh.dwFlags = PSH_WIZARD_LITE;
|
|
psh.hwndParent = m_hwndParent;
|
|
psh.hInstance = m_hInstance;
|
|
psh.nPages = ARRAYSIZE(rghpage);
|
|
psh.phpage = rghpage;
|
|
|
|
TCHAR szTitle[MAX_PATH];
|
|
TCHAR szSubTitle[MAX_PATH];
|
|
|
|
for (int i = 0; i < ARRAYSIZE(rghpage) && SUCCEEDED(hr); i++)
|
|
{
|
|
CWizardPage *pwp = m_rgpWizPages[i];
|
|
ZeroMemory(&psp, sizeof(psp));
|
|
|
|
psp.dwSize = sizeof(psp);
|
|
psp.dwFlags |= pwp->GetPageFlags();
|
|
psp.hInstance = m_hInstance;
|
|
psp.pszTemplate = MAKEINTRESOURCE(pwp->GetDlgTemplate());
|
|
psp.pfnDlgProc = pwp->GetDlgProc();
|
|
psp.lParam = (LPARAM)pwp;
|
|
|
|
rghpage[i] = CreatePropertySheetPage(&psp);
|
|
if (NULL == rghpage[i])
|
|
{
|
|
while(0 <= --i)
|
|
{
|
|
DestroyPropertySheetPage(rghpage[i]);
|
|
}
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
switch(PropertySheet(&psh))
|
|
{
|
|
case -1:
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
break;
|
|
|
|
case 0:
|
|
hr = S_FALSE; // User pressed "Cancel".
|
|
break;
|
|
|
|
case 1:
|
|
hr = S_OK; // User pressed "Finish".
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// This is the function you call when you want to run the wizard.
|
|
// It merely creates a wizard object and tells it to run.
|
|
// If the user finishes the wizard, it records this fact in the
|
|
// registry. Calling FirstPinWizardCompleted() will tell
|
|
// you later if the user has finished the wizard.
|
|
//
|
|
// Returns:
|
|
//
|
|
// S_OK = User completed wizard and pressed "Finish".
|
|
// S_FALSE = User cancelled out of wizard.
|
|
// Other = Error creating wizard.
|
|
//
|
|
HRESULT
|
|
ShowFirstPinWizard(
|
|
HWND hwndParent
|
|
)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
CFirstPinWizard Wizard(g_hInstance, hwndParent);
|
|
hr = Wizard.Run();
|
|
if (S_OK == hr)
|
|
{
|
|
//
|
|
// Only record "finished" in registry if user
|
|
// pressed "finish".
|
|
//
|
|
RegKey key(HKEY_CURRENT_USER, REGSTR_KEY_OFFLINEFILES);
|
|
if (SUCCEEDED(key.Open(KEY_SET_VALUE, true)))
|
|
{
|
|
key.SetValue(REGSTR_VAL_FIRSTPINWIZARDSHOWN, 1);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Has user seen the wizard and pressed "finish"?
|
|
//
|
|
bool
|
|
FirstPinWizardCompleted(
|
|
void
|
|
)
|
|
{
|
|
return CConfig::GetSingleton().FirstPinWizardShown();
|
|
}
|