windows-nt/Source/XPSP1/NT/ds/netapi/svcdlls/lls/ccfapi32/nlicdlg.cpp

1407 lines
33 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1994-95 Microsoft Corporation
Module Name:
nlicdlg.cpp
Abstract:
3.51-style license dialog implementation.
Author:
Don Ryan (donryan) 02-Feb-1995
Environment:
User Mode - Win32
Revision History:
Jeff Parham (jeffparh) 14-Dec-1995
Moved over from LLSMGR, added ability to purchase per server licenses,
added license removal functionality.
--*/
#include "stdafx.h"
#include "ccfapi.h"
#include "nlicdlg.h"
#include "pseatdlg.h"
#include "psrvdlg.h"
#include <htmlhelp.h>
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
BEGIN_MESSAGE_MAP(CNewLicenseDialog, CDialog)
//{{AFX_MSG_MAP(CNewLicenseDialog)
ON_NOTIFY(UDN_DELTAPOS, IDC_NEW_LICENSE_SPIN, OnDeltaPosSpin)
ON_EN_UPDATE(IDC_NEW_LICENSE_QUANTITY, OnUpdateQuantity)
ON_BN_CLICKED(IDC_MY_HELP, OnHelp)
ON_BN_CLICKED(IDC_PER_SEAT, OnPerSeat)
ON_BN_CLICKED(IDC_PER_SERVER, OnPerServer)
ON_MESSAGE( WM_HELP , OnHelpCmd )
ON_WM_DESTROY()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
CNewLicenseDialog::CNewLicenseDialog(CWnd* pParent /*=NULL*/)
: CDialog(CNewLicenseDialog::IDD, pParent)
/*++
Routine Description:
Constructor for dialog.
Arguments:
pParent - owner window.
Return Values:
None.
--*/
{
//{{AFX_DATA_INIT(CNewLicenseDialog)
m_strComment = _T("");
m_nLicenses = 0;
m_nLicensesMin = 0;
m_strProduct = _T("");
m_nLicenseMode = -1;
//}}AFX_DATA_INIT
m_strServerName = _T("");
m_strProduct = _T("");
m_dwEnterFlags = 0;
m_nLicenseMode = 0; // per seat
m_bAreCtrlsInitialized = FALSE;
m_hLls = NULL;
m_hEnterpriseLls = NULL;
}
CNewLicenseDialog::~CNewLicenseDialog()
{
if ( NULL != m_hLls )
{
LlsClose( m_hLls );
}
if ( NULL != m_hEnterpriseLls )
{
LlsClose( m_hEnterpriseLls );
}
}
void CNewLicenseDialog::DoDataExchange(CDataExchange* pDX)
/*++
Routine Description:
Called by framework to exchange dialog data.
Arguments:
pDX - data exchange object.
Return Values:
None.
--*/
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CNewLicenseDialog)
DDX_Control(pDX, IDC_NEW_LICENSE_COMMENT, m_comEdit);
DDX_Control(pDX, IDC_NEW_LICENSE_QUANTITY, m_licEdit);
DDX_Control(pDX, IDC_NEW_LICENSE_SPIN, m_spinCtrl);
DDX_Control(pDX, IDC_NEW_LICENSE_PRODUCT, m_productList);
DDX_Text(pDX, IDC_NEW_LICENSE_COMMENT, m_strComment);
DDX_Text(pDX, IDC_NEW_LICENSE_QUANTITY, m_nLicenses);
DDV_MinMaxLong(pDX, m_nLicenses, m_nLicensesMin, 999999);
DDX_CBString(pDX, IDC_NEW_LICENSE_PRODUCT, m_strProduct);
DDX_Radio(pDX, IDC_PER_SEAT, m_nLicenseMode);
//}}AFX_DATA_MAP
}
LRESULT CNewLicenseDialog::OnHelpCmd( WPARAM , LPARAM )
{
OnHelp( );
return 0;
}
void CNewLicenseDialog::InitCtrls()
/*++
Routine Description:
Initializes dialog controls.
Arguments:
None.
Return Values:
None.
--*/
{
m_licEdit.SetFocus();
m_licEdit.SetSel(0,-1);
m_licEdit.LimitText(6);
m_comEdit.LimitText(256);
m_spinCtrl.SetRange(0, UD_MAXVAL);
// if license mode set by application, don't let user change it
if ( m_dwEnterFlags & ( CCF_ENTER_FLAG_PER_SEAT_ONLY | CCF_ENTER_FLAG_PER_SERVER_ONLY ) )
{
if ( m_dwEnterFlags & CCF_ENTER_FLAG_PER_SEAT_ONLY )
{
m_nLicenseMode = 0;
OnPerSeat();
}
else
{
m_nLicenseMode = 1;
OnPerServer();
}
GetDlgItem( IDC_PER_SERVER )->EnableWindow( FALSE );
GetDlgItem( IDC_PER_SEAT )->EnableWindow( FALSE );
UpdateData( FALSE );
}
if( m_nLicenses == 0 )
{
GetDlgItem( IDOK )->EnableWindow( FALSE );
}
m_bAreCtrlsInitialized = TRUE;
}
void CNewLicenseDialog::AbortDialogIfNecessary()
/*++
Routine Description:
Displays status and aborts if connection lost.
Arguments:
None.
Return Values:
None.
--*/
{
theApp.DisplayLastError();
if ( theApp.IsConnectionDropped() )
{
AbortDialog(); // bail...
}
}
void CNewLicenseDialog::AbortDialog()
/*++
Routine Description:
Aborts dialog.
Arguments:
None.
Return Values:
None.
--*/
{
EndDialog(IDABORT);
}
BOOL CNewLicenseDialog::OnInitDialog()
/*++
Routine Description:
Message handler for WM_INITDIALOG.
Arguments:
None.
Return Values:
Returns false if focus set manually.
--*/
{
CDialog::OnInitDialog();
if (!m_bAreCtrlsInitialized)
{
InitCtrls();
if (!RefreshCtrls())
{
AbortDialogIfNecessary(); // display error...
}
}
return TRUE;
}
void CNewLicenseDialog::OnOK()
/*++
Routine Description:
Creates a new license for product.
Arguments:
None.
Return Values:
None.
--*/
{
if ( ConnectServer() )
{
if (!IsQuantityValid())
return;
if (m_strProduct.IsEmpty())
return;
if ( m_nLicenseMode )
{
CPerServerLicensingDialog psLicDlg;
psLicDlg.m_strProduct = m_strProduct;
psLicDlg.m_strLicenses.Format( TEXT( "%u" ), m_nLicenses );
if ( psLicDlg.DoModal() != IDOK )
return;
}
else
{
CPerSeatLicensingDialog psLicDlg;
psLicDlg.m_strProduct = m_strProduct;
if ( psLicDlg.DoModal() != IDOK )
return;
}
NTSTATUS NtStatus = AddLicense();
if ( STATUS_SUCCESS == NtStatus )
{
EndDialog(IDOK);
}
else if ( ( ERROR_CANCELLED != NtStatus ) && ( STATUS_CANCELLED != NtStatus ) )
{
AbortDialogIfNecessary(); // display error...
}
}
}
BOOL CNewLicenseDialog::RefreshCtrls()
/*++
Routine Description:
Refreshs list of products available.
Arguments:
None.
Return Values:
Returns true if controls refreshed.
--*/
{
int iProductInCB = CB_ERR;
BeginWaitCursor(); // hourglass...
if ( !m_strProduct.IsEmpty() )
{
iProductInCB = m_productList.AddString(m_strProduct);
}
else if ( ConnectServer() )
{
GetProductList();
}
m_productList.SetCurSel((iProductInCB == CB_ERR) ? 0 : iProductInCB);
EndWaitCursor(); // hourglass...
return TRUE;
}
void CNewLicenseDialog::OnDeltaPosSpin(NMHDR* pNMHDR, LRESULT* pResult)
/*++
Routine Description:
Notification handler for UDN_DELTAPOS.
Arguments:
pNMHDR - notification header.
pResult - return code.
Return Values:
None.
--*/
{
UpdateData(TRUE); // get data
m_nLicenses += ((NM_UPDOWN*)pNMHDR)->iDelta;
if (m_nLicenses < 0)
{
m_nLicenses = 0;
::MessageBeep(MB_OK);
}
else if (m_nLicenses > 999999)
{
m_nLicenses = 999999;
::MessageBeep(MB_OK);
}
UpdateData(FALSE); // set data
GetDlgItem( IDOK )->EnableWindow( m_nLicenses == 0 ? FALSE : TRUE );
*pResult = 1; // handle ourselves...
}
void CNewLicenseDialog::OnUpdateQuantity()
/*++
Routine Description:
Message handler for EN_UPDATE.
Arguments:
None.
Return Values:
None.
--*/
{
long nLicensesOld = m_nLicenses;
if (!IsQuantityValid())
{
m_nLicenses = nLicensesOld;
UpdateData(FALSE);
m_licEdit.SetFocus();
m_licEdit.SetSel(0,-1);
::MessageBeep(MB_OK);
}
GetDlgItem( IDOK )->EnableWindow( m_nLicenses == 0 ? FALSE : TRUE );
}
BOOL CNewLicenseDialog::IsQuantityValid()
/*++
Routine Description:
Wrapper around UpdateData(TRUE).
Arguments:
None.
Return Values:
VT_BOOL.
--*/
{
BOOL bIsValid;
m_nLicensesMin = 1; // raise minimum...
bIsValid = UpdateData(TRUE);
m_nLicensesMin = 0; // reset minimum...
return bIsValid;
}
BOOL CNewLicenseDialog::ConnectServer()
/*++
Routine Description:
Establish a connection to the license service on the target server.
Arguments:
None.
Return Values:
BOOL.
--*/
{
if ( NULL == m_hLls )
{
LPTSTR pszServerName;
if ( m_strServerName.IsEmpty() )
{
pszServerName = NULL;
}
else
{
pszServerName = m_strServerName.GetBuffer( 0 );
}
NTSTATUS nt = ConnectTo( FALSE, pszServerName, &m_hLls );
if ( NULL != pszServerName )
{
m_strServerName.ReleaseBuffer();
}
}
if ( NULL == m_hLls )
{
theApp.DisplayLastError();
EndDialog( IDABORT );
}
return ( NULL != m_hLls );
}
BOOL CNewLicenseDialog::ConnectEnterprise()
/*++
Routine Description:
Establish a connection to the license service on the enterprise server
of the target server.
Arguments:
None.
Return Values:
BOOL.
--*/
{
if ( NULL == m_hEnterpriseLls )
{
LPTSTR pszServerName;
if ( m_strServerName.IsEmpty() )
{
pszServerName = NULL;
}
else
{
pszServerName = m_strServerName.GetBuffer( 0 );
}
NTSTATUS nt = ConnectTo( !( m_dwEnterFlags & CCF_ENTER_FLAG_SERVER_IS_ES ), pszServerName, &m_hEnterpriseLls );
if ( NULL != pszServerName )
{
m_strServerName.ReleaseBuffer();
}
}
if ( NULL == m_hEnterpriseLls )
{
theApp.DisplayLastError();
// not being able to connect to the enterprise
// is not a fatal error
// EndDialog( IDABORT );
}
return ( NULL != m_hEnterpriseLls );
}
NTSTATUS CNewLicenseDialog::ConnectTo( BOOL bUseEnterprise, LPTSTR pszServerName, PLLS_HANDLE phLls )
/*++
Routine Description:
Establish a connection to the license service on the given server or that
on the given server's enterprise server.
Arguments:
bUseEnterprise (BOOL)
If TRUE, connect to the enterprise server of the target server, not to
the target server itself.
pszServerName (LPTSTR)
The target server. A NULL value indicates the local server.
phLls (PLLS_HANDLE)
On return, holds the handle to the standard LLS RPC.
Return Values:
STATUS_SUCCESS or NT status code.
--*/
{
NTSTATUS nt;
if ( !bUseEnterprise )
{
nt = ::LlsConnect( pszServerName, phLls );
}
else
{
PLLS_CONNECT_INFO_0 pConnect = NULL;
nt = ::LlsConnectEnterprise( pszServerName, phLls, 0, (LPBYTE *) &pConnect );
if ( STATUS_SUCCESS == nt )
{
::LlsFreeMemory( pConnect );
}
}
if ( STATUS_SUCCESS != nt )
{
*phLls = NULL;
}
theApp.SetLastLlsError( nt );
return nt;
}
void CNewLicenseDialog::GetProductList()
/*++
Routine Description:
Fill the product list box with the unsecure product names from the
target server.
Arguments:
None.
Return Values:
None.
--*/
{
if ( ConnectServer() )
{
// get list of products from license server, inserting into listbox
m_productList.ResetContent();
DWORD dwResumeHandle = 0;
DWORD dwTotalEntries;
DWORD dwEntriesRead;
NTSTATUS nt;
do
{
LPBYTE pReturnBuffer = NULL;
BOOL bListProduct;
nt = ::LlsProductEnum( m_hLls,
0,
&pReturnBuffer,
0x4000,
&dwEntriesRead,
&dwTotalEntries,
&dwResumeHandle );
theApp.SetLastLlsError( nt );
if ( ( STATUS_SUCCESS == nt ) || ( STATUS_MORE_ENTRIES == nt ) )
{
LLS_PRODUCT_INFO_0 * pProductInfo = (LLS_PRODUCT_INFO_0 *) pReturnBuffer;
for ( DWORD i=0; i < dwEntriesRead; i++ )
{
if ( !LlsCapabilityIsSupported( m_hLls, LLS_CAPABILITY_SECURE_CERTIFICATES ) )
{
// 3.51-level server; all products are unsecure, so add all
bListProduct = TRUE;
}
else
{
// only list this product if it's unsecure
BOOL bIsSecure;
bListProduct = ( STATUS_SUCCESS != ::LlsProductSecurityGet( m_hLls, pProductInfo[i].Product, &bIsSecure ) )
|| ( !bIsSecure );
}
if ( bListProduct )
{
m_productList.AddString( pProductInfo[i].Product );
}
::LlsFreeMemory( pProductInfo[i].Product );
}
::LlsFreeMemory( pProductInfo );
}
} while ( STATUS_MORE_ENTRIES == nt );
if ( STATUS_SUCCESS != nt )
{
// still connected?
AbortDialogIfNecessary();
}
// restore previous edit selection
UpdateData( FALSE );
}
}
NTSTATUS CNewLicenseDialog::AddLicense()
/*++
Routine Description:
Add the license described in the dialog.
Arguments:
None.
Return Values:
STATUS_SUCCESS
ERROR_CANCELLED
ERROR_NOT_ENOUGH_MEMORY
NT status code
Win error
--*/
{
NTSTATUS nt;
if ( !ConnectServer() )
{
nt = ERROR_CANCELLED;
// don't set last error
// (preserve that set by the failed connect attempt)
}
else
{
LPTSTR pszProductName = m_strProduct.GetBuffer(0);
LPTSTR pszServerName = m_strServerName.GetBuffer(0);
LPTSTR pszComment = m_strComment.GetBuffer(0);
if ( ( NULL == pszProductName ) || ( NULL == pszServerName ) || ( NULL == pszComment ) )
{
nt = ERROR_NOT_ENOUGH_MEMORY;
theApp.SetLastError( nt );
}
else
{
LLS_HANDLE hLls = m_hLls;
if ( ( 0 != m_nLicenseMode )
|| ( m_dwEnterFlags & CCF_ENTER_FLAG_SERVER_IS_ES ) )
{
// per server mode, or per seat installed on ES; target server correct
nt = STATUS_SUCCESS;
}
else
{
// per seat mode; make sure we're installing on the enterprise server
PLLS_CONNECT_INFO_0 pConnectInfo = NULL;
BeginWaitCursor();
nt = ::LlsEnterpriseServerFind( pszServerName, 0, (LPBYTE *) &pConnectInfo );
theApp.SetLastLlsError( nt );
EndWaitCursor();
if ( STATUS_SUCCESS == nt )
{
if ( lstrcmpi( pszServerName, pConnectInfo->EnterpriseServer ) )
{
// not the enterprise server; make sure that per seat
// licenses are being sent to the right place (i.e., the
// enterprise server)
int nResponse;
nResponse = AfxMessageBox( IDS_PER_SEAT_CHOSEN_SEND_TO_ENTERPRISE, MB_ICONINFORMATION | MB_OKCANCEL, 0 );
if ( IDOK == nResponse )
{
if ( !ConnectEnterprise() )
{
nt = ERROR_CANCELLED;
// don't set last error
// (preserve that set by the failed connect attempt)
}
else
{
hLls = m_hEnterpriseLls;
}
}
else
{
nt = ERROR_CANCELLED;
theApp.SetLastError( nt );
}
}
}
// free memory allocated for us by Lls
LlsFreeMemory( pConnectInfo );
}
if ( STATUS_SUCCESS == nt )
{
// we've determined the real target server
// get name of user entering the certificate
TCHAR szUserName[ 64 ];
DWORD cchUserName;
BOOL ok;
cchUserName = sizeof( szUserName ) / sizeof( *szUserName );
ok = GetUserName( szUserName, &cchUserName );
if ( !ok )
{
nt = GetLastError();
theApp.SetLastError( nt );
}
else
{
// enter certificate into system
if ( 0 == m_nLicenseMode )
{
// add 3.51 style per seat license
LLS_LICENSE_INFO_0 lic;
ZeroMemory( &lic, sizeof( lic ) );
lic.Product = pszProductName;
lic.Comment = pszComment;
lic.Admin = szUserName;
lic.Quantity = m_nLicenses;
lic.Date = 0;
BeginWaitCursor();
nt = ::LlsLicenseAdd( hLls, 0, (LPBYTE) &lic );
theApp.SetLastLlsError( nt );
EndWaitCursor();
}
else
{
// add 3.51 style per server license (blek)
HKEY hKeyLocalMachine;
nt = RegConnectRegistry( pszServerName, HKEY_LOCAL_MACHINE, &hKeyLocalMachine );
if ( ERROR_SUCCESS != nt )
{
theApp.SetLastError( nt );
}
else
{
HKEY hKeyLicenseInfo;
nt = RegOpenKeyEx( hKeyLocalMachine, TEXT( "SYSTEM\\CurrentControlSet\\Services\\LicenseInfo" ), 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_SET_VALUE, &hKeyLicenseInfo );
if ( ERROR_SUCCESS != nt )
{
theApp.SetLastError( nt );
}
else
{
BOOL bFoundKey = FALSE;
DWORD iSubKey = 0;
// okay, now we have to find the product corresponding to this display name (ickie)
do
{
TCHAR szKeyName[ 128 ];
DWORD cchKeyName = sizeof( szKeyName ) / sizeof( *szKeyName );
nt = RegEnumKeyEx( hKeyLicenseInfo, iSubKey++, szKeyName, &cchKeyName, NULL, NULL, NULL, NULL );
if ( ERROR_SUCCESS == nt )
{
HKEY hKeyProduct;
nt = RegOpenKeyEx( hKeyLicenseInfo, szKeyName, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hKeyProduct );
if ( ERROR_SUCCESS == nt )
{
DWORD dwType;
TCHAR szDisplayName[ 128 ];
DWORD cbDisplayName = sizeof( szDisplayName );
nt = RegQueryValueEx( hKeyProduct, TEXT( "DisplayName" ), NULL, &dwType, (LPBYTE) szDisplayName, &cbDisplayName );
if ( ( ERROR_SUCCESS == nt )
&& ( REG_SZ == dwType )
&& !lstrcmpi( szDisplayName, pszProductName ) )
{
// YES! we found the product key
// now add the concurrent licenses
bFoundKey = TRUE;
DWORD dwConcurrentLimit;
DWORD cbConcurrentLimit = sizeof( dwConcurrentLimit );
nt = RegQueryValueEx( hKeyProduct, TEXT( "ConcurrentLimit" ), NULL, &dwType, (LPBYTE) &dwConcurrentLimit, &cbConcurrentLimit );
if ( ( ERROR_FILE_NOT_FOUND == nt ) || ( ERROR_PATH_NOT_FOUND == nt ) )
{
// okay if the value doesn't exist
dwConcurrentLimit = 0;
nt = ERROR_SUCCESS;
}
if ( ERROR_SUCCESS == nt )
{
if ( (LONG)dwConcurrentLimit + (LONG)m_nLicenses > 0 )
{
dwConcurrentLimit += m_nLicenses;
nt = RegSetValueEx( hKeyProduct, TEXT( "ConcurrentLimit" ), 0, REG_DWORD, (LPBYTE) &dwConcurrentLimit, sizeof( dwConcurrentLimit ) );
}
}
}
RegCloseKey( hKeyProduct );
}
// even if an error occurred while trying to find the right product key,
// we should continue to search the rest
if ( !bFoundKey )
{
nt = ERROR_SUCCESS;
}
}
} while ( !bFoundKey && ( ERROR_SUCCESS == nt ) );
if ( ERROR_NO_MORE_ITEMS == nt )
{
// trying to install per server licenses for this box, but
// the application isn't installed locally
AfxMessageBox( IDS_PER_SERVER_APP_NOT_INSTALLED, MB_ICONSTOP | MB_OK, 0 );
nt = ERROR_CANCELLED;
}
else if ( ERROR_SUCCESS != nt )
{
theApp.SetLastError( nt );
}
RegCloseKey( hKeyLicenseInfo );
}
RegCloseKey( hKeyLocalMachine );
}
}
}
}
}
if ( NULL != pszProductName ) m_strProduct.ReleaseBuffer();
if ( NULL != pszServerName ) m_strServerName.ReleaseBuffer();
if ( NULL != pszComment ) m_strComment.ReleaseBuffer();
}
return nt;
}
void CNewLicenseDialog::OnHelp()
/*++
Routine Description:
Handler for help button click.
Arguments:
None.
Return Values:
None.
--*/
{
WinHelp( IDD, HELP_CONTEXT );
}
void CNewLicenseDialog::WinHelp(DWORD dwData, UINT nCmd)
/*++
Routine Description:
Call WinHelp for this dialog.
Arguments:
dwData (DWORD)
nCmd (UINT)
Return Values:
None.
--*/
{
::HtmlHelp(m_hWnd, L"liceconcepts.chm", HH_DISPLAY_TOPIC,0);
/*
BOOL ok = ::WinHelp( m_hWnd, theApp.GetHelpFileName(), nCmd, dwData );
ASSERT( ok );
*/
}
void CNewLicenseDialog::OnDestroy()
/*++
Routine Description:
Handler for WM_DESTROY.
Arguments:
None.
Return Values:
None.
--*/
{
::WinHelp( m_hWnd, theApp.GetHelpFileName(), HELP_QUIT, 0 );
CDialog::OnDestroy();
}
void CNewLicenseDialog::OnPerSeat()
/*++
Routine Description:
Handler for per seat radio button selection.
Arguments:
None.
Return Values:
None.
--*/
{
GetDlgItem( IDC_NEW_LICENSE_COMMENT )->EnableWindow( TRUE );
}
void CNewLicenseDialog::OnPerServer()
/*++
Routine Description:
Handler for per server radio button selection.
Arguments:
None.
Return Values:
None.
--*/
{
GetDlgItem( IDC_NEW_LICENSE_COMMENT )->EnableWindow( FALSE );
}
DWORD CNewLicenseDialog::CertificateEnter( LPCSTR pszServerName, LPCSTR pszProductName, LPCSTR pszVendor, DWORD dwFlags )
/*++
Routine Description:
Display a dialog allowing the user to enter a license certificate
into the system with no certificate (3.51-style).
Arguments:
pszServerName (LPCSTR)
Name of the server for which licenses are to be installed. Note that
this may not be the same as the server on which licenses are actually
installed, as, for example, per seat licenses are always installed on
the enterprise server. A NULL value indicates the local server.
pszProductName (LPCSTR)
Product for which licenses are to be installed. A NULL value indicates
that the user should be allowed to choose.
pszVendor (LPCSTR)
Name of the vendor of the product. This value should be NULL if
pszProductName is NULL, and should be non-NULL if pszProductName is
non-NULL.
dwFlags (DWORD)
A bitfield containing one or more of the following:
CCF_ENTER_FLAG_PER_SEAT_ONLY
Allow the user to enter only per seat licenses. Not valid in
combination with CCF_ENTER_FLAG_PER_SERVER_ONLY.
CCF_ENTER_FLAG_PER_SERVER_ONLY
Allow the user to enter only per server licenses. Not valid in
combination with CCF_ENTER_FLAG_PER_SEAT_ONLY.
Return Value:
ERROR_SUCCESS (A certificate was successfully entered into the system.)
ERROR_CANCELLED (The user cancelled without installing a certificate.)
other Win error
--*/
{
DWORD dwError;
m_strServerName = pszServerName ? pszServerName : "";
m_strProduct = pszProductName ? pszProductName : "";
// pszVendor is not used
m_dwEnterFlags = dwFlags;
if ( IDOK == DoModal() )
{
dwError = ERROR_SUCCESS;
}
else
{
dwError = ERROR_CANCELLED;
}
return dwError;
}
DWORD CNewLicenseDialog::CertificateRemove( LPCSTR pszServerName, DWORD dwFlags, PLLS_LICENSE_INFO_1 pLicenseInfo )
/*++
Routine Description:
Remove licenses previously installed via 3.51 or CertificateEnter().
Arguments:
pszServerName (LPCSTR)
Name of the server on which licenses are to be removed. A NULL value
indicates the local server.
dwFlags (DWORD)
Certificate removal options. As of this writing, no flags are
supported.
dwLicenseLevel (DWORD)
Level of the LLS_LICENSE_INFO_X structure pointed to by pvLicenseInfo.
pvLicenseInfo (LPVOID)
Points to a LLS_LICENSE_INFO_X (where X is determined by dwLicenseLevel)
describing the licenses to be removed.
Return Value:
ERROR_SUCCESS
Win error
--*/
{
DWORD dwError;
m_strServerName = pszServerName ? pszServerName : "";
m_strProduct = pLicenseInfo->Product;
if ( !ConnectServer() )
{
dwError = theApp.GetLastError();
// error message already displayed
}
else
{
if ( LLS_LICENSE_MODE_ALLOW_PER_SERVER & pLicenseInfo->AllowedModes )
{
// remove per server licenses
HKEY hKeyLocalMachine;
LPTSTR pszUniServerName = m_strServerName.GetBuffer(0);
if ( NULL == pszUniServerName )
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
dwError = RegConnectRegistry( pszUniServerName, HKEY_LOCAL_MACHINE, &hKeyLocalMachine );
if ( ERROR_SUCCESS != dwError )
{
theApp.SetLastError( dwError );
}
else
{
HKEY hKeyLicenseInfo;
dwError = RegOpenKeyEx( hKeyLocalMachine, TEXT( "SYSTEM\\CurrentControlSet\\Services\\LicenseInfo" ), 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_SET_VALUE, &hKeyLicenseInfo );
if ( ERROR_SUCCESS != dwError )
{
theApp.SetLastError( dwError );
}
else
{
BOOL bFoundKey = FALSE;
DWORD iSubKey = 0;
// okay, now we have to find the product corresponding to this display name (ickie)
do
{
TCHAR szKeyName[ 128 ];
DWORD cchKeyName = sizeof( szKeyName ) / sizeof( *szKeyName );
dwError = RegEnumKeyEx( hKeyLicenseInfo, iSubKey++, szKeyName, &cchKeyName, NULL, NULL, NULL, NULL );
if ( ERROR_SUCCESS == dwError )
{
HKEY hKeyProduct;
dwError = RegOpenKeyEx( hKeyLicenseInfo, szKeyName, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hKeyProduct );
if ( ERROR_SUCCESS == dwError )
{
DWORD dwType;
TCHAR szDisplayName[ 128 ];
DWORD cbDisplayName = sizeof( szDisplayName );
dwError = RegQueryValueEx( hKeyProduct, TEXT( "DisplayName" ), NULL, &dwType, (LPBYTE) szDisplayName, &cbDisplayName );
if ( ( ERROR_SUCCESS == dwError )
&& ( REG_SZ == dwType )
&& !lstrcmpi( szDisplayName, m_strProduct ) )
{
// YES! we found the product key
// now subtract the concurrent licenses
bFoundKey = TRUE;
DWORD dwConcurrentLimit;
DWORD cbConcurrentLimit = sizeof( dwConcurrentLimit );
dwError = RegQueryValueEx( hKeyProduct, TEXT( "ConcurrentLimit" ), NULL, &dwType, (LPBYTE) &dwConcurrentLimit, &cbConcurrentLimit );
if ( ( ERROR_SUCCESS == dwError ) && ( REG_DWORD == dwType ) )
{
if ( (LONG)dwConcurrentLimit + (LONG)m_nLicenses > 0 )
{
if ( pLicenseInfo->Quantity > (LONG)dwConcurrentLimit )
{
dwConcurrentLimit = 0;
}
else
{
dwConcurrentLimit -= pLicenseInfo->Quantity;
}
dwError = RegSetValueEx( hKeyProduct, TEXT( "ConcurrentLimit" ), 0, REG_DWORD, (LPBYTE) &dwConcurrentLimit, sizeof( dwConcurrentLimit ) );
}
}
}
RegCloseKey( hKeyProduct );
}
// even if an error occurred while trying to find the right product key,
// we should continue to search the rest
if ( !bFoundKey )
{
dwError = ERROR_SUCCESS;
}
}
} while ( !bFoundKey && ( ERROR_SUCCESS == dwError ) );
if ( ERROR_SUCCESS != dwError )
{
theApp.SetLastError( dwError );
}
RegCloseKey( hKeyLicenseInfo );
}
RegCloseKey( hKeyLocalMachine );
}
}
}
else
{
// remove per seat licenses
CString strComment;
strComment.LoadString( IDS_NO_REMOVE_COMMENT );
LPTSTR pszUniProductName = m_strProduct.GetBuffer(0);
LPTSTR pszUniComment = strComment.GetBuffer(0);
if ( ( NULL == pszUniProductName ) || ( NULL == pszUniComment ) )
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
TCHAR szUserName[ 256 ];
DWORD cchUserName = sizeof( szUserName ) / sizeof( *szUserName );
BOOL ok = GetUserName( szUserName, &cchUserName );
if ( !ok )
{
dwError = GetLastError();
}
else
{
NTSTATUS nt;
LLS_LICENSE_INFO_0 lic;
ZeroMemory( &lic, sizeof( lic ) );
lic.Product = pszUniProductName;
lic.Comment = pszUniComment;
lic.Admin = szUserName;
lic.Quantity = -pLicenseInfo->Quantity;
lic.Date = 0;
BeginWaitCursor();
nt = ::LlsLicenseAdd( m_hLls, 0, (LPBYTE) &lic );
theApp.SetLastLlsError( nt );
EndWaitCursor();
dwError = (DWORD) nt;
}
}
if ( NULL != pszUniProductName ) m_strProduct.ReleaseBuffer();
if ( NULL != pszUniComment ) strComment.ReleaseBuffer();
}
if ( ( ERROR_SUCCESS != dwError ) && ( ERROR_CANCELLED != dwError ) )
{
theApp.SetLastError( dwError );
theApp.DisplayLastError();
}
}
return dwError;
}