addrlist.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 19k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. /**************************************************************
  2.     FILE: addrlist.cpp
  3.     DESCRIPTION:
  4.         This is a class that all Address Lists can inherite
  5.     from.  This will give them the IAddressList interface
  6.     so they can work in the AddressBand/Bar.
  7. **************************************************************/
  8. #include "priv.h"
  9. #include "dbgmem.h"
  10. #include "util.h"
  11. #include "itbdrop.h"
  12. #include "autocomp.h"
  13. #include "addrlist.h"
  14. #include "apithk.h"
  15. #include "shui.h"
  16. #include "shlguid.h"
  17. CAddressList::CAddressList() : _cRef(1)
  18. {
  19.     // This needs to be allocated in Zero Inited Memory.
  20.     // Assert that all Member Variables are inited to Zero.
  21.     ASSERT(!_pbp);
  22. }
  23. CAddressList::~CAddressList()
  24. {
  25.     if (_pbp)
  26.         _pbp->Release();
  27.     if (_pbs)
  28.         _pbs->Release();
  29.     if (_pshuUrl)
  30.         delete _pshuUrl;
  31. }
  32. ULONG CAddressList::AddRef()
  33. {
  34.     _cRef++;
  35.     return _cRef;
  36. }
  37. ULONG CAddressList::Release()
  38. {
  39.     ASSERT(_cRef > 0);
  40.     _cRef--;
  41.     if (_cRef > 0)
  42.         return _cRef;
  43.     delete this;
  44.     return 0;
  45. }
  46. HRESULT CAddressList::QueryInterface(REFIID riid, void **ppvObj)
  47. {
  48.     if (IsEqualIID(riid, IID_IUnknown) ||
  49.         IsEqualIID(riid, IID_IWinEventHandler) ||
  50.         IsEqualIID(riid, IID_IAddressList))
  51.     {
  52.         *ppvObj = SAFECAST(this, IAddressList*);
  53.     }
  54.     else
  55.     {
  56.         *ppvObj = NULL;
  57.         return E_NOINTERFACE;
  58.     }
  59.     AddRef();
  60.     return S_OK;
  61. }
  62. //================================
  63. //  ** IWinEventHandler Interface ***
  64. /****************************************************
  65.     FUNCTION: OnWinEvent
  66.     DESCRIPTION:
  67.         This function will give receive events from
  68.     the parent ShellToolbar.
  69. ****************************************************/
  70. HRESULT CAddressList::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  71. {
  72.     LRESULT lres = 0;
  73.     switch (uMsg)
  74.     {
  75.     case WM_COMMAND:
  76.         lres = _OnCommand(wParam, lParam);
  77.         break;
  78.     case WM_NOTIFY:
  79.         lres = _OnNotify((LPNMHDR)lParam);
  80.         break;
  81.     }
  82.     if (plres)
  83.         *plres = lres;
  84.     return S_OK;
  85. }
  86. //================================
  87. // *** IAddressList Interface ***
  88. /****************************************************
  89.     FUNCTION: Connect
  90.     DESCRIPTION:
  91.         We are either becoming the selected list for
  92.     the AddressBand's combobox, or lossing this status.
  93.     We need to populate or unpopulate the combobox
  94.     as appropriate.
  95. ****************************************************/
  96. HRESULT CAddressList::Connect(BOOL fConnect, HWND hwnd, IBrowserService * pbs, IBandProxy * pbp, IAutoComplete * pac)
  97. {
  98.     HRESULT hr = S_OK;
  99.     ASSERT(hwnd);
  100.     _fVisible = fConnect;
  101.     _hwnd = hwnd;
  102.     // Copy the (IBandProxy *) parameter
  103.     if (_pbp)
  104.         _pbp->Release();
  105.     _pbp = pbp;
  106.     if (_pbp)
  107.         _pbp->AddRef();
  108.     if (_pbs)
  109.         _pbs->Release();
  110.     _pbs = pbs;
  111.     if (_pbs)
  112.         _pbs->AddRef();
  113.     if (fConnect)
  114.     {
  115.         //
  116.         // Initial combobox parameters.
  117.         //
  118.         _InitCombobox();
  119.     }
  120.     else
  121.     {
  122.         // Remove contents of the List
  123.         _PurgeComboBox();
  124.     }
  125.     return hr;
  126. }
  127. /****************************************************
  128.     FUNCTION: _InitCombobox
  129.     DESCRIPTION:
  130.         Prepare the combo box for this list.  This normally
  131.     means that the indenting and icon are either turned
  132.     on or off.
  133. ****************************************************/
  134. void CAddressList::_InitCombobox()
  135. {
  136.      SendMessage(_hwnd, CB_SETDROPPEDWIDTH, 200, 0L);
  137.      SendMessage(_hwnd, CB_SETEXTENDEDUI, TRUE, 0L);
  138.      SendMessage(_hwnd, CBEM_SETEXTENDEDSTYLE, CBES_EX_NOSIZELIMIT, CBES_EX_NOSIZELIMIT);
  139. }
  140. /****************************************************
  141.     FUNCTION: _PurgeComboBox
  142.     DESCRIPTION:
  143.         Removes all items from the combobox.
  144. ****************************************************/
  145. void CAddressList::_PurgeComboBox()
  146. {
  147.     if (_hwnd)
  148.     {
  149.         SendMessage(_hwnd, CB_RESETCONTENT, 0, 0L);
  150.     }
  151. }
  152. /****************************************************
  153.     FUNCTION: _OnCommand
  154.     DESCRIPTION:
  155.         This function will handle WM_COMMAND messages.
  156. ****************************************************/
  157. LRESULT CAddressList::_OnCommand(WPARAM wParam, LPARAM lParam)
  158. {
  159.     UINT uCmd = GET_WM_COMMAND_CMD(wParam, lParam);
  160.     switch (uCmd)
  161.     {
  162.         case CBN_DROPDOWN:
  163.             {
  164.                 HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  165.                 //
  166.                 // DOH! The user wants to see the full combo contents.
  167.                 // Better go fill it in now.
  168.                 //
  169.                 _Populate();
  170.                 SetCursor(hCursorOld);
  171.             }
  172.             break;
  173.     }
  174.     return 0;
  175. }
  176. /****************************************************
  177.     FUNCTION: NavigationComplete
  178.     DESCRIPTION:
  179.         Update the URL in the Top of the list.
  180. ****************************************************/
  181. HRESULT CAddressList::NavigationComplete(LPVOID pvCShellUrl)
  182. {
  183.     HRESULT hr = S_OK;
  184.     TCHAR szDisplayName[MAX_URL_STRING];
  185.     CShellUrl * psu = (CShellUrl *) pvCShellUrl;
  186.     LPITEMIDLIST pidl;
  187.     ASSERT(pvCShellUrl);
  188.     hr = psu->GetDisplayName(szDisplayName, SIZECHARS(szDisplayName));
  189.     ASSERT(SUCCEEDED(hr));
  190.     //
  191.     // Don't display the url to internal error pages.  The url that should get
  192.     // displayed is appended after the #.
  193.     //
  194.     // All error urls start with res:// so do a quick check first.
  195.     //
  196.     BOOL fChangeURL = TRUE;
  197.     if (TEXT('r') == szDisplayName[0] && TEXT('e') == szDisplayName[1])
  198.     {
  199.         if (IsErrorUrl(szDisplayName))
  200.         {
  201.             TCHAR* pszUrl = StrChr(szDisplayName, TEXT('#'));
  202.             if (pszUrl)
  203.             {
  204.                 pszUrl += 1;
  205.                 DWORD dwScheme = GetUrlScheme(pszUrl);
  206.                 fChangeURL = ((URL_SCHEME_HTTP == dwScheme) ||
  207.                               (URL_SCHEME_HTTPS == dwScheme) ||
  208.                               (URL_SCHEME_FTP == dwScheme) ||
  209.                               (URL_SCHEME_GOPHER == dwScheme));
  210.                 // Don't blast in the stuff after the # into address bar
  211.                 // unless it is a 'safe' url.  If it's not safe leave the
  212.                 // addressbar alone to preserve what the user typed in.
  213.                 //
  214.                 // The issue here is that a web page could navigate to our internal
  215.                 // error page with "format c:" after the '#'.  The error page
  216.                 // suggests that the user refreshed the page which would be very bad!
  217.                 if(fChangeURL)
  218.                 {
  219.                     StrCpyN(szDisplayName, pszUrl, ARRAYSIZE(szDisplayName));
  220.                 }
  221.             }
  222.         }
  223.     }
  224.     if (fChangeURL)
  225.     {
  226.         SHRemoveURLTurd(szDisplayName);
  227.         hr = psu->GetPidl(&pidl);
  228.         if (SUCCEEDED(hr))
  229.         {
  230.             COMBOBOXEXITEM cbexItem = {0};
  231.             cbexItem.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
  232.             cbexItem.iItem = -1;
  233.             cbexItem.pszText = szDisplayName;
  234.             cbexItem.cchTextMax = ARRAYSIZE(szDisplayName);
  235.             hr = _GetPidlIcon(pidl, &(cbexItem.iImage), &(cbexItem.iSelectedImage));
  236.             SendMessage(_hwnd, CBEM_SETITEM, (WPARAM)0, (LPARAM)(LPVOID)&cbexItem);
  237.             ILFree(pidl);
  238.         }
  239.     }
  240.     TraceMsg(TF_BAND|TF_GENERAL, "CAddressList: NavigationComplete(), URL=%s", szDisplayName);
  241.     return hr;
  242. }
  243. /*******************************************************************
  244.     FUNCTION: _MoveAddressToTopOfList
  245.     PARAMETERS:
  246.         iSel - index of item in combo box to move
  247.     DESCRIPTION:
  248.         Moves the specified selection in the combo box
  249.     to be the first item in the combo box
  250. ********************************************************************/
  251. BOOL CAddressList::_MoveAddressToTopOfList(int iSel)
  252. {
  253.     BOOL fRet = FALSE;
  254.     ASSERT(iSel >= 0);   // must have valid index
  255.     COMBOBOXEXITEM cbexItem = {0};
  256.     TCHAR szAddress[MAX_URL_STRING+1];
  257.     cbexItem.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
  258.     cbexItem.pszText = szAddress;
  259.     cbexItem.cchTextMax = ARRAYSIZE(szAddress);
  260.     cbexItem.iItem = iSel;
  261.     
  262.     // get the specified item from combo box
  263.     if (SendMessage(_hwnd,CBEM_GETITEM,0,(LPARAM) &cbexItem)) {
  264.         SendMessage(_hwnd, CBEM_DELETEITEM, (WPARAM)iSel, (LPARAM)0);
  265.         // re-insert it at index 0 to put it at the top
  266.         cbexItem.iItem = 0;
  267.         // sending CBEM_INSERTITEM should return the index we specified
  268.                 // (0) if successful
  269.         fRet = (SendMessage(_hwnd, CBEM_INSERTITEM, (WPARAM)0,
  270.             (LPARAM)(LPVOID)&cbexItem) == 0);
  271.     }
  272.     return fRet;
  273. }
  274. /*******************************************************************
  275.     FUNCTION: _ComboBoxInsertURL
  276.     DESCRIPTION:
  277.         Adds the specified URL to the top of the address bar
  278.     combo box.  Limits the number of URLs in combo box to
  279.     nMaxComboBoxSize.
  280. ********************************************************************/
  281. void CAddressList::_ComboBoxInsertURL(LPCTSTR pszURL, int cchStrSize, int nMaxComboBoxSize)
  282. {
  283.     // Since we own it and it's populated,
  284.     // we will add it directly to the ComboBox.
  285.     int iPrevInstance;
  286.     int iImage, iSelectedImage ;
  287.     COMBOBOXEXITEM cbexItem = {0};
  288.     cbexItem.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
  289.     cbexItem.iItem = 0;
  290.     cbexItem.cchTextMax = cchStrSize;
  291.     cbexItem.pszText = (LPTSTR)pszURL;
  292.     _GetUrlUI(NULL, (LPTSTR)pszURL, &iImage, &iSelectedImage);
  293.     cbexItem.iImage = iImage;
  294.     cbexItem.iSelectedImage = iSelectedImage;
  295.     iPrevInstance = (int)SendMessage(_hwnd, CB_FINDSTRINGEXACT, (WPARAM)-1,  (LPARAM)pszURL);
  296.     if (iPrevInstance != CB_ERR) {
  297.         _MoveAddressToTopOfList(iPrevInstance);
  298.         return;
  299.     }
  300.     // insert the URL as the first item in combo box
  301.     SendMessage(_hwnd, CBEM_INSERTITEM, (WPARAM)0, (LPARAM)(LPVOID)&cbexItem);
  302.     // limit number of items in combo box to nMaxComboBoxSize
  303.     if (ComboBox_GetCount(_hwnd) > nMaxComboBoxSize)
  304.     {
  305.         // if we're ever over the limit, we should only be over the limit
  306.         // by exactly one item
  307.         ASSERT(ComboBox_GetCount(_hwnd) == nMaxComboBoxSize+1);
  308.         // if over the limit, delete the least recently used
  309.         // (the one with the highest index)
  310.         SendMessage(_hwnd, CBEM_DELETEITEM, (WPARAM)nMaxComboBoxSize, (LPARAM)0);
  311.     }
  312. }
  313. /*******************************************************************
  314.     FUNCTION: SetToListIndex
  315.     DESCRIPTION:
  316.         This function will set the CShellUrl parameter to the item
  317.     in the Drop Down list that is indexed by nIndex.
  318. ********************************************************************/
  319. HRESULT CAddressList::SetToListIndex(int nIndex, LPVOID pvShelLUrl)
  320. {
  321.     HRESULT hr = S_OK;
  322.     TCHAR szBuffer[MAX_URL_STRING];
  323.     CShellUrl * psuURL = (CShellUrl *) pvShelLUrl;
  324.     GetCBListIndex(_hwnd, nIndex, szBuffer, SIZECHARS(szBuffer));
  325.     hr = psuURL->ParseFromOutsideSource(szBuffer, SHURL_FLAGS_NOUI);
  326.     ASSERT(SUCCEEDED(hr));  // We should not have added it to the Drop Down list if it's invalid.
  327.     return hr;
  328. }
  329. HRESULT CAddressList::FileSysChangeAL(DWORD dw, LPCITEMIDLIST *ppidl)
  330. {
  331.     return S_OK;
  332. }
  333. /****************************************************
  334.     FUNCTION: GetCBListIndex
  335.     DESCRIPTION:
  336.         This function will get the text of a specified
  337.     element in the combobox.
  338. ****************************************************/
  339. HRESULT GetCBListIndex(HWND hwnd, int iItem, LPTSTR szAddress, int cchAddressSize)
  340. {
  341.     HRESULT hr = E_FAIL;
  342.     COMBOBOXEXITEM cbexItem = {0};
  343.     cbexItem.mask = CBEIF_TEXT;
  344.     cbexItem.pszText = szAddress;
  345.     cbexItem.cchTextMax = cchAddressSize;
  346.     cbexItem.iItem = iItem;
  347.     if (SendMessage(hwnd, CBEM_GETITEM, 0, (LPARAM) &cbexItem))
  348.         hr = S_OK;
  349.     return hr;
  350. }
  351. // Helper Function
  352. // We need to really becareful of perf in this function.
  353. HRESULT CAddressList::_GetUrlUI(CShellUrl *psu, LPCTSTR szUrl, int *piImage, int *piSelectedImage)
  354. {
  355.     CShellUrl * psuUrl;
  356.     HRESULT hr = E_FAIL;
  357.     int iDrive;
  358.     if (psu)
  359.         psuUrl = psu;
  360.     else
  361.     {
  362.         psuUrl = new CShellUrl();
  363.         if (EVAL(psuUrl))
  364.         {
  365.             // Set the parent for error messageboxes.  Note that this could end up disabing the taskbar.
  366.             // If this is deemed to be a problem we can first check to see where the addressbar is hosted.
  367.             psuUrl->SetMessageBoxParent(_hwnd);
  368.             SetDefaultShellPath(psuUrl);
  369.         }
  370.     }
  371.     //Initialize the values to 0
  372.     *piImage = 0;
  373.     *piSelectedImage = 0;
  374.     //if object is not created return with default value
  375.     if (!psuUrl)
  376.         return E_OUTOFMEMORY;
  377.     // See if we have a drive specified in the path
  378.     if((iDrive = PathGetDriveNumber(szUrl)) >= 0)
  379.     {
  380.         // See if the drive is removable ?
  381.         if(DriveType(iDrive) == DRIVE_REMOVABLE)
  382.             hr = S_OK;    //Drive is removable so pass the default icons
  383.     }
  384.     // Do we still need to get the icons?
  385.     if (FAILED(hr))
  386.     {
  387.         // Yes, so try the fast way first.
  388.         hr = _GetFastPathIcons(szUrl, piImage, piSelectedImage);
  389.         if (FAILED(hr))
  390.         {
  391.             LPITEMIDLIST pidl = NULL;
  392.             // If that failed because it the string probably uses advanced parsing, 
  393.             // let CShellUrl do it the slower but more thurough way.
  394.             hr = psuUrl->ParseFromOutsideSource(szUrl, SHURL_FLAGS_NOUI);
  395.             if(SUCCEEDED(hr))
  396.                 hr = psuUrl->GetPidl(&pidl);
  397.             if(SUCCEEDED(hr))
  398.             {
  399.                 hr = _GetPidlIcon(pidl, piImage, piSelectedImage);
  400.                 ILFree(pidl);
  401.             }
  402.         }
  403.     }
  404.     if (psu != psuUrl)
  405.         delete psuUrl;
  406.     return hr;
  407. }
  408. // IECreateFromPath() and CShellUrl::ParseFromOutsideSource() both
  409. // touch the disk which causes unconnected network cases to be really
  410. // slow.  This will create icons for file system paths w/o hitting
  411. // the disk.
  412. HRESULT CAddressList::_GetFastPathIcons(LPCTSTR pszPath, int *piImage, int *piSelectedImage)
  413. {
  414.     SHFILEINFO shFileInfo = {0};
  415.     // SHGetFileInfo() with those flags will be fast because it's won't filter out
  416.     // garbage passed to it.  So it will think URLs are actually relative paths
  417.     // and accept them.  We will fall back to the slow advanced parser which is still
  418.     // fast with URLs.
  419.     if (PathIsRelative(pszPath))
  420.         return E_FAIL;
  421.     HIMAGELIST himl = (HIMAGELIST) SHGetFileInfo(pszPath, FILE_ATTRIBUTE_DIRECTORY, &shFileInfo, sizeof(shFileInfo), (SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES));
  422.     if (!himl || !shFileInfo.iIcon)
  423.         return E_FAIL;
  424.     *piImage = shFileInfo.iIcon;
  425.     *piSelectedImage = shFileInfo.iIcon;
  426.     // I don't need to free himl.
  427.     return S_OK;
  428. }
  429. HRESULT CAddressList::_GetPidlIcon(LPCITEMIDLIST pidl, int *piImage, int *piSelectedImage)
  430. {
  431.     IShellFolder *psfParent;
  432.     LPCITEMIDLIST pidlChild;
  433.     HRESULT hr = IEBindToParentFolder(pidl, &psfParent, &pidlChild);
  434.     if (SUCCEEDED(hr))
  435.     {
  436.         *piImage = IEMapPIDLToSystemImageListIndex(psfParent, pidlChild, piSelectedImage);
  437.         psfParent->Release();
  438.     }
  439.     return hr;
  440. }
  441. LPITEMIDLIST CAddressList::_GetDragDropPidl(LPNMCBEDRAGBEGINW pnmcbe)
  442. {
  443.     LPITEMIDLIST pidl = NULL;
  444.     CShellUrl *psuUrl = new CShellUrl();
  445.     if (psuUrl)
  446.     {
  447.         // Set the parent for error messageboxes.  Note that this could end up disabing the taskbar.
  448.         // If this is deemed to be a problem we can first check to see where the addressbar is hosted.
  449.         psuUrl->SetMessageBoxParent(_hwnd);
  450.         HRESULT hr = SetDefaultShellPath(psuUrl);
  451.         if (SUCCEEDED(hr))
  452.         {
  453.             hr = psuUrl->ParseFromOutsideSource(pnmcbe->szText, SHURL_FLAGS_NOUI, NULL);
  454.             if (SUCCEEDED(hr))
  455.             {
  456.                 hr = psuUrl->GetPidl(&pidl);
  457.             }
  458.         }
  459.         delete psuUrl;
  460.     }
  461.     return pidl;
  462. }
  463. LRESULT CAddressList::_OnDragBeginA(LPNMCBEDRAGBEGINA pnmcbe)
  464. {
  465.     NMCBEDRAGBEGINW  nmcbew;
  466.     nmcbew.hdr = pnmcbe->hdr;
  467.     nmcbew.iItemid = pnmcbe->iItemid;
  468.     SHAnsiToUnicode(pnmcbe->szText, nmcbew.szText, SIZECHARS(nmcbew.szText));
  469.     return _OnDragBeginW(&nmcbew);
  470. }
  471. #ifdef UNIX
  472. extern "C" LPITEMIDLIST UnixUrlToPidl(UINT uiCP, LPCTSTR pszUrl, LPCWSTR pszLocation);
  473. #endif
  474. LRESULT CAddressList::_OnDragBeginW(LPNMCBEDRAGBEGINW pnmcbe)
  475. {
  476.     LPITEMIDLIST pidl = _GetDragDropPidl(pnmcbe);
  477. #ifdef UNIX
  478.     // for UNIX we fake a URL pidl so we create a .url instead of a .lnk
  479.     if (!IsURLChild(pidl, TRUE))
  480.     {
  481.         LPITEMIDLIST pidl1;
  482.         TCHAR szPath[MAX_PATH];
  483.         StrCpyN(szPath, TEXT("file://"), 8);
  484.         SHGetPathFromIDList(pidl, &szPath[7]);
  485.         pidl1 = UnixUrlToPidl(CP_ACP, szPath, NULL);
  486.         if (pidl1)
  487.     {
  488.             ILFree(pidl);
  489.             pidl = pidl1;
  490.         }
  491.     }
  492. #endif
  493.     if (pidl) 
  494.     {
  495.         IOleCommandTarget *pcmdt = NULL;
  496.         IUnknown *punk;
  497.         if (SUCCEEDED(_pbp->GetBrowserWindow(&punk)))
  498.         {
  499.             punk->QueryInterface(IID_IOleCommandTarget, (void **)&pcmdt);
  500.             punk->Release(); 
  501.         }
  502.         DoDragDropWithInternetShortcut(pcmdt, pidl, _hwnd);
  503.         if (pcmdt)
  504.             pcmdt->Release();
  505.         ILFree(pidl);
  506.     }
  507.     return 0;
  508. }
  509. // handle WM_NOTIFY messages.
  510. LRESULT CAddressList::_OnNotify(LPNMHDR pnm)
  511. {
  512.     LRESULT lReturn = 0;
  513.     switch (pnm->code)
  514.     {
  515.     case NM_SETCURSOR:
  516.         if (!SendMessage(_hwnd, CBEM_GETEXTENDEDSTYLE, 0, 0) & CBES_EX_NOEDITIMAGE)
  517.         {
  518.             RECT rc;
  519.             POINT pt;
  520.             int cx, cy;
  521.             GetCursorPos(&pt);
  522.             GetClientRect(_hwnd, &rc);
  523.             MapWindowRect(_hwnd, HWND_DESKTOP, &rc);
  524.             ImageList_GetIconSize((HIMAGELIST)SendMessage(_hwnd, CBEM_GETIMAGELIST, 0, 0), &cx, &cy);
  525.             rc.right = rc.left + cx + GetSystemMetrics(SM_CXEDGE);
  526.             if (PtInRect(&rc, pt)) 
  527.             {
  528.                 // this means there's an image, which means we can drag
  529.                 SetCursor(LoadHandCursor(0));
  530.                 return 1;
  531.             }
  532.         }
  533.         break;
  534.         case CBEN_DRAGBEGINA:
  535.             lReturn = _OnDragBeginA((LPNMCBEDRAGBEGINA)pnm);
  536.             break;
  537.         case CBEN_DRAGBEGINW:
  538.             lReturn = _OnDragBeginW((LPNMCBEDRAGBEGINW)pnm);
  539.             break;
  540.     }
  541.     return lReturn;
  542. }