Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1413 lines
34 KiB

  1. /*++
  2. Copyright (c) 1994-95 Microsoft Corporation
  3. Module Name:
  4. nlicdlg.cpp
  5. Abstract:
  6. 3.51-style license dialog implementation.
  7. Author:
  8. Don Ryan (donryan) 02-Feb-1995
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. Jeff Parham (jeffparh) 14-Dec-1995
  13. Moved over from LLSMGR, added ability to purchase per server licenses,
  14. added license removal functionality.
  15. --*/
  16. #include "stdafx.h"
  17. #include "ccfapi.h"
  18. #include "nlicdlg.h"
  19. #include "pseatdlg.h"
  20. #include "psrvdlg.h"
  21. #include <htmlhelp.h>
  22. #ifdef _DEBUG
  23. #undef THIS_FILE
  24. static char BASED_CODE THIS_FILE[] = __FILE__;
  25. #endif
  26. BEGIN_MESSAGE_MAP(CNewLicenseDialog, CDialog)
  27. //{{AFX_MSG_MAP(CNewLicenseDialog)
  28. ON_NOTIFY(UDN_DELTAPOS, IDC_NEW_LICENSE_SPIN, OnDeltaPosSpin)
  29. ON_EN_UPDATE(IDC_NEW_LICENSE_QUANTITY, OnUpdateQuantity)
  30. ON_BN_CLICKED(IDC_MY_HELP, OnHelp)
  31. ON_BN_CLICKED(IDC_PER_SEAT, OnPerSeat)
  32. ON_BN_CLICKED(IDC_PER_SERVER, OnPerServer)
  33. ON_MESSAGE( WM_HELP , OnHelpCmd )
  34. ON_WM_DESTROY()
  35. //}}AFX_MSG_MAP
  36. END_MESSAGE_MAP()
  37. CNewLicenseDialog::CNewLicenseDialog(CWnd* pParent /*=NULL*/)
  38. : CDialog(CNewLicenseDialog::IDD, pParent)
  39. /*++
  40. Routine Description:
  41. Constructor for dialog.
  42. Arguments:
  43. pParent - owner window.
  44. Return Values:
  45. None.
  46. --*/
  47. {
  48. //{{AFX_DATA_INIT(CNewLicenseDialog)
  49. m_strComment = _T("");
  50. m_nLicenses = 0;
  51. m_nLicensesMin = 0;
  52. m_strProduct = _T("");
  53. m_nLicenseMode = -1;
  54. //}}AFX_DATA_INIT
  55. m_strServerName = _T("");
  56. m_strProduct = _T("");
  57. m_dwEnterFlags = 0;
  58. m_nLicenseMode = 0; // per seat
  59. m_bAreCtrlsInitialized = FALSE;
  60. m_hLls = NULL;
  61. m_hEnterpriseLls = NULL;
  62. }
  63. CNewLicenseDialog::~CNewLicenseDialog()
  64. {
  65. if ( NULL != m_hLls )
  66. {
  67. LlsClose( m_hLls );
  68. }
  69. if ( NULL != m_hEnterpriseLls )
  70. {
  71. LlsClose( m_hEnterpriseLls );
  72. }
  73. }
  74. void CNewLicenseDialog::DoDataExchange(CDataExchange* pDX)
  75. /*++
  76. Routine Description:
  77. Called by framework to exchange dialog data.
  78. Arguments:
  79. pDX - data exchange object.
  80. Return Values:
  81. None.
  82. --*/
  83. {
  84. CDialog::DoDataExchange(pDX);
  85. //{{AFX_DATA_MAP(CNewLicenseDialog)
  86. DDX_Control(pDX, IDC_NEW_LICENSE_COMMENT, m_comEdit);
  87. DDX_Control(pDX, IDC_NEW_LICENSE_QUANTITY, m_licEdit);
  88. DDX_Control(pDX, IDC_NEW_LICENSE_SPIN, m_spinCtrl);
  89. DDX_Control(pDX, IDC_NEW_LICENSE_PRODUCT, m_productList);
  90. DDX_Text(pDX, IDC_NEW_LICENSE_COMMENT, m_strComment);
  91. DDX_Text(pDX, IDC_NEW_LICENSE_QUANTITY, m_nLicenses);
  92. DDV_MinMaxLong(pDX, m_nLicenses, m_nLicensesMin, 999999);
  93. DDX_CBString(pDX, IDC_NEW_LICENSE_PRODUCT, m_strProduct);
  94. DDX_Radio(pDX, IDC_PER_SEAT, m_nLicenseMode);
  95. //}}AFX_DATA_MAP
  96. }
  97. LRESULT CNewLicenseDialog::OnHelpCmd( WPARAM , LPARAM )
  98. {
  99. OnHelp( );
  100. return 0;
  101. }
  102. void CNewLicenseDialog::InitCtrls()
  103. /*++
  104. Routine Description:
  105. Initializes dialog controls.
  106. Arguments:
  107. None.
  108. Return Values:
  109. None.
  110. --*/
  111. {
  112. m_licEdit.SetFocus();
  113. m_licEdit.SetSel(0,-1);
  114. m_licEdit.LimitText(6);
  115. m_comEdit.LimitText(256);
  116. m_spinCtrl.SetRange(0, UD_MAXVAL);
  117. // if license mode set by application, don't let user change it
  118. if ( m_dwEnterFlags & ( CCF_ENTER_FLAG_PER_SEAT_ONLY | CCF_ENTER_FLAG_PER_SERVER_ONLY ) )
  119. {
  120. if ( m_dwEnterFlags & CCF_ENTER_FLAG_PER_SEAT_ONLY )
  121. {
  122. m_nLicenseMode = 0;
  123. OnPerSeat();
  124. }
  125. else
  126. {
  127. m_nLicenseMode = 1;
  128. OnPerServer();
  129. }
  130. GetDlgItem( IDC_PER_SERVER )->EnableWindow( FALSE );
  131. GetDlgItem( IDC_PER_SEAT )->EnableWindow( FALSE );
  132. UpdateData( FALSE );
  133. }
  134. if( m_nLicenses == 0 )
  135. {
  136. GetDlgItem( IDOK )->EnableWindow( FALSE );
  137. }
  138. m_bAreCtrlsInitialized = TRUE;
  139. }
  140. void CNewLicenseDialog::AbortDialogIfNecessary()
  141. /*++
  142. Routine Description:
  143. Displays status and aborts if connection lost.
  144. Arguments:
  145. None.
  146. Return Values:
  147. None.
  148. --*/
  149. {
  150. theApp.DisplayLastError();
  151. if ( theApp.IsConnectionDropped() )
  152. {
  153. AbortDialog(); // bail...
  154. }
  155. }
  156. void CNewLicenseDialog::AbortDialog()
  157. /*++
  158. Routine Description:
  159. Aborts dialog.
  160. Arguments:
  161. None.
  162. Return Values:
  163. None.
  164. --*/
  165. {
  166. EndDialog(IDABORT);
  167. }
  168. BOOL CNewLicenseDialog::OnInitDialog()
  169. /*++
  170. Routine Description:
  171. Message handler for WM_INITDIALOG.
  172. Arguments:
  173. None.
  174. Return Values:
  175. Returns false if focus set manually.
  176. --*/
  177. {
  178. CDialog::OnInitDialog();
  179. if (!m_bAreCtrlsInitialized)
  180. {
  181. InitCtrls();
  182. if (!RefreshCtrls())
  183. {
  184. AbortDialogIfNecessary(); // display error...
  185. }
  186. }
  187. return TRUE;
  188. }
  189. void CNewLicenseDialog::OnOK()
  190. /*++
  191. Routine Description:
  192. Creates a new license for product.
  193. Arguments:
  194. None.
  195. Return Values:
  196. None.
  197. --*/
  198. {
  199. if ( ConnectServer() )
  200. {
  201. if (!IsQuantityValid())
  202. return;
  203. if (m_strProduct.IsEmpty())
  204. return;
  205. if ( m_nLicenseMode )
  206. {
  207. CPerServerLicensingDialog psLicDlg;
  208. psLicDlg.m_strProduct = m_strProduct;
  209. psLicDlg.m_strLicenses.Format( TEXT( "%u" ), m_nLicenses );
  210. if ( psLicDlg.DoModal() != IDOK )
  211. return;
  212. }
  213. else
  214. {
  215. CPerSeatLicensingDialog psLicDlg;
  216. psLicDlg.m_strProduct = m_strProduct;
  217. if ( psLicDlg.DoModal() != IDOK )
  218. return;
  219. }
  220. NTSTATUS NtStatus = AddLicense();
  221. if ( STATUS_SUCCESS == NtStatus )
  222. {
  223. EndDialog(IDOK);
  224. }
  225. else if ( ( ERROR_CANCELLED != NtStatus ) && ( STATUS_CANCELLED != NtStatus ) )
  226. {
  227. AbortDialogIfNecessary(); // display error...
  228. }
  229. }
  230. }
  231. BOOL CNewLicenseDialog::RefreshCtrls()
  232. /*++
  233. Routine Description:
  234. Refreshs list of products available.
  235. Arguments:
  236. None.
  237. Return Values:
  238. Returns true if controls refreshed.
  239. --*/
  240. {
  241. int iProductInCB = CB_ERR;
  242. BeginWaitCursor(); // hourglass...
  243. if ( !m_strProduct.IsEmpty() )
  244. {
  245. iProductInCB = m_productList.AddString(m_strProduct);
  246. }
  247. else if ( ConnectServer() )
  248. {
  249. GetProductList();
  250. }
  251. m_productList.SetCurSel((iProductInCB == CB_ERR) ? 0 : iProductInCB);
  252. EndWaitCursor(); // hourglass...
  253. return TRUE;
  254. }
  255. void CNewLicenseDialog::OnDeltaPosSpin(NMHDR* pNMHDR, LRESULT* pResult)
  256. /*++
  257. Routine Description:
  258. Notification handler for UDN_DELTAPOS.
  259. Arguments:
  260. pNMHDR - notification header.
  261. pResult - return code.
  262. Return Values:
  263. None.
  264. --*/
  265. {
  266. UpdateData(TRUE); // get data
  267. m_nLicenses += ((NM_UPDOWN*)pNMHDR)->iDelta;
  268. if (m_nLicenses < 0)
  269. {
  270. m_nLicenses = 0;
  271. ::MessageBeep(MB_OK);
  272. }
  273. else if (m_nLicenses > 999999)
  274. {
  275. m_nLicenses = 999999;
  276. ::MessageBeep(MB_OK);
  277. }
  278. UpdateData(FALSE); // set data
  279. GetDlgItem( IDOK )->EnableWindow( m_nLicenses == 0 ? FALSE : TRUE );
  280. *pResult = 1; // handle ourselves...
  281. }
  282. void CNewLicenseDialog::OnUpdateQuantity()
  283. /*++
  284. Routine Description:
  285. Message handler for EN_UPDATE.
  286. Arguments:
  287. None.
  288. Return Values:
  289. None.
  290. --*/
  291. {
  292. long nLicensesOld = m_nLicenses;
  293. if (!IsQuantityValid())
  294. {
  295. m_nLicenses = nLicensesOld;
  296. UpdateData(FALSE);
  297. m_licEdit.SetFocus();
  298. m_licEdit.SetSel(0,-1);
  299. ::MessageBeep(MB_OK);
  300. }
  301. GetDlgItem( IDOK )->EnableWindow( m_nLicenses == 0 ? FALSE : TRUE );
  302. }
  303. BOOL CNewLicenseDialog::IsQuantityValid()
  304. /*++
  305. Routine Description:
  306. Wrapper around UpdateData(TRUE).
  307. Arguments:
  308. None.
  309. Return Values:
  310. VT_BOOL.
  311. --*/
  312. {
  313. BOOL bIsValid;
  314. m_nLicensesMin = 1; // raise minimum...
  315. bIsValid = UpdateData(TRUE);
  316. m_nLicensesMin = 0; // reset minimum...
  317. return bIsValid;
  318. }
  319. BOOL CNewLicenseDialog::ConnectServer()
  320. /*++
  321. Routine Description:
  322. Establish a connection to the license service on the target server.
  323. Arguments:
  324. None.
  325. Return Values:
  326. BOOL.
  327. --*/
  328. {
  329. if ( NULL == m_hLls )
  330. {
  331. LPTSTR pszServerName;
  332. if ( m_strServerName.IsEmpty() )
  333. {
  334. pszServerName = NULL;
  335. }
  336. else
  337. {
  338. pszServerName = m_strServerName.GetBuffer( 0 );
  339. }
  340. NTSTATUS nt = ConnectTo( FALSE, pszServerName, &m_hLls );
  341. if ( NULL != pszServerName )
  342. {
  343. m_strServerName.ReleaseBuffer();
  344. }
  345. }
  346. if ( NULL == m_hLls )
  347. {
  348. theApp.DisplayLastError();
  349. EndDialog( IDABORT );
  350. }
  351. return ( NULL != m_hLls );
  352. }
  353. BOOL CNewLicenseDialog::ConnectEnterprise()
  354. /*++
  355. Routine Description:
  356. Establish a connection to the license service on the enterprise server
  357. of the target server.
  358. Arguments:
  359. None.
  360. Return Values:
  361. BOOL.
  362. --*/
  363. {
  364. if ( NULL == m_hEnterpriseLls )
  365. {
  366. LPTSTR pszServerName;
  367. if ( m_strServerName.IsEmpty() )
  368. {
  369. pszServerName = NULL;
  370. }
  371. else
  372. {
  373. pszServerName = m_strServerName.GetBuffer( 0 );
  374. }
  375. NTSTATUS nt = ConnectTo( !( m_dwEnterFlags & CCF_ENTER_FLAG_SERVER_IS_ES ), pszServerName, &m_hEnterpriseLls );
  376. if ( NULL != pszServerName )
  377. {
  378. m_strServerName.ReleaseBuffer();
  379. }
  380. }
  381. if ( NULL == m_hEnterpriseLls )
  382. {
  383. theApp.DisplayLastError();
  384. // not being able to connect to the enterprise
  385. // is not a fatal error
  386. // EndDialog( IDABORT );
  387. }
  388. return ( NULL != m_hEnterpriseLls );
  389. }
  390. NTSTATUS CNewLicenseDialog::ConnectTo( BOOL bUseEnterprise, LPTSTR pszServerName, PLLS_HANDLE phLls )
  391. /*++
  392. Routine Description:
  393. Establish a connection to the license service on the given server or that
  394. on the given server's enterprise server.
  395. Arguments:
  396. bUseEnterprise (BOOL)
  397. If TRUE, connect to the enterprise server of the target server, not to
  398. the target server itself.
  399. pszServerName (LPTSTR)
  400. The target server. A NULL value indicates the local server.
  401. phLls (PLLS_HANDLE)
  402. On return, holds the handle to the standard LLS RPC.
  403. Return Values:
  404. STATUS_SUCCESS or NT status code.
  405. --*/
  406. {
  407. NTSTATUS nt;
  408. if ( !bUseEnterprise )
  409. {
  410. nt = ::LlsConnect( pszServerName, phLls );
  411. }
  412. else
  413. {
  414. PLLS_CONNECT_INFO_0 pConnect = NULL;
  415. nt = ::LlsConnectEnterprise( pszServerName, phLls, 0, (LPBYTE *) &pConnect );
  416. if ( STATUS_SUCCESS == nt )
  417. {
  418. ::LlsFreeMemory( pConnect );
  419. }
  420. }
  421. if ( STATUS_SUCCESS != nt )
  422. {
  423. *phLls = NULL;
  424. }
  425. theApp.SetLastLlsError( nt );
  426. return nt;
  427. }
  428. void CNewLicenseDialog::GetProductList()
  429. /*++
  430. Routine Description:
  431. Fill the product list box with the unsecure product names from the
  432. target server.
  433. Arguments:
  434. None.
  435. Return Values:
  436. None.
  437. --*/
  438. {
  439. if ( ConnectServer() )
  440. {
  441. // get list of products from license server, inserting into listbox
  442. m_productList.ResetContent();
  443. DWORD dwResumeHandle = 0;
  444. DWORD dwTotalEntries;
  445. DWORD dwEntriesRead;
  446. NTSTATUS nt;
  447. do
  448. {
  449. LPBYTE pReturnBuffer = NULL;
  450. BOOL bListProduct;
  451. nt = ::LlsProductEnum( m_hLls,
  452. 0,
  453. &pReturnBuffer,
  454. 0x4000,
  455. &dwEntriesRead,
  456. &dwTotalEntries,
  457. &dwResumeHandle );
  458. theApp.SetLastLlsError( nt );
  459. if ( ( STATUS_SUCCESS == nt ) || ( STATUS_MORE_ENTRIES == nt ) )
  460. {
  461. LLS_PRODUCT_INFO_0 * pProductInfo = (LLS_PRODUCT_INFO_0 *) pReturnBuffer;
  462. for ( DWORD i=0; i < dwEntriesRead; i++ )
  463. {
  464. if ( !LlsCapabilityIsSupported( m_hLls, LLS_CAPABILITY_SECURE_CERTIFICATES ) )
  465. {
  466. // 3.51-level server; all products are unsecure, so add all
  467. bListProduct = TRUE;
  468. }
  469. else
  470. {
  471. // only list this product if it's unsecure
  472. BOOL bIsSecure;
  473. bListProduct = ( STATUS_SUCCESS != ::LlsProductSecurityGet( m_hLls, pProductInfo[i].Product, &bIsSecure ) )
  474. || ( !bIsSecure );
  475. }
  476. if ( bListProduct )
  477. {
  478. m_productList.AddString( pProductInfo[i].Product );
  479. }
  480. ::LlsFreeMemory( pProductInfo[i].Product );
  481. }
  482. ::LlsFreeMemory( pProductInfo );
  483. }
  484. } while ( STATUS_MORE_ENTRIES == nt );
  485. if ( STATUS_SUCCESS != nt )
  486. {
  487. // still connected?
  488. AbortDialogIfNecessary();
  489. }
  490. // restore previous edit selection
  491. UpdateData( FALSE );
  492. }
  493. }
  494. NTSTATUS CNewLicenseDialog::AddLicense()
  495. /*++
  496. Routine Description:
  497. Add the license described in the dialog.
  498. Arguments:
  499. None.
  500. Return Values:
  501. STATUS_SUCCESS
  502. ERROR_CANCELLED
  503. ERROR_NOT_ENOUGH_MEMORY
  504. NT status code
  505. Win error
  506. --*/
  507. {
  508. NTSTATUS nt;
  509. if ( !ConnectServer() )
  510. {
  511. nt = ERROR_CANCELLED;
  512. // don't set last error
  513. // (preserve that set by the failed connect attempt)
  514. }
  515. else
  516. {
  517. LPTSTR pszProductName = m_strProduct.GetBuffer(0);
  518. LPTSTR pszServerName = m_strServerName.GetBuffer(0);
  519. LPTSTR pszComment = m_strComment.GetBuffer(0);
  520. if ( ( NULL == pszProductName ) || ( NULL == pszServerName ) || ( NULL == pszComment ) )
  521. {
  522. nt = ERROR_NOT_ENOUGH_MEMORY;
  523. theApp.SetLastError( nt );
  524. }
  525. else
  526. {
  527. LLS_HANDLE hLls = m_hLls;
  528. if ( ( 0 != m_nLicenseMode )
  529. || ( m_dwEnterFlags & CCF_ENTER_FLAG_SERVER_IS_ES ) )
  530. {
  531. // per server mode, or per seat installed on ES; target server correct
  532. nt = STATUS_SUCCESS;
  533. }
  534. else
  535. {
  536. // per seat mode; make sure we're installing on the enterprise server
  537. PLLS_CONNECT_INFO_0 pConnectInfo = NULL;
  538. BeginWaitCursor();
  539. nt = ::LlsEnterpriseServerFind( pszServerName, 0, (LPBYTE *) &pConnectInfo );
  540. theApp.SetLastLlsError( nt );
  541. EndWaitCursor();
  542. if ( STATUS_SUCCESS == nt )
  543. {
  544. if ( lstrcmpi( pszServerName, pConnectInfo->EnterpriseServer ) )
  545. {
  546. // not the enterprise server; make sure that per seat
  547. // licenses are being sent to the right place (i.e., the
  548. // enterprise server)
  549. int nResponse;
  550. nResponse = AfxMessageBox( IDS_PER_SEAT_CHOSEN_SEND_TO_ENTERPRISE, MB_ICONINFORMATION | MB_OKCANCEL, 0 );
  551. if ( IDOK == nResponse )
  552. {
  553. if ( !ConnectEnterprise() )
  554. {
  555. nt = ERROR_CANCELLED;
  556. // don't set last error
  557. // (preserve that set by the failed connect attempt)
  558. }
  559. else
  560. {
  561. hLls = m_hEnterpriseLls;
  562. }
  563. }
  564. else
  565. {
  566. nt = ERROR_CANCELLED;
  567. theApp.SetLastError( nt );
  568. }
  569. }
  570. }
  571. // free memory allocated for us by Lls
  572. LlsFreeMemory( pConnectInfo );
  573. }
  574. if ( STATUS_SUCCESS == nt )
  575. {
  576. // we've determined the real target server
  577. // get name of user entering the certificate
  578. TCHAR szUserName[ 64 ];
  579. DWORD cchUserName;
  580. BOOL ok;
  581. cchUserName = sizeof( szUserName ) / sizeof( *szUserName );
  582. ok = GetUserName( szUserName, &cchUserName );
  583. if ( !ok )
  584. {
  585. nt = GetLastError();
  586. theApp.SetLastError( nt );
  587. }
  588. else
  589. {
  590. // enter certificate into system
  591. if ( 0 == m_nLicenseMode )
  592. {
  593. // add 3.51 style per seat license
  594. LLS_LICENSE_INFO_0 lic;
  595. ZeroMemory( &lic, sizeof( lic ) );
  596. lic.Product = pszProductName;
  597. lic.Comment = pszComment;
  598. lic.Admin = szUserName;
  599. lic.Quantity = m_nLicenses;
  600. lic.Date = 0;
  601. BeginWaitCursor();
  602. nt = ::LlsLicenseAdd( hLls, 0, (LPBYTE) &lic );
  603. theApp.SetLastLlsError( nt );
  604. EndWaitCursor();
  605. }
  606. else
  607. {
  608. // add 3.51 style per server license (blek)
  609. HKEY hKeyLocalMachine;
  610. nt = RegConnectRegistry( pszServerName, HKEY_LOCAL_MACHINE, &hKeyLocalMachine );
  611. if ( ERROR_SUCCESS != nt )
  612. {
  613. theApp.SetLastError( nt );
  614. }
  615. else
  616. {
  617. HKEY hKeyLicenseInfo;
  618. nt = RegOpenKeyEx( hKeyLocalMachine, TEXT( "SYSTEM\\CurrentControlSet\\Services\\LicenseInfo" ), 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_SET_VALUE, &hKeyLicenseInfo );
  619. if ( ERROR_SUCCESS != nt )
  620. {
  621. theApp.SetLastError( nt );
  622. }
  623. else
  624. {
  625. BOOL bFoundKey = FALSE;
  626. DWORD iSubKey = 0;
  627. // okay, now we have to find the product corresponding to this display name (ickie)
  628. do
  629. {
  630. TCHAR szKeyName[ 128 ];
  631. DWORD cchKeyName = sizeof( szKeyName ) / sizeof( *szKeyName );
  632. nt = RegEnumKeyEx( hKeyLicenseInfo, iSubKey++, szKeyName, &cchKeyName, NULL, NULL, NULL, NULL );
  633. if ( ERROR_SUCCESS == nt )
  634. {
  635. HKEY hKeyProduct;
  636. nt = RegOpenKeyEx( hKeyLicenseInfo, szKeyName, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hKeyProduct );
  637. if ( ERROR_SUCCESS == nt )
  638. {
  639. DWORD dwType;
  640. TCHAR szDisplayName[ 128 ];
  641. DWORD cbDisplayName = sizeof( szDisplayName );
  642. nt = RegQueryValueEx( hKeyProduct, TEXT( "DisplayName" ), NULL, &dwType, (LPBYTE) szDisplayName, &cbDisplayName );
  643. if ( ( ERROR_SUCCESS == nt )
  644. && ( REG_SZ == dwType )
  645. && !lstrcmpi( szDisplayName, pszProductName ) )
  646. {
  647. // YES! we found the product key
  648. // now add the concurrent licenses
  649. bFoundKey = TRUE;
  650. DWORD dwConcurrentLimit;
  651. DWORD cbConcurrentLimit = sizeof( dwConcurrentLimit );
  652. nt = RegQueryValueEx( hKeyProduct, TEXT( "ConcurrentLimit" ), NULL, &dwType, (LPBYTE) &dwConcurrentLimit, &cbConcurrentLimit );
  653. if ( ( ERROR_FILE_NOT_FOUND == nt ) || ( ERROR_PATH_NOT_FOUND == nt ) )
  654. {
  655. // okay if the value doesn't exist
  656. dwConcurrentLimit = 0;
  657. nt = ERROR_SUCCESS;
  658. }
  659. if ( ERROR_SUCCESS == nt )
  660. {
  661. if ( (LONG)dwConcurrentLimit + (LONG)m_nLicenses > 0 )
  662. {
  663. dwConcurrentLimit += m_nLicenses;
  664. nt = RegSetValueEx( hKeyProduct, TEXT( "ConcurrentLimit" ), 0, REG_DWORD, (LPBYTE) &dwConcurrentLimit, sizeof( dwConcurrentLimit ) );
  665. }
  666. }
  667. }
  668. RegCloseKey( hKeyProduct );
  669. }
  670. // even if an error occurred while trying to find the right product key,
  671. // we should continue to search the rest
  672. if ( !bFoundKey )
  673. {
  674. nt = ERROR_SUCCESS;
  675. }
  676. }
  677. } while ( !bFoundKey && ( ERROR_SUCCESS == nt ) );
  678. if ( ERROR_NO_MORE_ITEMS == nt )
  679. {
  680. // trying to install per server licenses for this box, but
  681. // the application isn't installed locally
  682. AfxMessageBox( IDS_PER_SERVER_APP_NOT_INSTALLED, MB_ICONSTOP | MB_OK, 0 );
  683. nt = ERROR_CANCELLED;
  684. }
  685. else if ( ERROR_SUCCESS != nt )
  686. {
  687. theApp.SetLastError( nt );
  688. }
  689. RegCloseKey( hKeyLicenseInfo );
  690. }
  691. RegCloseKey( hKeyLocalMachine );
  692. }
  693. }
  694. }
  695. }
  696. }
  697. if ( NULL != pszProductName ) m_strProduct.ReleaseBuffer();
  698. if ( NULL != pszServerName ) m_strServerName.ReleaseBuffer();
  699. if ( NULL != pszComment ) m_strComment.ReleaseBuffer();
  700. }
  701. return nt;
  702. }
  703. void CNewLicenseDialog::OnHelp()
  704. /*++
  705. Routine Description:
  706. Handler for help button click.
  707. Arguments:
  708. None.
  709. Return Values:
  710. None.
  711. --*/
  712. {
  713. WinHelp( IDD, HELP_CONTEXT );
  714. }
  715. void CNewLicenseDialog::WinHelp(DWORD dwData, UINT nCmd)
  716. /*++
  717. Routine Description:
  718. Call WinHelp for this dialog.
  719. Arguments:
  720. dwData (DWORD)
  721. nCmd (UINT)
  722. Return Values:
  723. None.
  724. --*/
  725. {
  726. HtmlHelp(m_hWnd, L"liceconcepts.chm", HH_DISPLAY_TOPIC, (DWORD_PTR)(L"LICE_dialog_box_Help2.htm"));
  727. UNREFERENCED_PARAMETER(nCmd);
  728. UNREFERENCED_PARAMETER(dwData);
  729. /*
  730. BOOL ok = ::WinHelp( m_hWnd, theApp.GetHelpFileName(), nCmd, dwData );
  731. ASSERT( ok );
  732. */
  733. }
  734. void CNewLicenseDialog::OnDestroy()
  735. /*++
  736. Routine Description:
  737. Handler for WM_DESTROY.
  738. Arguments:
  739. None.
  740. Return Values:
  741. None.
  742. --*/
  743. {
  744. ::WinHelp( m_hWnd, theApp.GetHelpFileName(), HELP_QUIT, 0 );
  745. CDialog::OnDestroy();
  746. }
  747. void CNewLicenseDialog::OnPerSeat()
  748. /*++
  749. Routine Description:
  750. Handler for per seat radio button selection.
  751. Arguments:
  752. None.
  753. Return Values:
  754. None.
  755. --*/
  756. {
  757. GetDlgItem( IDC_NEW_LICENSE_COMMENT )->EnableWindow( TRUE );
  758. }
  759. void CNewLicenseDialog::OnPerServer()
  760. /*++
  761. Routine Description:
  762. Handler for per server radio button selection.
  763. Arguments:
  764. None.
  765. Return Values:
  766. None.
  767. --*/
  768. {
  769. GetDlgItem( IDC_NEW_LICENSE_COMMENT )->EnableWindow( FALSE );
  770. }
  771. DWORD CNewLicenseDialog::CertificateEnter( LPCSTR pszServerName, LPCSTR pszProductName, LPCSTR pszVendor, DWORD dwFlags )
  772. /*++
  773. Routine Description:
  774. Display a dialog allowing the user to enter a license certificate
  775. into the system with no certificate (3.51-style).
  776. Arguments:
  777. pszServerName (LPCSTR)
  778. Name of the server for which licenses are to be installed. Note that
  779. this may not be the same as the server on which licenses are actually
  780. installed, as, for example, per seat licenses are always installed on
  781. the enterprise server. A NULL value indicates the local server.
  782. pszProductName (LPCSTR)
  783. Product for which licenses are to be installed. A NULL value indicates
  784. that the user should be allowed to choose.
  785. pszVendor (LPCSTR)
  786. Name of the vendor of the product. This value should be NULL if
  787. pszProductName is NULL, and should be non-NULL if pszProductName is
  788. non-NULL.
  789. dwFlags (DWORD)
  790. A bitfield containing one or more of the following:
  791. CCF_ENTER_FLAG_PER_SEAT_ONLY
  792. Allow the user to enter only per seat licenses. Not valid in
  793. combination with CCF_ENTER_FLAG_PER_SERVER_ONLY.
  794. CCF_ENTER_FLAG_PER_SERVER_ONLY
  795. Allow the user to enter only per server licenses. Not valid in
  796. combination with CCF_ENTER_FLAG_PER_SEAT_ONLY.
  797. Return Value:
  798. ERROR_SUCCESS (A certificate was successfully entered into the system.)
  799. ERROR_CANCELLED (The user cancelled without installing a certificate.)
  800. other Win error
  801. --*/
  802. {
  803. DWORD dwError;
  804. UNREFERENCED_PARAMETER(pszVendor);
  805. m_strServerName = pszServerName ? pszServerName : "";
  806. m_strProduct = pszProductName ? pszProductName : "";
  807. // pszVendor is not used
  808. m_dwEnterFlags = dwFlags;
  809. if ( IDOK == DoModal() )
  810. {
  811. dwError = ERROR_SUCCESS;
  812. }
  813. else
  814. {
  815. dwError = ERROR_CANCELLED;
  816. }
  817. return dwError;
  818. }
  819. DWORD CNewLicenseDialog::CertificateRemove( LPCSTR pszServerName, DWORD dwFlags, PLLS_LICENSE_INFO_1 pLicenseInfo )
  820. /*++
  821. Routine Description:
  822. Remove licenses previously installed via 3.51 or CertificateEnter().
  823. Arguments:
  824. pszServerName (LPCSTR)
  825. Name of the server on which licenses are to be removed. A NULL value
  826. indicates the local server.
  827. dwFlags (DWORD)
  828. Certificate removal options. As of this writing, no flags are
  829. supported.
  830. dwLicenseLevel (DWORD)
  831. Level of the LLS_LICENSE_INFO_X structure pointed to by pvLicenseInfo.
  832. pvLicenseInfo (LPVOID)
  833. Points to a LLS_LICENSE_INFO_X (where X is determined by dwLicenseLevel)
  834. describing the licenses to be removed.
  835. Return Value:
  836. ERROR_SUCCESS
  837. Win error
  838. --*/
  839. {
  840. DWORD dwError;
  841. UNREFERENCED_PARAMETER(dwFlags);
  842. m_strServerName = pszServerName ? pszServerName : "";
  843. ASSERT(NULL != pLicenseInfo);
  844. m_strProduct = pLicenseInfo->Product;
  845. if ( !ConnectServer() )
  846. {
  847. dwError = theApp.GetLastError();
  848. // error message already displayed
  849. }
  850. else
  851. {
  852. if ( LLS_LICENSE_MODE_ALLOW_PER_SERVER & pLicenseInfo->AllowedModes )
  853. {
  854. // remove per server licenses
  855. HKEY hKeyLocalMachine;
  856. LPTSTR pszUniServerName = m_strServerName.GetBuffer(0);
  857. if ( NULL == pszUniServerName )
  858. {
  859. dwError = ERROR_NOT_ENOUGH_MEMORY;
  860. }
  861. else
  862. {
  863. dwError = RegConnectRegistry( pszUniServerName, HKEY_LOCAL_MACHINE, &hKeyLocalMachine );
  864. if ( ERROR_SUCCESS != dwError )
  865. {
  866. theApp.SetLastError( dwError );
  867. }
  868. else
  869. {
  870. HKEY hKeyLicenseInfo;
  871. dwError = RegOpenKeyEx( hKeyLocalMachine, TEXT( "SYSTEM\\CurrentControlSet\\Services\\LicenseInfo" ), 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_SET_VALUE, &hKeyLicenseInfo );
  872. if ( ERROR_SUCCESS != dwError )
  873. {
  874. theApp.SetLastError( dwError );
  875. }
  876. else
  877. {
  878. BOOL bFoundKey = FALSE;
  879. DWORD iSubKey = 0;
  880. // okay, now we have to find the product corresponding to this display name (ickie)
  881. do
  882. {
  883. TCHAR szKeyName[ 128 ];
  884. DWORD cchKeyName = sizeof( szKeyName ) / sizeof( *szKeyName );
  885. dwError = RegEnumKeyEx( hKeyLicenseInfo, iSubKey++, szKeyName, &cchKeyName, NULL, NULL, NULL, NULL );
  886. if ( ERROR_SUCCESS == dwError )
  887. {
  888. HKEY hKeyProduct;
  889. dwError = RegOpenKeyEx( hKeyLicenseInfo, szKeyName, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hKeyProduct );
  890. if ( ERROR_SUCCESS == dwError )
  891. {
  892. DWORD dwType;
  893. TCHAR szDisplayName[ 128 ];
  894. DWORD cbDisplayName = sizeof( szDisplayName );
  895. dwError = RegQueryValueEx( hKeyProduct, TEXT( "DisplayName" ), NULL, &dwType, (LPBYTE) szDisplayName, &cbDisplayName );
  896. if ( ( ERROR_SUCCESS == dwError )
  897. && ( REG_SZ == dwType )
  898. && !lstrcmpi( szDisplayName, m_strProduct ) )
  899. {
  900. // YES! we found the product key
  901. // now subtract the concurrent licenses
  902. bFoundKey = TRUE;
  903. DWORD dwConcurrentLimit;
  904. DWORD cbConcurrentLimit = sizeof( dwConcurrentLimit );
  905. dwError = RegQueryValueEx( hKeyProduct, TEXT( "ConcurrentLimit" ), NULL, &dwType, (LPBYTE) &dwConcurrentLimit, &cbConcurrentLimit );
  906. if ( ( ERROR_SUCCESS == dwError ) && ( REG_DWORD == dwType ) )
  907. {
  908. if ( (LONG)dwConcurrentLimit + (LONG)m_nLicenses > 0 )
  909. {
  910. if ( pLicenseInfo->Quantity > (LONG)dwConcurrentLimit )
  911. {
  912. dwConcurrentLimit = 0;
  913. }
  914. else
  915. {
  916. dwConcurrentLimit -= pLicenseInfo->Quantity;
  917. }
  918. dwError = RegSetValueEx( hKeyProduct, TEXT( "ConcurrentLimit" ), 0, REG_DWORD, (LPBYTE) &dwConcurrentLimit, sizeof( dwConcurrentLimit ) );
  919. }
  920. }
  921. }
  922. RegCloseKey( hKeyProduct );
  923. }
  924. // even if an error occurred while trying to find the right product key,
  925. // we should continue to search the rest
  926. if ( !bFoundKey )
  927. {
  928. dwError = ERROR_SUCCESS;
  929. }
  930. }
  931. } while ( !bFoundKey && ( ERROR_SUCCESS == dwError ) );
  932. if ( ERROR_SUCCESS != dwError )
  933. {
  934. theApp.SetLastError( dwError );
  935. }
  936. RegCloseKey( hKeyLicenseInfo );
  937. }
  938. RegCloseKey( hKeyLocalMachine );
  939. }
  940. }
  941. }
  942. else
  943. {
  944. // remove per seat licenses
  945. CString strComment;
  946. strComment.LoadString( IDS_NO_REMOVE_COMMENT );
  947. LPTSTR pszUniProductName = m_strProduct.GetBuffer(0);
  948. LPTSTR pszUniComment = strComment.GetBuffer(0);
  949. if ( ( NULL == pszUniProductName ) || ( NULL == pszUniComment ) )
  950. {
  951. dwError = ERROR_NOT_ENOUGH_MEMORY;
  952. }
  953. else
  954. {
  955. TCHAR szUserName[ 256 ];
  956. DWORD cchUserName = sizeof( szUserName ) / sizeof( *szUserName );
  957. BOOL ok = GetUserName( szUserName, &cchUserName );
  958. if ( !ok )
  959. {
  960. dwError = GetLastError();
  961. }
  962. else
  963. {
  964. NTSTATUS nt;
  965. LLS_LICENSE_INFO_0 lic;
  966. ZeroMemory( &lic, sizeof( lic ) );
  967. lic.Product = pszUniProductName;
  968. lic.Comment = pszUniComment;
  969. lic.Admin = szUserName;
  970. lic.Quantity = -pLicenseInfo->Quantity;
  971. lic.Date = 0;
  972. BeginWaitCursor();
  973. nt = ::LlsLicenseAdd( m_hLls, 0, (LPBYTE) &lic );
  974. theApp.SetLastLlsError( nt );
  975. EndWaitCursor();
  976. dwError = (DWORD) nt;
  977. }
  978. }
  979. if ( NULL != pszUniProductName ) m_strProduct.ReleaseBuffer();
  980. if ( NULL != pszUniComment ) strComment.ReleaseBuffer();
  981. }
  982. if ( ( ERROR_SUCCESS != dwError ) && ( ERROR_CANCELLED != dwError ) )
  983. {
  984. theApp.SetLastError( dwError );
  985. theApp.DisplayLastError();
  986. }
  987. }
  988. return dwError;
  989. }