home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 27 / IOPROG_27.ISO / SOFT / ADSDK.ZIP / Samples / General / ADQI / ADs.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-04-08  |  15.7 KB  |  766 lines

  1. //----------------------------------------------------------------------------
  2. //
  3. //  Microsoft Active Directory 2.5 Sample Code
  4. //
  5. //  Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. //  File:       ADs.cpp
  8. //
  9. //  Contents:   IADs and IADsPathname usage
  10. //
  11. //
  12. //----------------------------------------------------------------------------
  13.  
  14. #include "stdafx.h"
  15. #include "ADQI.h"
  16. #include "ADs.h"
  17. #include "ADsContainer.h"
  18.  
  19. #ifdef _DEBUG
  20. #undef THIS_FILE
  21. static char THIS_FILE[]=__FILE__;
  22. #define new DEBUG_NEW
  23. #endif
  24.  
  25.  
  26. /////////////////////////////////////////////////////////////////////////////
  27. // CDlgIADs dialog
  28.  
  29. #define STRING_SEPARATOR _T("----------")
  30.  
  31. extern ADSIIF  adsiIfs[];
  32.  
  33. CDlgIADs::CDlgIADs(LPUNKNOWN pUnk, CWnd* pParent /*=NULL*/)
  34.     : CDialog(CDlgIADs::IDD, pParent)
  35. {
  36.     //{{AFX_DATA_INIT(CDlgIADs)
  37.     m_sADsPath = _T("");
  38.     m_sClass = _T("");
  39.     m_sName = _T("");
  40.     m_sParent = _T("");
  41.     m_sSchema = _T("");
  42.     m_sGUID = _T("");
  43.     //}}AFX_DATA_INIT
  44.  
  45.     ///////////////////////////////////////
  46.     // Get the IADs pointer and save it 
  47.     /////////////////////////////////////
  48.     HRESULT hr;
  49.     m_pADs = NULL;
  50.     hr = pUnk->QueryInterface( IID_IADs, (void **) &m_pADs );
  51.     if ( !SUCCEEDED(hr) )
  52.     {
  53.         AfxMessageBox(_T("Fatal Error! QI for IADs failed"));
  54.         return;
  55.     }
  56.     pUnk->Release();
  57.     
  58.  
  59. }
  60.  
  61.  
  62. CDlgIADs::~CDlgIADs()
  63. {
  64.   if ( m_pADs )
  65.   {
  66.       m_pADs->Release();
  67.   }
  68. }
  69.  
  70. void CDlgIADs::DoDataExchange(CDataExchange* pDX)
  71. {
  72.     CDialog::DoDataExchange(pDX);
  73.     //{{AFX_DATA_MAP(CDlgIADs)
  74.     DDX_Control(pDX, IDC_ATTRVALUE, m_cValueList);
  75.     DDX_Control(pDX, IDC_ATTRLIST, m_cAttrList);
  76.     DDX_Text(pDX, IDC_ADSPATH, m_sADsPath);
  77.     DDX_Text(pDX, IDC_CLASS, m_sClass);
  78.     DDX_Text(pDX, IDC_NAME, m_sName);
  79.     DDX_Text(pDX, IDC_PARENT, m_sParent);
  80.     DDX_Text(pDX, IDC_SCHEMA, m_sSchema);
  81.     DDX_Text(pDX, IDC_GUID, m_sGUID);
  82.     //}}AFX_DATA_MAP
  83. }
  84.  
  85.  
  86. BEGIN_MESSAGE_MAP(CDlgIADs, CDialog)
  87.     //{{AFX_MSG_MAP(CDlgIADs)
  88.     ON_BN_CLICKED(IDC_GET, OnGet)
  89.     ON_BN_CLICKED(IDC_GETEX, OnGetEx)
  90.     ON_BN_CLICKED(IDC_GETINFO, OnGetInfo)
  91.     ON_BN_CLICKED(IDC_SETINFO, OnSetInfo)
  92.     ON_BN_CLICKED(IDC_GETINFOEX, OnGetInfoex)
  93.     ON_BN_CLICKED(IDC_PUT, OnPut)
  94.     ON_BN_CLICKED(IDC_PUTEX, OnPutEx)
  95.     ON_BN_CLICKED(IDC_PARENTPATH, OnParentPath)
  96.     ON_BN_CLICKED(IDC_SCHEMAPATH, OnSchemaPath)
  97.     ON_BN_CLICKED(IDC_BINDGUID, OnBindGuid)
  98.     ON_CBN_SELCHANGE(IDC_ATTRLIST, OnSelChangeAttrList)
  99.     ON_LBN_DBLCLK(IDC_ATTRVALUE, OnDblClkAttrValue)
  100.     ON_WM_HSCROLL()
  101.     ON_BN_CLICKED(IDC_COPY, OnCopy)
  102.     //}}AFX_MSG_MAP
  103. END_MESSAGE_MAP()
  104.  
  105. /////////////////////////////////////////////////////////////////////////////
  106. // CDlgIADs message handler
  107.  
  108.  
  109. BOOL CDlgIADs::OnInitDialog() 
  110. {
  111.     HRESULT hr;
  112.     VARIANT var;
  113.     BSTR    bstr;
  114.     CStringList sList;
  115.  
  116.     CDialog::OnInitDialog();
  117.  
  118.  
  119.     ASSERT( m_pADs );
  120.     VariantInit(&var);
  121.     //////////////////////////
  122.     // Get the IADs Properties
  123.     /////////////////////////    
  124.  
  125.     // Path
  126.     hr = m_pADs->get_ADsPath( &bstr );
  127.     if ( SUCCEEDED(hr) )
  128.     {
  129.        m_sADsPath = bstr;
  130.        SysFreeString(bstr);
  131.     }
  132.  
  133.     // Name
  134.     hr = m_pADs->get_Name( &bstr );
  135.     if ( SUCCEEDED(hr) )
  136.     {
  137.        m_sName = bstr;
  138.        SysFreeString(bstr);
  139.     }
  140.  
  141.     // Parent
  142.     hr = m_pADs->get_Parent( &bstr );
  143.     if ( SUCCEEDED(hr) )
  144.     {
  145.        m_sParent = bstr;
  146.        SysFreeString(bstr);
  147.     }
  148.  
  149.     // Schema
  150.     hr = m_pADs->get_Schema( &bstr );
  151.     if ( SUCCEEDED(hr) )
  152.     {
  153.        m_sSchema = bstr;
  154.        SysFreeString(bstr);
  155.     }
  156.  
  157.     // Class
  158.     hr = m_pADs->get_Class( &bstr );
  159.     if ( SUCCEEDED(hr) )
  160.     {
  161.        m_sClass = bstr;
  162.        SysFreeString(bstr);
  163.     }
  164.  
  165.     // GUID
  166.     hr = m_pADs->get_GUID( &bstr );
  167.     if ( SUCCEEDED(hr) )
  168.     {
  169.        m_sGUID = bstr;
  170.        SysFreeString(bstr);
  171.     }
  172.  
  173.     if ( m_sGUID.GetLength() == 0 )
  174.     {
  175.         GetDlgItem(IDC_BINDGUID)->EnableWindow( FALSE );
  176.     }
  177.  
  178.     ///////////////////////////////////////////////////////////////
  179.     //
  180.     // Enumerate all attributes in this object
  181.     // Steps:
  182.     //  1. Get the object's schema information
  183.     //  2. Bind to that schema
  184.     //  3. QI for Class
  185.     //  4. Enumerate the Mandatory and Optional Attributes
  186.     //
  187.     /////////////////////////////////////////////////////////////
  188.     USES_CONVERSION;
  189.     IADsClass *pClass;
  190.     hr = App->ADsOpenObject(T2OLE(m_sSchema), IID_IADsClass, (void**) &pClass );
  191.     if ( SUCCEEDED(hr) )
  192.     {
  193.         m_cAttrList.ResetContent(); // Clear the list box content.
  194.  
  195.        // Mandatory
  196.        pClass->get_MandatoryProperties( &var );
  197.        VariantToStringList(  var, sList );
  198.        PopulateComboBoxFromStringList( m_cAttrList, sList );
  199.        VariantClear(&var);
  200.  
  201.        //  A separator to seperate mandatory and optional attributes
  202.        m_cAttrList.AddString( STRING_SEPARATOR);
  203.  
  204.        // Optional
  205.        pClass->get_OptionalProperties( &var );
  206.        VariantToStringList(  var, sList );
  207.        PopulateComboBoxFromStringList( m_cAttrList, sList );
  208.        VariantClear(&var);
  209.     }
  210.  
  211.  
  212.     UpdateData(FALSE);
  213.     
  214.     return TRUE;  // return TRUE unless you set the focus to a control
  215.                   // EXCEPTION: OCX Property Pages should return FALSE
  216. }
  217.  
  218. void CDlgIADs::OnGet() 
  219. {
  220.    CString sAttr;
  221.    CStringList sList;
  222.    VARIANT var;
  223.    HRESULT hr;
  224.    m_cAttrList.GetLBText( m_cAttrList.GetCurSel(), sAttr );
  225.  
  226.  
  227.  
  228.    if ( sAttr == STRING_SEPARATOR )
  229.    {
  230.        MessageBeep(0);
  231.        return;
  232.    }
  233.  
  234.    m_cValueList.ResetContent();
  235.  
  236.  
  237.    USES_CONVERSION;
  238.    /////////////////////////////
  239.    // Get the attribute
  240.    ////////////////////////////////
  241.    hr = m_pADs->Get( T2OLE(sAttr), &var);
  242.    
  243.  
  244.    ////////////////////////////////
  245.    // UI: populate the listbox
  246.    ////////////////////////////////
  247.    if ( SUCCEEDED(hr) )
  248.    {
  249.         
  250.         hr = VariantToStringList(  var, sList );
  251.    
  252.         if ( SUCCEEDED(hr) )
  253.         {
  254.             PopulateListBoxFromStringList( m_cValueList, sList );
  255.         }
  256.  
  257.  
  258.         VariantClear(&var);
  259.    }
  260.    else
  261.    {
  262.        CString s;
  263.        s = GetErrorMessage( hr );
  264.        m_cValueList.AddString( s );
  265.    }
  266.     
  267. }
  268.  
  269. ////////////////////////////////////////////////////////////////////////////////
  270. // IADs::GetEx is similar to Get. The GetEx always return an array of variant
  271. // regardless if the attribute is single or multi value.
  272. // This is useful for VB/VBS environment. 
  273. ////////////////////////////////////////////////////////////////////////////////
  274. void CDlgIADs::OnGetEx() 
  275. {
  276.  
  277.    CString sAttr;
  278.    CStringList sList;
  279.    VARIANT var;
  280.    HRESULT hr;
  281.    m_cAttrList.GetLBText( m_cAttrList.GetCurSel(), sAttr );
  282.    m_cValueList.ResetContent();
  283.  
  284.    USES_CONVERSION;
  285.    /////////////////////////////
  286.    // GetEx the attribute
  287.    ////////////////////////////////
  288.    hr = m_pADs->GetEx( T2OLE(sAttr), &var);
  289.    
  290.  
  291.    ////////////////////////////////
  292.    // UI: populate the listbox
  293.    ////////////////////////////////
  294.    if ( SUCCEEDED(hr) )
  295.    {
  296.         
  297.         hr = VariantToStringList(  var, sList );
  298.    
  299.         if ( SUCCEEDED(hr) )
  300.         {
  301.             PopulateListBoxFromStringList( m_cValueList, sList );
  302.         }
  303.  
  304.         VariantClear(&var);
  305.    }
  306.  
  307.     
  308. }
  309.  
  310. //////////////////////////////////////////////////////
  311. // GetInfo is to refresh the cache
  312. // All attributes in this object will be sent
  313. // to the client and be cached again
  314. //
  315. /////////////////////////////////////////////////////////
  316. void CDlgIADs::OnGetInfo() 
  317. {
  318.     HRESULT hr;
  319.     ASSERT(m_pADs);
  320.  
  321.     hr = m_pADs->GetInfo();    
  322.     if (!SUCCEEDED(hr) )
  323.     {
  324.         AfxMessageBox(GetErrorMessage(hr));
  325.         return;
  326.     }
  327.     else
  328.     {
  329.         AfxMessageBox(_T("Succeed"));
  330.     }
  331. }
  332.  
  333. /////////////////////////////////////////////////////////////
  334. // SetInfo will commit any changes since the last SetInfo    //
  335. //                                                            //
  336. //////////////////////////////////////////////////////////////
  337. void CDlgIADs::OnSetInfo() 
  338. {
  339.     HRESULT hr;
  340.     ASSERT(m_pADs);
  341.  
  342.     hr = m_pADs->GetInfo();    
  343.     if (!SUCCEEDED(hr) )
  344.     {
  345.         AfxMessageBox(GetErrorMessage(hr));
  346.         return;
  347.     }
  348.     else
  349.     {
  350.         AfxMessageBox(_T("Succeed"));
  351.     }
  352.  
  353.     
  354. }
  355.  
  356. //////////////////////////////////////////////////
  357. // Similar to GetInfo. Unlike GetInfo, GetInfoEx
  358. // only brings the specified attributes to the client
  359. // This is for an optimization purpose.
  360. ///////////////////////////////////////////////////
  361. void CDlgIADs::OnGetInfoex() 
  362. {
  363.     CGetInfoExDlg dlg;
  364.     VARIANT var;
  365.     HRESULT hr;
  366.  
  367.     if ( dlg.DoModal() == IDOK )
  368.     {
  369.         CString s;
  370.         CString sAttr;
  371.         CStringList sList;
  372.         int idx;
  373.  
  374.         s = dlg.GetAttribute();
  375.         //////////////////////////////////////////
  376.         // Parse and put them in the string list
  377.         //////////////////////////////////////////
  378.         idx = s.Find(_T(","));
  379.         while( idx != -1 )
  380.         {
  381.            sAttr = s.Mid(0, idx );
  382.            sAttr.TrimLeft(); sAttr.TrimRight();
  383.            sList.AddTail( sAttr );
  384.            s = s.Mid( idx + 1 );
  385.            idx = s.Find(_T(","));
  386.         }
  387.         s.TrimLeft(); s.TrimRight();
  388.         sList.AddTail( s );
  389.  
  390.         /////////////////////////////////
  391.         // Convert stringlist to variant
  392.         ////////////////////////////////
  393.         hr = StringListToVariant( var, sList);
  394.         if ( SUCCEEDED(hr) )
  395.         {
  396.             ///////////////////////////////
  397.             // Now do the real work!!
  398.             ///////////////////////////////
  399.             hr = m_pADs->GetInfoEx( var, 0 );
  400.             if (!SUCCEEDED(hr) )
  401.             {
  402.                 AfxMessageBox(GetErrorMessage(hr));
  403.             }
  404.             VariantClear(&var);
  405.         }
  406.  
  407.  
  408.  
  409.     }
  410.     
  411. }
  412.  
  413.  
  414. void CDlgIADs::OnPut() 
  415. {
  416.     // TODO: Add your control notification handler code here
  417.     
  418. }
  419.  
  420. void CDlgIADs::OnPutEx() 
  421. {
  422.     // TODO: Add your control notification handler code here
  423.     
  424. }
  425.  
  426.  
  427.  
  428.  
  429.  
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437. /////////////////////////////////////////////////////////////////////////////
  438. // CGetInfoExDlg dialog
  439.  
  440.  
  441. CGetInfoExDlg::CGetInfoExDlg(CWnd* pParent /*=NULL*/)
  442.     : CDialog(CGetInfoExDlg::IDD, pParent)
  443. {
  444.     //{{AFX_DATA_INIT(CGetInfoExDlg)
  445.     m_sAttrText = _T("");
  446.     //}}AFX_DATA_INIT
  447. }
  448.  
  449.  
  450. void CGetInfoExDlg::DoDataExchange(CDataExchange* pDX)
  451. {
  452.     CDialog::DoDataExchange(pDX);
  453.     //{{AFX_DATA_MAP(CGetInfoExDlg)
  454.     DDX_Text(pDX, IDC_ATTR, m_sAttrText);
  455.     //}}AFX_DATA_MAP
  456. }
  457.  
  458.  
  459. BEGIN_MESSAGE_MAP(CGetInfoExDlg, CDialog)
  460.     //{{AFX_MSG_MAP(CGetInfoExDlg)
  461.     //}}AFX_MSG_MAP
  462. END_MESSAGE_MAP()
  463.  
  464. /////////////////////////////////////////////////////////////////////////////
  465. // CGetInfoExDlg message handlers
  466.  
  467. void CGetInfoExDlg::OnOK() 
  468. {
  469.     UpdateData(TRUE);
  470.     m_sAttr = m_sAttrText;
  471.     CDialog::OnOK();
  472. }
  473.  
  474.  
  475.  
  476.  
  477. void CDlgIADs::OnParentPath() 
  478. {
  479.       HRESULT hr;
  480.       UpdateData(TRUE); // Retrieve from UI
  481.  
  482.  
  483.       USES_CONVERSION;
  484.       IUnknown *pUnk;
  485.       CWaitCursor wait;
  486.       
  487.       hr = App->ADsOpenObject( T2OLE( m_sParent ), IID_IUnknown, (void**) &pUnk ); 
  488.       
  489.       /////////////////////////////////////
  490.       // Bring up the IADsContainer Dialog
  491.       ///////////////////////////////////////
  492.       if ( SUCCEEDED(hr) )
  493.       {
  494.           pUnk->AddRef();
  495.           CDlgIADsContainer dlg( pUnk, this );      
  496.           dlg.DoModal();
  497.  
  498.           pUnk->Release();
  499.       }
  500.       else
  501.       {
  502.           AfxMessageBox( GetErrorMessage(hr) );
  503.       }
  504.  
  505.     
  506. }
  507.  
  508.  
  509. void CDlgIADs::OnSchemaPath() 
  510. {
  511.       HRESULT hr;
  512.       UpdateData(TRUE); // Retrieve from UI
  513.  
  514.  
  515.       USES_CONVERSION;
  516.       IUnknown *pUnk;
  517.       IADs       *pADs;
  518.       BSTR      bstr;
  519.       CWaitCursor wait;
  520.  
  521.       
  522.       hr = App->ADsOpenObject( T2OLE( m_sSchema ), IID_IADs, (void**) &pADs ); 
  523.       RETURN_ON_FAILURE(hr);
  524.       
  525.  
  526.       hr = pADs->get_Parent( &bstr );
  527.       pADs->Release();
  528.  
  529.       RETURN_ON_FAILURE(hr);
  530.  
  531.       hr = App->ADsOpenObject( bstr, IID_IUnknown, (void**) &pUnk ); 
  532.       SysFreeString( bstr );
  533.  
  534.       /////////////////////////////////////
  535.       // Bring up the IADsContainer Dialog
  536.       ///////////////////////////////////////
  537.       if ( SUCCEEDED(hr) )
  538.       {
  539.           pUnk->AddRef();
  540.           CDlgIADsContainer dlg( pUnk, this );      
  541.           dlg.DoModal();
  542.  
  543.           pUnk->Release();
  544.       }
  545.  
  546.  
  547.     
  548. }
  549.  
  550. //////////////////////////////////////////////////////
  551. //
  552. // GUID Binding: Only works with Active Directory
  553. //
  554. ////////////////////////////////////////////////////////
  555. void CDlgIADs::OnBindGuid() 
  556. {
  557.   CWaitCursor wait;
  558.   CComBSTR bstrPath;
  559.   IUnknown *pUnk = NULL;
  560.   HRESULT hr;
  561.   UpdateData(TRUE); // Retrieve from UI
  562.  
  563.  
  564.   
  565.   CComPtr<IADsPathname> pPathname=NULL;
  566.   BSTR bstr;
  567.   BSTR bstrProvider;
  568.   BSTR bstrServer;
  569.   
  570.  
  571.   hr = CoCreateInstance( CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (void**) &pPathname );
  572.  
  573.   RETURN_ON_FAILURE(hr);
  574.  
  575.  
  576.   hr = m_pADs->get_ADsPath(&bstr);
  577.  
  578.   RETURN_ON_FAILURE(hr);
  579.  
  580.   
  581.   /////////////////////////////////////////////////
  582.   // Usage: PathName to find out the provider 
  583.   ///////////////////////////////////////////////////
  584.   hr = pPathname->Set( bstr, ADS_SETTYPE_FULL );
  585.   SysFreeString( bstr );
  586.   RETURN_ON_FAILURE(hr);
  587.  
  588.   hr = pPathname->Retrieve(ADS_FORMAT_PROVIDER, &bstrProvider );
  589.   RETURN_ON_FAILURE(hr);
  590.  
  591.   if ( wcscmp( bstrProvider, L"LDAP") != 0 )
  592.   {
  593.       AfxMessageBox(_T("Only LDAP: (Active Directory Provider) knows about <GUID=xxxx> syntax"));
  594.       SysFreeString( bstrProvider );
  595.       return;
  596.   }
  597.  
  598.   /////////////////////////////////////////////////
  599.   // Usage: PathName to find out the server
  600.   ///////////////////////////////////////////////////
  601.   hr = pPathname->Retrieve(ADS_FORMAT_SERVER, &bstrServer );
  602.  
  603.   if ( hr == E_ADS_BAD_PATHNAME ) // Serverless binding ( can work only from DS aware client )
  604.   {
  605.       bstrServer = SysAllocString(L"");
  606.   }
  607.  
  608.   
  609.   
  610.  
  611.  
  612.   ///////////////////////////////////////////////
  613.   // Now build the LDAP://server/<GUID=xxx
  614.   //////////////////////////////////////////////
  615.  
  616.  
  617.   bstrPath = bstrProvider;
  618.   bstrPath.Append(_T("://"));
  619.   if ( wcslen( bstrServer ) ) // Server based binding ?
  620.   {
  621.      bstrPath.AppendBSTR( bstrServer );
  622.      bstrPath.Append(_T("/"));
  623.      SysFreeString( bstrServer );
  624.   }
  625.   bstrPath.Append(_T("<GUID="));
  626.   bstrPath.Append( m_sGUID );
  627.   bstrPath.Append(_T(">") );
  628.  
  629.   // we don't need these bstrs anymore
  630.   SysFreeString( bstrProvider );
  631.   
  632.  
  633.  
  634.   // Now Bind using GUID
  635.   
  636.   hr = App->ADsOpenObject( bstrPath, IID_IUnknown, (void**) &pUnk ); 
  637.       
  638.   /////////////////////////////////////
  639.   // Bring up the IADs Dialog
  640.   ///////////////////////////////////////
  641.   if ( SUCCEEDED(hr) )
  642.   {
  643.       pUnk->AddRef();
  644.       CDlgIADs dlg( pUnk, this );      
  645.       dlg.DoModal();
  646.       pUnk->Release();
  647.   }
  648.   else
  649.   {
  650.       AfxMessageBox( GetErrorMessage(hr) );
  651.       return;
  652.   }
  653.       
  654.     
  655. }
  656.  
  657. void CDlgIADs::OnSelChangeAttrList() 
  658. {
  659.     OnGet();
  660. }
  661.  
  662. void CDlgIADs::OnDblClkAttrValue() 
  663. {
  664.     int idx;
  665.     HRESULT hr;
  666.  
  667.     idx = m_cValueList.GetCurSel();
  668.     if ( idx == LB_ERR )
  669.     {
  670.         return;
  671.     }
  672.  
  673.     // If someone click this it may be an interface that has the UI.
  674.     // The interface value start with --> in the UI
  675.     CString s;
  676.     int xx;
  677.     CString sArrow = ARROW_SYMBOL;
  678.     m_cValueList.GetText( idx, s );
  679.     
  680.     if ( s.Find(sArrow,0 ) == 0 )
  681.     {
  682.         s = s.Mid( sArrow.GetLength() );
  683.  
  684.         // Find the appropriate dialog box
  685.         xx=0;
  686.         while( !IsEqualIID( *adsiIfs[xx].pIID, IID_NULL ) && s != adsiIfs[xx].szIf  )
  687.         {
  688.            xx++;
  689.         }
  690.  
  691.      
  692.         if ( adsiIfs[xx].pFn )
  693.         {
  694.             
  695.             CString sAttr;
  696.             VARIANT var;
  697.  
  698.             // We need to get the value again
  699.             USES_CONVERSION;
  700.             m_cAttrList.GetLBText( m_cAttrList.GetCurSel(), sAttr );
  701.             hr = m_pADs->Get( T2OLE(sAttr), &var);
  702.             if ( SUCCEEDED(hr) )
  703.             {
  704.               IUnknown *pUnk;
  705.               hr = V_DISPATCH(&var)->QueryInterface( IID_IUnknown, (void**) &pUnk );
  706.               if ( SUCCEEDED(hr) )
  707.               {
  708.                   (*adsiIfs[xx].pFn)( pUnk, NULL );
  709.               }
  710.             }
  711.         }
  712.         else
  713.         {
  714.            AfxMessageBox(_T("No UI implemented yet"));
  715.         }
  716.  
  717.  
  718.  
  719.         return;
  720.  
  721.     }
  722.     
  723.  
  724.  
  725. }
  726.  
  727. /////////////////////////////////
  728. // Copy to cliboard
  729. /////////////////////////////////
  730. void CDlgIADs::OnCopy() 
  731. {
  732.     CString s;
  733.     HANDLE hMem;
  734.     int idx;
  735.     
  736.  
  737.     idx = m_cValueList.GetCurSel();
  738.  
  739.     if ( idx == LB_ERR )
  740.     {
  741.         return;
  742.     }
  743.  
  744.     m_cValueList.GetText( idx, s );
  745.  
  746.     if ( !OpenClipboard() )
  747.     {
  748.         return;
  749.     }
  750.     EmptyClipboard();
  751.  
  752.     
  753.     hMem = GlobalAlloc( GMEM_DDESHARE, sizeof(TCHAR) * (s.GetLength() + 1) );
  754.     if ( hMem )
  755.     {
  756.         LPTSTR pMem;
  757.         pMem = (LPTSTR) GlobalLock( hMem );
  758.         lstrcpy( pMem, s );
  759.         GlobalUnlock(hMem);
  760.         SetClipboardData( CF_TEXT, hMem );
  761.     }
  762.  
  763.     CloseClipboard();
  764.     
  765. }
  766.