home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / OWLSRC.PAK / SHELLITM.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  52.6 KB  |  1,647 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1995, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.20  $
  6. //
  7. // Implementations of the following Win95 Shell Classes:
  8. //    TPidl, TShellItem, and TShellItemIterator
  9. // The following clases are completely implemented in the header file:
  10. //    TShellMalloc, TExtractIcon, TContextMenu, TDataObject, TDropTarget
  11. //----------------------------------------------------------------------------
  12. #include <owl/pch.h>
  13. #if !defined(OWL_SHELLITM_H)
  14. # include <owl/shellitm.h>
  15. #endif
  16.  
  17. OWL_DIAGINFO;
  18. DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlShell, 1, 0);        // Shell Diagostic Group
  19.  
  20. //
  21. //  protected function used internally to free PIDL memory with the shell's allocator
  22. //
  23. void
  24. TPidl::FreePidl()
  25. {
  26.   if (Pidl) {
  27.     TShellMalloc malloc;
  28.     malloc->Free(Pidl);
  29.     Pidl = 0;
  30.   }
  31. }
  32.  
  33. //
  34. // GetItemCount returns the number of identifiers in the
  35. // identifier list (pidl)
  36. //
  37. long
  38. TPidl::GetItemCount() const
  39. {
  40.   long cnt = 0;
  41.  
  42.   if (Pidl) {
  43.     ITEMIDLIST* pidl = Pidl;
  44.     while (pidl->mkid.cb) {
  45.       cnt++;
  46.       pidl = Next(pidl);
  47.     }
  48.   }
  49.   return cnt;
  50. }
  51.  
  52. //
  53. // GetSize returns the size (in bytes) of the PIDL
  54. //
  55. ulong
  56. TPidl::GetSize() const
  57. {
  58.   long size = sizeof(Pidl->mkid.cb);
  59.   ITEMIDLIST* pidl = Pidl;
  60.   while (pidl->mkid.cb) {
  61.     size += pidl->mkid.cb;
  62.     pidl = Next(pidl);
  63.   }
  64.   return size;
  65. }
  66.  
  67. //
  68. // CopyPidl copies a pidl (allocates memory with the shell's allocator)
  69. //
  70. ITEMIDLIST*
  71. TPidl::CopyPidl() const
  72. {
  73.   if (!Pidl)
  74.     return 0;
  75.   else {
  76.     ITEMIDLIST* newPidl;
  77.     TShellMalloc malloc;
  78.     newPidl = REINTERPRET_CAST(ITEMIDLIST*, malloc->Alloc(GetSize()));
  79.     WARNX(OwlShell, !newPidl, 0, \
  80.          "IShellMalloc::Alloc failed.  IShellMalloc* = "\
  81.           << hex << STATIC_CAST(IMalloc*, malloc));
  82.     if (!newPidl)
  83.       TXShell::Raise(IDS_SHELLALLOCFAIL);
  84.     ITEMIDLIST* pidlSrc = Pidl;
  85.     ITEMIDLIST* pidlDest = newPidl;
  86.     while (pidlSrc->mkid.cb) {
  87.       CopyMemory(pidlDest, pidlSrc, pidlSrc->mkid.cb);
  88.       pidlDest = Next(pidlDest);
  89.       pidlSrc = Next(pidlSrc);
  90.     }
  91.     ushort zero = 0;
  92.     CopyMemory(pidlDest, &zero, sizeof(ushort));
  93.     return newPidl;
  94.   }
  95. }
  96.  
  97. //
  98. // GetLastItem returns the last item in an identifier list
  99. // for file system items, this is the rightmost part of a path
  100. // e.g., GetLastItem() on a pidl representing
  101. //       "c:\\dir1\\dir2\\dir3\\file1") returns "file1"
  102. //
  103. TPidl
  104. TPidl::GetLastItem() const
  105. {
  106.   if (!Pidl)
  107.     return TPidl();
  108.   else {
  109.     long cnt = GetItemCount();
  110.     ITEMIDLIST* pidl = Pidl;
  111.     for (int i = 0; i < cnt - 1; i++)
  112.       pidl = Next(pidl);
  113.     ITEMIDLIST* newPidl;
  114.     TShellMalloc malloc;
  115.     newPidl = REINTERPRET_CAST(ITEMIDLIST*,
  116.                                malloc->Alloc(pidl->mkid.cb + sizeof (pidl->mkid.cb)));
  117.     WARNX(OwlShell, !newPidl, 0, "IShellMalloc::Alloc failed.  IShellMalloc* = "
  118.           << hex << STATIC_CAST(IMalloc*, malloc));
  119.     if (!newPidl)
  120.       TXShell::Raise(IDS_SHELLALLOCFAIL);
  121.  
  122.     CopyMemory(newPidl, pidl, pidl->mkid.cb);
  123.     ITEMIDLIST* pidlDest = Next(newPidl);
  124.     USHORT zero = 0;
  125.     CopyMemory(pidlDest, &zero, sizeof (USHORT));
  126.     return newPidl;
  127.   }
  128. }
  129.  
  130. //
  131. // StripLastItem returns a pidl stipped of its last (rightmost) item
  132. //
  133. TPidl
  134. TPidl::StripLastItem() const
  135. {
  136.   int i;
  137.   if (!Pidl)
  138.     return TPidl();
  139.   else {
  140.     // calculate the size less the last item id
  141.     long cnt = GetItemCount();
  142.     if (cnt < 2)
  143.       return TPidl();
  144.     long size = sizeof(Pidl->mkid.cb);
  145.     ITEMIDLIST* pidl = Pidl;
  146.     for (i = 0; i < cnt - 1; i++) {
  147.       size += pidl->mkid.cb;
  148.                 pidl = Next(pidl);
  149.     }
  150.     ITEMIDLIST* newPidl;
  151.     TShellMalloc malloc;
  152.     newPidl = REINTERPRET_CAST(ITEMIDLIST*, malloc->Alloc(size));
  153.     WARNX(OwlShell, !newPidl, 0, "IShellMalloc::Alloc failed.  IShellMalloc* = "
  154.           << hex << STATIC_CAST(IMalloc*, malloc));
  155.     if (!newPidl)
  156.       TXShell::Raise(IDS_SHELLALLOCFAIL);
  157.     ITEMIDLIST* pidlSrc = Pidl;
  158.     ITEMIDLIST* pidlDest = newPidl;
  159.     for (i = 0; i < cnt - 1; i++) {
  160.       CopyMemory(pidlDest, pidlSrc, pidlSrc->mkid.cb);
  161.       pidlDest = Next(pidlDest);
  162.       pidlSrc = Next(pidlSrc);
  163.     }
  164.     USHORT zero = 0;
  165.     CopyMemory(pidlDest, &zero, sizeof (USHORT));
  166.  
  167.     return newPidl;
  168.   }
  169. }
  170.  
  171. // TShellItem constructor to make a TShellItem for a file or directory in the file system.
  172. // If the throwOnInvalidPath argument is true, an exception will be raised if the path is
  173. // not valid or if the file or directory does not exist.  If this argument is false, no
  174. // exception will be raised and the Valid() function should be called to make sure it
  175. // returns true.  If Valid() returns false, the TShellItem does not represent a object
  176. // in the shell namespace.
  177. //
  178. TShellItem::TShellItem(const char* path, bool throwOnInvalidPath, HWND windowOwner)
  179.            :TComRef<IShellFolder>(0), Pidl(0), ParentFolder(0)
  180. {
  181.   TShellItem desktop(TShellItem::Desktop, windowOwner);
  182.  
  183.   TCreateStruct cs;
  184.   ulong eaten;
  185.   HRESULT hr = desktop.ParseDisplayName(cs, path, &eaten, windowOwner);
  186.   WARNX(OwlShell, FAILED(hr), 0, "Invalid path.  Path = " << path);
  187.   if (FAILED(hr))
  188.     if (throwOnInvalidPath)
  189.       TXShell::Raise(IDS_INVALIDPATH);
  190.     else
  191.       return;
  192.  
  193.   Pidl = cs.Pidl.GetLastItem();
  194.  
  195.   hr = desktop->BindToObject(cs.Pidl.StripLastItem(), 0, IID_IShellFolder,
  196.                              REINTERPRET_CAST(void **,
  197.                              STATIC_CAST(IShellFolder**, ParentFolder)));
  198.   WARNX(OwlShell, FAILED(hr), 0, "IShellFolder::BindToObject failed.  TShellItem* = "
  199.         << hex << (LPVOID)this << "  IShellFolder* = "
  200.         << STATIC_CAST(IShellFolder*, ParentFolder));
  201.   TXShell::Check(hr, IDS_BINDTOOBJECTFAIL);
  202. }
  203.  
  204. //
  205. //  TShellItem constructor to make a TShellItem for a special folder.  Special
  206. //  folders can be any specified in the TSpecialFolderKind enum.
  207. //
  208. //  (see MS doc for SHGetSpecialFolderLocation for more information,
  209. //  Programmer's Guide to MS Windows 95, MS Press, p. 209)
  210. //
  211. TShellItem::TShellItem(const TSpecialFolderKind kind, HWND windowOwner)
  212.            :TComRef<IShellFolder>(0), Pidl(0), ParentFolder(0)
  213. {
  214.   IShellFolder* desktop;
  215.   HRESULT hr = ::SHGetDesktopFolder(&desktop);
  216.   WARNX(OwlShell, FAILED(hr), 0, "::SHGetDesktopFolder failed.");
  217.   TXShell::Check(hr, IDS_SHGETDESKTOPFAIL);
  218.  
  219.   TPidl pidl;
  220.   hr = ::SHGetSpecialFolderLocation(windowOwner, kind, pidl);
  221.   WARNX(OwlShell, FAILED(hr), 0, \
  222.         "::SHGetSpecialFolderLocation failed.  kind = " << kind);
  223.   TXShell::Check(hr, IDS_SHGETSPECIALFAIL);
  224.   if (kind == Desktop) {
  225.     I = desktop;       // Gets itself for the ParentFolder below
  226.     I->AddRef();
  227.   }
  228.   else {
  229.     hr = desktop->BindToObject(pidl, 0, IID_IShellFolder,
  230.                                REINTERPRET_CAST(void **, STATIC_CAST(IShellFolder**, *this)));
  231.     WARNX(OwlShell, FAILED(hr), 0, "IShellFolder::BindToObject failed.  Desktop IShellFolder* = "
  232.           << hex << STATIC_CAST(IShellFolder*, desktop));
  233.     TXShell::Check(hr, IDS_BINDTOOBJECTFAIL);
  234.   }
  235.  
  236.   ParentFolder = desktop;  // It's not clearly documented but we're assuming
  237.   Pidl = pidl;             // that all special folders are children of the
  238. }                          // desktop/root.
  239.  
  240. //
  241. //  TShellItem constructor to make a TShellItem from a TCreateStruct
  242. //
  243. //  TCreateStruct contains a TPidl and a
  244. //    TComRef<IShellFolder>ParentFolder which represents the parent folder
  245. //
  246. //  TCreateStructs are returned by TShellItem::GetParentFolder() and by the
  247. //    following TShellItemIterator functions:
  248. //      operator ++(pre- &post-fix), operator -- (pre- & post-fix), operator [](),
  249. //      and Current()
  250. //
  251. //  TCreateStructs are also returned as out parameters of the following TShellItem
  252. //    functions:
  253. //      BrowseForFolder(), ParseDisplayName()
  254. //
  255. TShellItem::TShellItem(const TCreateStruct& cs)
  256.            :TComRef<IShellFolder>(0), Pidl(cs.Pidl),
  257.             ParentFolder(cs.ParentFolder)
  258. {
  259. }
  260.  
  261. //
  262. //  TShellIterm constructor to make a TShellItem from a ITEMIDLIST(pidl) and a
  263. //    TComRef<IShellFolder> (parent folder)
  264. //
  265. //
  266. TShellItem::TShellItem(ITEMIDLIST* pidl, const TComRef<IShellFolder>& parentFolder)
  267.            :TComRef<IShellFolder>(0), Pidl(pidl), ParentFolder(parentFolder)
  268. {
  269. }
  270.  
  271. //
  272. //  TShellItem constructor to make a TShellItem from a TPidl and a
  273. //    TComRef<IShellFolder> (parent folder)
  274. //
  275. TShellItem::TShellItem(const TPidl& pidl, const TComRef<IShellFolder>& parentFolder)
  276.            :TComRef<IShellFolder>(0), Pidl(pidl), ParentFolder(parentFolder)
  277. {
  278. }
  279.  
  280. //
  281. //  TShellItem copy constructor
  282. //
  283. TShellItem::TShellItem(const TShellItem& source)
  284.            :TComRef<IShellFolder>(source), Pidl(source.Pidl),
  285.             ParentFolder(source.ParentFolder)
  286. {
  287. }
  288.  
  289. //
  290. // TShellItem assignment (from another TShellItem)
  291. //
  292. TShellItem& TShellItem::operator = (const TShellItem &source)
  293. {
  294.   if (&source != this) {
  295.     TComRef<IShellFolder>::operator=(source);
  296.     Pidl = source.Pidl;
  297.     ParentFolder = source.ParentFolder;
  298.   }
  299.   return *this;
  300. }
  301.  
  302. //
  303. // TShellItem assignment (from a TCreateStruct)
  304. //
  305. TShellItem& TShellItem::operator = (const TCreateStruct& cs)
  306. {
  307.   Clear();
  308.   Pidl = cs.Pidl;
  309.   ParentFolder = cs.ParentFolder;
  310.   return *this;
  311. }
  312.  
  313. //
  314. //  GetAttributes gets Capabilities, Display, Contents, & Misc. Attributes
  315. //    with a single call
  316. //
  317. //  'validateCachedInfo' defaults to false.  If true, the shell will not
  318. //   rely on cached information.
  319. //
  320. //  See MS doc for IShellFolder::GetAttributesOf for more information, Programmer's
  321. //    Guide to MS Windows 95, MS Press, pp. 194-195.
  322. //
  323. ulong
  324. TShellItem::GetAttributes(const ulong reqAttrib, const bool validateCachedInfo) const
  325. {
  326.   EnforceValidity();
  327.   ulong req = reqAttrib | ((validateCachedInfo)? SFGAO_VALIDATE: 0);
  328.   HRESULT hr = ParentFolder->GetAttributesOf(1, Pidl, &req);
  329.   WARNX(OwlShell, FAILED(hr), 0, "IShellFolder::GetAttributesOf failed.  TShellItem* = "
  330.         << hex << (LPVOID)this << "  Parent IShellFolder* = "
  331.         << STATIC_CAST(IShellFolder*, *CONST_CAST(TComRef<IShellFolder>*, &ParentFolder)));
  332.   TXShell::Check(hr, IDS_GETATTRIBUTESOFFAIL);
  333.   return req;
  334. }
  335.  
  336. //
  337. //  GetAttribute is a protected function used by all the attribute functions except
  338. //    IsDesktop.
  339. //
  340. //  Note:  GetAttribute gets attributes one at a time.  GetAttributes (with the 's')
  341. //    is used to get any number of attributes with one call.
  342. //
  343. bool
  344. TShellItem::GetAttribute(const TAttribute at, const bool validateCachedInfo) const
  345. {
  346.   EnforceValidity();
  347.   ulong req = at;
  348.   req = GetAttributes(req, validateCachedInfo);
  349.   return (req & at);
  350. }
  351.  
  352. // Attributes - Additional (Not part of GetAttributes)
  353.  
  354. //
  355. //  IsDesktop returns true if the TShellItem respresents the shell's desktop.
  356. //
  357. bool
  358. TShellItem::IsDesktop() const
  359. {
  360.   EnforceValidity();
  361.   TShellItem desktop(Desktop);
  362.   return (I == desktop.I);
  363. }
  364.  
  365. //
  366. //  GetParentFolder returns a TCreateStruct representing the folder which contains
  367. //  the TShellItem.
  368. //
  369. TShellItem::TCreateStruct
  370. TShellItem::GetParentFolder() const
  371. {
  372.   EnforceValidity();
  373.   TCreateStruct cs;
  374.  
  375.   if (IsDesktop()) {
  376.     cs.Pidl = Pidl;                           // return self
  377.     cs.ParentFolder = ParentFolder;           // ParentFolder is itself too
  378.   }
  379.   else {
  380.     TShellItem desktop(Desktop);
  381.     TPidl newFullPidl = GetFullyQualifiedPidl().StripLastItem();
  382.     cs.Pidl = newFullPidl.GetLastItem();
  383.     HRESULT hr = desktop->BindToObject(newFullPidl.StripLastItem(), 0, IID_IShellFolder,
  384.           REINTERPRET_CAST(void **, STATIC_CAST(IShellFolder**, cs.ParentFolder)));
  385.     WARNX(OwlShell, FAILED(hr), 0, "IShellFolder::BindToObject failed.  TShellItem* = "
  386.           << hex << (LPVOID)this << "  Parent ITEMIDLIST* = "
  387.           << STATIC_CAST(ITEMIDLIST*, newFullPidl.StripLastItem()));
  388.     TXShell::Check(hr, IDS_BINDTOOBJECTFAIL);
  389.   }
  390.  
  391.   return cs;
  392. }
  393.  
  394. //
  395. //  GetFullyQualifiedPidl returns a TPidl that is fully qualified (from the desktop).
  396. //
  397. TPidl
  398. TShellItem::GetFullyQualifiedPidl() const
  399. {
  400.   EnforceValidity();
  401.   TString name = GetDisplayName(ForParsing);
  402.   TShellItem desktop(Desktop);
  403.   TCreateStruct cs;
  404.   desktop.ParseDisplayName(cs, name);
  405.   return cs.Pidl;
  406. }
  407.  
  408. //
  409. //  GetExeType returns the type of executable that is contained in the TShellItem
  410. //    Also, the optional major and minor args return version numbers
  411. //    e.g., return = WindowsPE, major = 4, minor = 0
  412. //
  413. //  See MS doc for SHGetFileInfo for more information, Programmer's Guide to MS
  414. //    Windows 95, MS Press, pp. 205-207.
  415. //
  416. TShellItem::TExeKind
  417. TShellItem::GetExeType(uint* major, uint* minor) const
  418. {
  419.   EnforceValidity();
  420.  
  421.   if (!IsPartOfFileSystem() || IsFolder() || ContainsSubFolder())
  422.     return NonExecutable;
  423.  
  424.   DWORD rc = ::SHGetFileInfo(GetPath(), 0, 0, 0, SHGFI_EXETYPE);
  425.  
  426.   short exeType = LOWORD(rc);
  427.   const char* charType = REINTERPRET_CAST(const char*, &exeType);
  428.  
  429.   if (major)
  430.     *major = HIBYTE(HIWORD(rc));
  431.   if (minor)
  432.     *minor = LOBYTE(HIWORD(rc));
  433.  
  434.   WARNX(OwlShell,
  435.         rc && ::strncmp("PE", charType, 2) && ::strncmp("NE", charType, 2) && ::strncmp("MZ", charType, 2),
  436.         0, "::GetFileInfo returned an invalid exeType.  exeType = " << exeType);
  437.  
  438.   if (!rc)
  439.     return NonExecutable;
  440.   else if (!::strncmp("PE", charType, 2))
  441.     return (HIWORD(rc))? WindowsPE: Win32Console;
  442.   else if (!::strncmp("NE", charType, 2))
  443.     return WindowsNE;
  444.   else if (!::strncmp("MZ", charType, 2))
  445.     return MSDOS;
  446.   else
  447.     TXShell::Raise(IDS_GETFILEINFOFAIL);
  448.  
  449.   return NonExecutable;     // To satisfy compiler
  450. }
  451.  
  452. //
  453. //  GetTypeName returns the type of item that is represented by this TShellItem
  454. //    examples:  application, notepad file, ...
  455. //
  456. //  See MS doc for SHGetFileInfo for more information, Programmer's Guide to MS
  457. //    Windows 95, MS Press, pp. 205-207.
  458. //
  459. TString
  460. TShellItem::GetTypeName() const
  461. {
  462.   EnforceValidity();
  463.   TString typeName;
  464.   SHFILEINFO fi;
  465.  
  466.   DWORD rc = ::SHGetFileInfo(
  467.     REINTERPRET_CAST(const char*, STATIC_CAST(ITEMIDLIST*, *CONST_CAST(TShellItem*, this))),
  468.     0, &fi, sizeof (fi), SHGFI_TYPENAME | SHGFI_PIDL);
  469.   WARNX(OwlShell, !rc, 0, "::GetFileInfo failed.  TShellItem = " << GetDisplayName());
  470.   if (!rc)
  471.     TXShell::Raise(IDS_GETFILEINFOFAIL);
  472.   typeName = fi.szTypeName;
  473.   return typeName;
  474. }
  475.  
  476. //
  477. //  GetDisplayName returns a name for this TShellItem that is suitable to display
  478. //    to the user.
  479. //
  480. //  The three options are:
  481. //
  482. //    Normal      - Suitable for displaying by itself
  483. //    InFolder    - Suitable for displaying within its parent folder
  484. //    ForParsing  - Suitable to pass to the ParseDiplayName member function
  485. //
  486. //  See MS doc for IShellFolder::GetDisplayNameOf for more information,
  487. //    Programmer's Guide to MS Windows 95, MS Press, pp. 197-198.
  488. //
  489. TString
  490. TShellItem::GetDisplayName(const TDisplayNameKind kind) const
  491. {
  492.   EnforceValidity();
  493.   TString s;
  494.   STRRET strRet;
  495.  
  496.   strRet.uType = STRRET_WSTR;
  497.   HRESULT hr = ParentFolder->GetDisplayNameOf(Pidl, kind, &strRet);
  498.   WARNX(OwlShell, FAILED(hr), 0, "IShellFolder::GetDisplayNameOf failed.  TShellItem* = "
  499.         << hex << (LPVOID)this);
  500.   TXShell::Check(hr, IDS_GETDISPLAYNAMEFAIL);
  501.  
  502.   switch (strRet.uType) {
  503.     case STRRET_WSTR:   // Case requested
  504.       s = strRet.pOleStr;
  505.       ::SysFreeString(strRet.pOleStr);
  506.       break;
  507.     case STRRET_CSTR:   // C-string
  508.       s = strRet.cStr;
  509.       break;
  510.     case STRRET_OFFSET: // Offset into the piddle
  511.       s = REINTERPRET_CAST(char *, STATIC_CAST(ITEMIDLIST*, Pidl)) + strRet.uOffset;
  512.       break;
  513.     }
  514.  
  515.   return s;
  516. }
  517.  
  518. //
  519. //  GetPath returns the fully qualified path representing this TShellItem
  520. //
  521. TString
  522. TShellItem::GetPath() const
  523. {
  524.   char path[_MAX_PATH];
  525.  
  526.   bool success = ::SHGetPathFromIDList(GetFullyQualifiedPidl(), path);
  527.   WARNX(OwlShell, !success, 0, "::SHGetPathFromIDList failed.  TShellItem* = "
  528.         << hex << (LPVOID)this);
  529.   if (!success)
  530.     TXShell::Raise(IDS_GETPATHFROMPIDLFAIL);
  531.  
  532.   TString s;
  533.   s = path;
  534.   return s;
  535. }
  536.  
  537. //
  538. //  Rename renames this TShellItem to newName.
  539. //
  540. //  kind indicates the kind of name being passed (Normal, InFolder, or ForParsing)
  541. //    (see GetDisplayName for description of these)
  542. //
  543. //  See MS doc for IShellFolder::SetNameOf for more information, Programmer's
  544. //    Guide to MS Windows 95, MS Press, pp. 198-199.
  545. //
  546. void
  547. TShellItem::Rename(const char *newName, HWND windowOwner, const TDisplayNameKind kind)
  548. {
  549.   LPITEMIDLIST pidl;
  550.  
  551.   if (!CanBeRenamed())
  552.     TXShell::Raise(IDS_SHELLRENAMEFAIL);
  553.  
  554.   // This stuff needed for ::SHChangeNotify
  555.   bool isFolder = IsFolder();
  556.   char oldPath[_MAX_PATH];
  557.   ::memset(oldPath, 0, sizeof (oldPath));
  558.   strcpy(oldPath, GetDisplayName(ForParsing));
  559.   TShellItem parentFolder = GetParentFolder();
  560.   char newPath[_MAX_PATH];
  561.   ::memset(newPath, 0, sizeof (newPath));
  562.   ::strcpy(newPath, parentFolder.GetDisplayName(ForParsing));
  563.   ::strcat(newPath, newName);
  564.  
  565.   HRESULT hr = ParentFolder->SetNameOf(windowOwner, Pidl, TString(newName), kind, &pidl);
  566.   WARNX(OwlShell, FAILED(hr), 0, "IShellFolder::SetNameOf failed.  TShellItem* = "
  567.         << hex << (LPVOID)this << "  Parent IShellFolder* = "
  568.         << STATIC_CAST(IShellFolder*, ParentFolder));
  569.   TXShell::Check(hr, IDS_SETNAMEOFFAIL);
  570.   Pidl = pidl;
  571.  
  572.   ::SHChangeNotify(isFolder? SHCNE_RENAMEFOLDER: SHCNE_RENAMEITEM,
  573.                    SHCNF_PATH /*| SHCNF_FLUSH*/, STATIC_CAST(const char*, oldPath),
  574.                    newPath);
  575. }
  576.  
  577. //
  578. //  Copy copies this TShellItem to destination path
  579. //
  580. //  destIsFolder must tell whether or not dest is a folder
  581. //
  582. //  flags are any combination of TFileOpFlags
  583. //    (see MS doc for SHFILEOPSTRUCT for meanings of these flags,
  584. //    Programmer's Guide to MS Windows 95, MS Press, p. 215)
  585. //
  586. //  Title is the title displayed in the progress dialog box
  587. //
  588. //  windowOwner should be set to the owner of the progress dialog box
  589. //
  590. //  See MS doc for SHFileOperation for more information, Programmer's Guide to
  591. //    MS Windows 95, MS Press, p. 204.
  592. //
  593. bool
  594. TShellItem::Copy(const char* dest, const bool destIsFolder,
  595.                  const USHORT flags, const char* title,
  596.                  HWND windowOwner) const
  597. {
  598.   EnforceValidity();
  599.   SHFILEOPSTRUCT fo;
  600.  
  601.   if (!CanBeCopied())
  602.     TXShell::Raise(IDS_SHELLCOPYFAIL);
  603.  
  604.   fo.hwnd = windowOwner;
  605.   fo.wFunc = FO_COPY;
  606.   char srcPath[_MAX_PATH];
  607.   ::memset(srcPath, 0, sizeof (srcPath));
  608.   strcpy(srcPath, GetDisplayName(ForParsing));
  609.   fo.pFrom = srcPath;
  610.   char destPath[_MAX_PATH];
  611.   ::memset(destPath, 0, sizeof (destPath));
  612.   strcpy(destPath, dest);
  613.   fo.pTo = destPath;
  614.   fo.fFlags = flags;
  615.   fo.fAnyOperationsAborted = FALSE;
  616.   fo.hNameMappings = 0;
  617.   fo.lpszProgressTitle = title;
  618.  
  619.   if (!destIsFolder)
  620.     fo.fFlags |= FOF_MULTIDESTFILES; // Destination is a filename, not a folder
  621.  
  622.   bool isFolder = IsFolder();
  623.  
  624.   int rc = ::SHFileOperation(&fo);
  625.  
  626.   if (rc || fo.fAnyOperationsAborted)
  627.     return false;
  628.  
  629.   ::SHChangeNotify(isFolder? SHCNE_MKDIR: SHCNE_CREATE, SHCNF_PATH /*| SHCNF_FLUSH*/,
  630.                    STATIC_CAST(const char*, GetDisplayName(ForParsing)), 0);
  631.   return true;
  632. }
  633.  
  634. //
  635. //  Copy copies this TShellItem to destination TShellItem
  636. //
  637. //  flags are any combination of TFileOpFlags
  638. //    (see MS doc for SHFILEOPSTRUCT for meanings of these flags,
  639. //    Programmer's Guide to MS Windows 95, MS Press, p. 215)
  640. //
  641. //  Title is the title displayed in the progress dialog box
  642. //
  643. //  windowOwner should be set to the owner of the progress dialog box
  644. //
  645. //  See MS doc for SHFileOperation for more information, Programmer's Guide to
  646. //    MS Windows 95, MS Press, p. 204.
  647. //
  648. bool
  649. TShellItem::Copy(const TShellItem& dest, const USHORT flags, const char* title,
  650.                  HWND windowOwner) const
  651. {
  652.   return Copy(dest.GetDisplayName(ForParsing), dest.IsFolder(), flags, title, windowOwner);
  653. }
  654.  
  655. //
  656. //  Move moves this TShellItem to destination path (which must be a folder)
  657. //
  658. //  flags are any combination of TFileOpFlags
  659. //    (see MS doc for SHFILEOPSTRUCT for meanings of these flags,
  660. //    Programmer's Guide to MS Windows 95, MS Press, p. 215)
  661. //
  662. //  Title is the title displayed in the progress dialog box
  663. //
  664. //  windowOwner should be set to the owner of the progress dialog box
  665. //
  666. //  See MS doc for SHFileOperation for more information, Programmer's Guide to
  667. //    MS Windows 95, MS Press, p. 204.
  668. //
  669. bool
  670. TShellItem::Move(const char* destFolder, const USHORT flags, const char* title,
  671.                  HWND windowOwner)
  672. {
  673.   EnforceValidity();
  674.   SHFILEOPSTRUCT fo;
  675.  
  676.   if (!CanBeMoved())
  677.     TXShell::Raise(IDS_SHELLMOVEFAIL);
  678.  
  679.   fo.hwnd = windowOwner;
  680.   fo.wFunc = FO_MOVE;
  681.  
  682.   char oldPath[_MAX_PATH];
  683.   ::memset(oldPath, 0, sizeof (oldPath));
  684.   strcpy(oldPath, GetDisplayName(ForParsing));
  685.   fo.pFrom = oldPath;
  686.   char destPath[_MAX_PATH];
  687.   ::memset(destPath, 0, sizeof (destPath));
  688.   strcpy(destPath, destFolder);
  689.   fo.pTo = destPath;
  690.   fo.fFlags = flags;
  691.   fo.fAnyOperationsAborted = FALSE;
  692.   fo.hNameMappings = 0;
  693.   fo.lpszProgressTitle = title;
  694.  
  695.   bool isFolder = IsFolder();
  696.  
  697.   int rc = ::SHFileOperation(&fo);
  698.  
  699.   if (rc || fo.fAnyOperationsAborted)
  700.     return false;
  701.  
  702.   char newPath[_MAX_PATH];
  703.   ::strcpy(newPath, destFolder);
  704.   if (newPath[::strlen(newPath)-1] != '\\')
  705.     ::strcat(newPath, "\\");
  706.   ::strcat(newPath, GetDisplayName());
  707.   *this = TShellItem(newPath);              // change myself to the new location
  708.  
  709.   // Notify deletion of old path
  710.   ::SHChangeNotify(isFolder? SHCNE_RMDIR: SHCNE_DELETE, SHCNF_PATH /*| SHCNF_FLUSH*/,
  711.                    STATIC_CAST(const char*, oldPath), 0);
  712.   // Notify creation of new path
  713.   ::SHChangeNotify(isFolder? SHCNE_MKDIR: SHCNE_CREATE, SHCNF_PATH /*| SHCNF_FLUSH*/,
  714.                    STATIC_CAST(const char*, GetDisplayName(ForParsing)), 0);
  715.  
  716.   return true;
  717. }
  718.  
  719. //
  720. //  Move moves this TShellItem to destination TShellItem (which must be a folder)
  721. //
  722. //  flags are any combination of TFileOpFlags
  723. //    (see MS doc for SHFILEOPSTRUCT for meanings of these flags,
  724. //    Programmer's Guide to MS Windows 95, MS Press, p. 215)
  725. //
  726. //  Title is the title displayed in the progress dialog box
  727. //
  728. //  windowOwner should be set to the owner of the progress dialog box
  729. //
  730. //  See MS doc for SHFileOperation for more information, Programmer's Guide to
  731. //    MS Windows 95, MS Press, p. 204.
  732. //
  733. bool
  734. TShellItem::Move(const TShellItem& destFolder, const USHORT flags,
  735.                  const char* title, HWND windowOwner)
  736. {
  737.   return Move(destFolder.GetDisplayName(ForParsing), flags, title, windowOwner);
  738. }
  739.  
  740. //
  741. //  Delete deletes this TShellItem
  742. //
  743. //  flags are any combination of TFileOpFlags
  744. //    (see MS doc for SHFILEOPSTRUCT for meanings of these flags,
  745. //    Programmer's Guide to MS Windows 95, MS Press, p. 215)
  746. //
  747. //  Title is the title displayed in the progress dialog box
  748. //
  749. //  windowOwner should be set to the owner of the progress dialog box
  750. //
  751. //  See MS doc for SHFileOperation for more information, Programmer's Guide to
  752. //    MS Windows 95, MS Press, p. 204.
  753. //
  754. bool
  755. TShellItem::Delete(const USHORT flags, const char* title, HWND windowOwner)
  756. {
  757.   EnforceValidity();
  758.   if (!Pidl)           // Nothing to delete!
  759.     return true;
  760.  
  761.   if (!CanBeDeleted())
  762.     TXShell::Raise(IDS_SHELLDELETEFAIL);
  763.  
  764.   SHFILEOPSTRUCT fo;
  765.   fo.hwnd = windowOwner;
  766.   fo.wFunc = FO_DELETE;
  767.   char path[_MAX_PATH];
  768.   ::memset(path, 0, sizeof (path));
  769.   strcpy(path, GetDisplayName(ForParsing)); // Also used to reconstruct if delete fails/user aborts
  770.   fo.pFrom = path;
  771.   fo.pTo = 0;
  772.   fo.fFlags = flags;
  773.   fo.fAnyOperationsAborted = FALSE;
  774.   fo.hNameMappings = 0;
  775.   fo.lpszProgressTitle = title;
  776.  
  777.   bool isFolder = IsFolder();               // Needed for ::SHChangeNotify
  778.  
  779.   // About to delete: save and release everything
  780.   //
  781.   TComRef<IShellFolder>::operator=(0);
  782.   Pidl = 0;
  783.   ParentFolder = 0;
  784.  
  785.   int rc = ::SHFileOperation(&fo);
  786.   if (rc || fo.fAnyOperationsAborted) {
  787.     *this = TShellItem(path);  // restore everything
  788.     return false;
  789.   }
  790.  
  791.   ::SHChangeNotify(isFolder? SHCNE_RMDIR: SHCNE_DELETE, SHCNF_PATH /*| SHCNF_FLUSH*/,
  792.                    path, 0);
  793.  
  794.   return true;
  795. }
  796.  
  797. //
  798. //  GetExtractIcon returns an interface pointer to this TShellItem's IExtractIcon
  799. //    OLE interface
  800. //
  801. //    (see MS doc for information on IExtractIcon,
  802. //    Programmer's Guide to MS Windows 95, MS Press, pp. 242-244)
  803. //
  804. TExtractIcon
  805. TShellItem::GetExtractIcon(HWND windowOwner)
  806. {
  807.   EnforceValidity();
  808.   IExtractIcon* iface;
  809.   HRESULT hr = ParentFolder->GetUIObjectOf(windowOwner, 1, Pidl, IID_IExtractIcon,
  810.                                            0, REINTERPRET_CAST(void**, &iface));
  811.   WARNX(OwlShell, FAILED(hr), 0, "IShellFolder::GetUIObjectOf(IExtractIcon) "
  812.         << "failed.  TShellItem* = "
  813.         << hex << (LPVOID)this << "  Parent IShellFolder* = "
  814.         << STATIC_CAST(IShellFolder*, ParentFolder));
  815.   TXShell::Check(hr, IDS_GETUIOBJECTOFFAIL);
  816.   return TExtractIcon(iface);
  817. }
  818.  
  819. //
  820. //  GetContextMenu returns an interface pointer to this TShellItem's IContextMenu
  821. //    OLE interface
  822. //
  823. //    (see MS doc for information on IContextMenu,
  824. //    Programmer's Guide to MS Windows 95, MS Press, pp. 237-240)
  825. //
  826. TContextMenu
  827. TShellItem::GetContextMenu(HWND windowOwner)
  828. {
  829.   EnforceValidity();
  830.   IContextMenu* iface;
  831.   HRESULT hr = ParentFolder->GetUIObjectOf(windowOwner, 1, Pidl, IID_IContextMenu,
  832.                                            0, REINTERPRET_CAST(void**, &iface));
  833.   WARNX(OwlShell, FAILED(hr), 0, "IShellFolder::GetUIObjectOf(IContextMenu) "
  834.         << "failed.  TShellItem* = "
  835.         << hex << (LPVOID)this << "  Parent IShellFolder* = "
  836.         << STATIC_CAST(IShellFolder*, ParentFolder));
  837.   TXShell::Check(hr, IDS_GETUIOBJECTOFFAIL);
  838.   return TContextMenu(iface);
  839. }
  840.  
  841. //
  842. //  GetDataObject returns an interface pointer to this TShellItem's IDataObject
  843. //    OLE interface
  844. //
  845. //    (see MS doc for a very brief description of IDataObject,
  846. //    Programmer's Guide to MS Windows 95, MS Press, p. 113)
  847. //
  848. TDataObject
  849. TShellItem::GetDataObject(HWND windowOwner)
  850. {
  851.   EnforceValidity();
  852.   IDataObject* iface;
  853.   HRESULT hr = ParentFolder->GetUIObjectOf(windowOwner, 1, Pidl, IID_IDataObject,
  854.                                            0, REINTERPRET_CAST(void**, &iface));
  855.   WARNX(OwlShell, FAILED(hr), 0, "IShellFolder::GetUIObjectOf(IDataObject) "
  856.         << "failed.  TShellItem* = "
  857.         << hex << (LPVOID)this << "  Parent IShellFolder* = "
  858.         << STATIC_CAST(IShellFolder*, ParentFolder));
  859.   TXShell::Check(hr, IDS_GETUIOBJECTOFFAIL);
  860.   return TDataObject(iface);
  861. }
  862.  
  863. //
  864. //  GetDropTarget returns an interface pointer to this TShellItem's IDropTarget
  865. //    OLE interface
  866. //
  867. TDropTarget
  868. TShellItem::GetDropTarget(HWND windowOwner)
  869. {
  870.   EnforceValidity();
  871.   IDropTarget* iface;
  872.   HRESULT hr = ParentFolder->GetUIObjectOf(windowOwner, 1, Pidl, IID_IDropTarget,
  873.                                            0, REINTERPRET_CAST(void**, &iface));
  874.   WARNX(OwlShell, FAILED(hr), 0, "IShellFolder::GetUIObjectOf(IDropTarget) "
  875.         << "failed.  TShellItem* = "
  876.         << hex << (LPVOID)this << "  Parent IShellFolder* = "
  877.         << STATIC_CAST(IShellFolder*, ParentFolder));
  878.   TXShell::Check(hr, IDS_GETUIOBJECTOFFAIL);
  879.   return TDropTarget(iface);
  880. }
  881.  
  882. //
  883. //  GetIcon returns a handle to an icon representing this TShellItem
  884. //
  885. //  size can be Large, Small, or Shell
  886. //  kind can be Link, Open, or Selected
  887. //    (see MS doc on SHGetFileInfo for meanings,
  888. //    Programmer's Guide to MS Windows 95, MS Press, pp. 206-207)
  889. //
  890. HICON
  891. TShellItem::GetIcon(TIconSize size, uint kind)
  892. {
  893.   EnforceValidity();
  894.  
  895.   if (!IsPartOfFileSystem()) {
  896.     uint inFlags = (size & Shell)? GIL_FORSHELL: 0 | (kind & Open)? GIL_OPENICON: 0;
  897.     char fileName[_MAX_PATH];
  898.     int index;
  899.     uint outFlags;
  900.     HICON largeIcon;
  901.     HICON smallIcon;
  902.  
  903.     TExtractIcon extractIcon = GetExtractIcon();
  904.     HRESULT hr = extractIcon->GetIconLocation(inFlags, fileName, sizeof (fileName),
  905.                                               &index, &outFlags);
  906.     TXShell::Check(hr, IDS_GETICONLOCFAIL);
  907.     if (hr != S_FALSE)
  908.       if (outFlags & GIL_NOTFILENAME || outFlags & GIL_DONTCACHE) {
  909.         hr = extractIcon->Extract(fileName, index, &largeIcon, &smallIcon, GetSystemMetrics(SM_CXICON));
  910.         TXShell::Check(hr, IDS_EXTRICONEXTRACTFAIL);
  911.         if (hr != S_FALSE)
  912.           return (size == Small)? smallIcon: largeIcon;
  913.       }
  914.   }
  915.  
  916.   // TShellItem is part of file system or couldn't get the icon with
  917.   // IExtractIcon::Extract
  918.   //
  919.   SHFILEINFO fi;
  920.   uint flags = SHGFI_ICON | kind | size;
  921.  
  922.   ::SHGetFileInfo(REINTERPRET_CAST(const char*, STATIC_CAST(ITEMIDLIST*, *this)),
  923.                   0, &fi, sizeof (fi), flags | SHGFI_PIDL);
  924.   WARNX(OwlShell, !fi.hIcon, 0, "::SHGetFileInfo failed.  TShellItem* = "
  925.         << hex << (LPVOID)this);
  926.   if (!fi.hIcon)
  927.       TXShell::Raise(IDS_GETFILEINFOFAIL);
  928.   return fi.hIcon;
  929. }
  930.  
  931. //
  932. // ResolveShortcut resolves this TShellItem (if it's a shortcut) and returns the
  933. // underlying TShellItem.  If this TShellItem is not a shortcut, it just returns itself.
  934. //
  935. // IMPORTANT:  This function calls CoCreateInstance.  Therefore an application that
  936. //             uses this function MUST have previously called CoInitialize (or OLEInitialize).
  937. //
  938. // IMPORTANT:  If the shortcut cannot be resolved, this function will return an
  939. //             empty (invalid) item.  One MUST check for this by calling IsValid()
  940. //             upon return from this function.
  941. //
  942. TShellItem
  943. TShellItem::ResolveShortcut(HWND windowOwner)
  944. {
  945.   EnforceValidity();
  946.  
  947.   if (!IsShortcut())
  948.     return *this;
  949.  
  950.   HRESULT hr;
  951.   TComRef<IShellLink> shellLink;
  952.   hr = CoCreateInstance(CLSID_ShellLink, 0, CLSCTX_INPROC_SERVER, IID_IShellLink,
  953.                         REINTERPRET_CAST(void **, STATIC_CAST(IShellLink**, shellLink)));
  954.   TXShell::Check(hr, IDS_CREATESHELLLINKFAIL);
  955.  
  956.   TComRef<IPersistFile> persistFile;
  957.   hr = shellLink->QueryInterface(IID_IPersistFile,
  958.                                  REINTERPRET_CAST(void **, STATIC_CAST(IPersistFile**, persistFile)));
  959.   TXShell::Check(hr, IDS_LINKQUERYINTRFCFAIL);
  960.   TString shortcutFile = GetPath();
  961.   hr = persistFile->Load(shortcutFile, STGM_READ);
  962.   TXShell::Check(hr, IDS_PERSISTFILELOADFAIL);
  963.  
  964.   hr = shellLink->Resolve(windowOwner, SLR_ANY_MATCH | SLR_UPDATE);
  965.   if (FAILED(hr)) {
  966.     // Failure to Resolve: return empty/invalid shell item object
  967.     //
  968.     return TShellItem();
  969.   }
  970.  
  971.   TPidl resolvedPidl;
  972.   hr = shellLink->GetIDList(resolvedPidl);
  973.   TXShell::Check(hr, IDS_LINKGETIDLISTFAIL);
  974.  
  975.   // Construct the resolved TShellItem
  976.   //
  977.   TCreateStruct cs;
  978.   cs.Pidl = resolvedPidl.GetLastItem();
  979.   if (resolvedPidl.GetItemCount() == 1)
  980.     cs.ParentFolder = TShellItem(Desktop);
  981.   else {
  982.     hr = TShellItem(Desktop)->BindToObject(resolvedPidl.StripLastItem(), 0, IID_IShellFolder,
  983.                     REINTERPRET_CAST(void **, STATIC_CAST(IShellFolder**, cs.ParentFolder)));
  984.     TXShell::Check(hr, IDS_BINDTOOBJECTFAIL);
  985.   }
  986.   return TShellItem(cs);
  987. }
  988.  
  989. //
  990. // Create a shortcut to a file object
  991. //
  992. // IMPORTANT:  This function calls CoCreateInstance.  Therefore an
  993. //             application that uses this function MUST have previously
  994. //             called CoInitialize (or OLEInitialize).
  995. //
  996. HRESULT
  997. TShellItem::CreateShortCut(LPCSTR objPath, LPSTR pathLink, LPSTR description)
  998. {
  999.   HRESULT hr;
  1000.   TComRef<IShellLink> shellLink;
  1001.   hr = CoCreateInstance(CLSID_ShellLink, 0, CLSCTX_INPROC_SERVER, IID_IShellLink,
  1002.                         REINTERPRET_CAST(void **, STATIC_CAST(IShellLink**, shellLink)));
  1003.   TXShell::Check(hr, IDS_CREATESHELLLINKFAIL);
  1004.  
  1005.   // Set path to shortcut target and add description
  1006.   //
  1007.   hr = shellLink->SetPath(TString(objPath));
  1008.   TXShell::Check(hr, IDS_SHLLINKSETPATHFAIL);
  1009.   hr = shellLink->SetDescription(TString(description));
  1010.   TXShell::Check(hr, IDS_SHLLINKSETDESCFAIL);
  1011.  
  1012.   // Query IShellLink for the IPersistFile Interface for saving the
  1013.   // shortcut in persistent storage
  1014.   //
  1015.   TComRef<IPersistFile> persistFile;
  1016.   hr = shellLink->QueryInterface(IID_IPersistFile,
  1017.                                  REINTERPRET_CAST(void **, STATIC_CAST(IPersistFile**, persistFile)));
  1018.   TXShell::Check(hr, IDS_LINKQUERYINTRFCFAIL);
  1019.  
  1020.   // Save link by calling IPersistFile::Save
  1021.   //
  1022.   hr = persistFile->Save(TString(pathLink), TRUE);
  1023.   return hr;
  1024. }
  1025.  
  1026. //
  1027. // Create a shortcut to a non-file object
  1028. //
  1029. // IMPORTANT:  This function calls CoCreateInstance.  Therefore an
  1030. //             application that uses this function MUST have previously
  1031. //             called CoInitialize (or OLEInitialize).
  1032. //
  1033. HRESULT
  1034. TShellItem::CreateShortCut(LPCITEMIDLIST pidl, LPSTR pathLink, LPSTR description)
  1035. {
  1036.   HRESULT hr;
  1037.   TComRef<IShellLink> shellLink;
  1038.   hr = CoCreateInstance(CLSID_ShellLink, 0, CLSCTX_INPROC_SERVER, IID_IShellLink,
  1039.                         REINTERPRET_CAST(void **, STATIC_CAST(IShellLink**, shellLink)));
  1040.   TXShell::Check(hr, IDS_CREATESHELLLINKFAIL);
  1041.  
  1042.   // Set path to shortcut target and add description
  1043.   //
  1044.   shellLink->SetIDList(pidl);
  1045.   shellLink->SetDescription(description);
  1046.  
  1047.   // Query IShellLink for the IPersistFile Interface for saving the
  1048.   // shortcut in persistent storage
  1049.   //
  1050.   TComRef<IPersistFile> persistFile;
  1051.   hr = shellLink->QueryInterface(IID_IPersistFile,
  1052.                                  REINTERPRET_CAST(void **, STATIC_CAST(IPersistFile**, persistFile)));
  1053.   TXShell::Check(hr, IDS_LINKQUERYINTRFCFAIL);
  1054.  
  1055.   // Save link by calling IPersistFile::Save
  1056.   //
  1057.   hr = persistFile->Save(TString(pathLink), TRUE);
  1058.   return hr;
  1059. }
  1060.  
  1061. //
  1062. // Creates a shortcut to this object
  1063. //
  1064. // IMPORTANT:  This function calls CoCreateInstance.  Therefore an
  1065. //             application that uses this function MUST have previously
  1066. //             called CoInitialize (or OLEInitialize).
  1067. //
  1068. TShellItem
  1069. TShellItem::CreateShortCut(LPSTR linkPath, LPSTR description)
  1070. {
  1071.   EnforceValidity();
  1072.  
  1073.   if (IsPartOfFileSystem()) {
  1074.     if (SUCCEEDED(CreateShortCut(GetPath(), linkPath, description)))
  1075.       return TShellItem(linkPath);
  1076.   } else {
  1077.     if (SUCCEEDED(CreateShortCut(GetFullyQualifiedPidl(), linkPath,
  1078.                                  description)))
  1079.       return TShellItem(linkPath);
  1080.   }
  1081.  
  1082.   // Failure: return empty/invalid Shell Item object
  1083.   //
  1084.   return TShellItem();
  1085. }
  1086.  
  1087. //
  1088. //  Adds the TShellItem to the taskbar's recent document list
  1089. //    (see MS doc for more info on SHAddToRecentDocs,
  1090. //    Programmer's Guide to MS Windows 95, MS Press, p. 202)
  1091. //
  1092. void
  1093. TShellItem::AddToRecentDocs() const
  1094. {
  1095.   EnforceValidity();
  1096.   ::SHAddToRecentDocs(SHARD_PIDL, STATIC_CAST(const ITEMIDLIST *, GetFullyQualifiedPidl()));
  1097. }
  1098.  
  1099. //
  1100. //  CompareIDs is a protected function that compares a TShellItem's pidl with
  1101. //    another TShellItem's pidl
  1102. //
  1103. //    (see MS doc for more info CompareIDs,
  1104. //    Programmer's Guide to MS Windows 95, MS Press, p. 194)
  1105. //
  1106. short
  1107. TShellItem::CompareIDs(const TShellItem& rhs) const
  1108. {
  1109.   EnforceValidity();
  1110.   rhs.EnforceValidity();
  1111.   HRESULT hr;
  1112.  
  1113.   if (!HaveSameParent(rhs)) {                                // use the desktop
  1114.     TShellItem desktop(Desktop);
  1115.     hr = desktop->CompareIDs(0, GetFullyQualifiedPidl(), rhs.GetFullyQualifiedPidl());
  1116.     WARNX(OwlShell, FAILED(hr), 0, "Desktop->CompareIDs failed."
  1117.           << "  this TShellItem* = " << hex << (LPVOID)this
  1118.           << "  other TShellItem* = " << (LPVOID)&rhs);
  1119.     TXShell::Check(hr, IDS_COMPAREIDSFAIL);
  1120.   }
  1121.   else {
  1122.     hr = ParentFolder->CompareIDs(0, Pidl, rhs.Pidl);
  1123.     WARNX(OwlShell, FAILED(hr), 0, "SameParent->CompareIDs failed."
  1124.           << "  this TShellItem* = " << hex << (LPVOID)this
  1125.           << "  other TShellItem* = " << (LPVOID)&rhs);
  1126.     TXShell::Check(hr, IDS_COMPAREIDSFAIL);
  1127.   }
  1128.  
  1129.   return STATIC_CAST(short, HRESULT_CODE(hr));
  1130. }
  1131.  
  1132. //
  1133. //  EnforceValidity is a protected function that checks that a TShellItem is valid
  1134. //    before proceeding with an operation that requires the TShellItem to be valid
  1135. //
  1136. void
  1137. TShellItem::EnforceValidity() const
  1138. {
  1139.   WARNX(OwlShell, !Valid(), 0, "TShellItem is not valid."
  1140.         << "  TShellItem* = " << hex << (LPVOID)this);
  1141.   if (!Valid())
  1142.     TXShell::Raise(IDS_TSHELLITEMINVALID);
  1143. }
  1144.  
  1145. // Folder Functions
  1146.  
  1147. //
  1148. //  RetrieveIShellFolder is a protected function that checks to see if a TShellItem's
  1149. //    IShellFolder interface is already assigned a value.  If not, it will BindToObject
  1150. //    in order to assign the interface a value.  Note:  Only TShellItem's that are
  1151. //    folders have an IShellFolder interface;  consequently, if this function is
  1152. //    called on a TShellItem that is not a folder, an exception will be thrown.
  1153. //
  1154. void
  1155. TShellItem::RetrieveIShellFolder() const
  1156. {
  1157.   EnforceValidity();
  1158.   if (!I) { // Need to call BindToObject
  1159.     IShellFolder* iface;
  1160.     HRESULT hr = ParentFolder->BindToObject(Pidl, 0, IID_IShellFolder,
  1161.                                             REINTERPRET_CAST(void **, &iface));
  1162.     WARNX(OwlShell, FAILED(hr), 0, "IShellFolder::BindToObject failed."
  1163.           << "  TShellItem* = " << hex << (LPVOID)this << "  Parent IShellFolder* = "
  1164.           << STATIC_CAST(IShellFolder*, *CONST_CAST(TComRef<IShellFolder>*, &ParentFolder)));
  1165.     TXShell::Check(hr, IDS_BINDTOOBJECTFAIL);
  1166.     CONST_CAST(IShellFolder*, I) = iface;
  1167.   }
  1168. }
  1169.  
  1170. //
  1171. //  EnumObjects is a protected function that returns an IEnumIDList enumerator on
  1172. //    a folder.  Note:  This function is only meaningful for folders;  consequently,
  1173. //    if this function is called on a TShellItem that is not a folder, an
  1174. //    exception will be thrown.
  1175. //
  1176. void
  1177. TShellItem::EnumObjects(IEnumIDList** iface, HWND windowOwner,
  1178.                         const int kind) const
  1179. {
  1180.   EnforceValidity();
  1181.   RetrieveIShellFolder();
  1182.   HRESULT hr = I->EnumObjects(windowOwner, (kind == -1)? TShellItemIterator::Folders |
  1183.                               TShellItemIterator::NonFolders: kind, iface);
  1184.   WARNX(OwlShell, FAILED(hr), 0, "IShellFolder::EnumObjects failed."
  1185.         << "  TShellItem* = " << hex << (LPVOID)this);
  1186.   TXShell::Check(hr, IDS_ENUMOBJECTSFAIL);
  1187. }
  1188.  
  1189. //
  1190. //  BrowseForFolder presents a dialog box to the user in which he can select a
  1191. //    subfolder.  The root of the dialog box is this TShellItem folder.
  1192. //
  1193. //  Note:  It is only meaningful to call this function if the TShellItem is a
  1194. //    folder;  consequently, if this function is called on a TShellItem that is
  1195. //    not a folder, an exception will be thrown.
  1196. //
  1197. //  Additional Documentation:  See MS doc on SHBrowseForFolder for more info,
  1198. //    more info, Programmer's Guide to MS Windows 95, MS Press, pp. 202-203.
  1199. //
  1200. bool
  1201. TShellItem::BrowseForFolder(TCreateStruct& cs, HWND windowOwner,
  1202.                             const char* title, const UINT flags, int* image,
  1203.                             const bool includeStatus, BFFCALLBACK func,
  1204.                             const LPARAM param) const
  1205. {
  1206.   EnforceValidity();
  1207.   RetrieveIShellFolder();
  1208.   char displayName[_MAX_PATH];
  1209.  
  1210.   BROWSEINFO bi;
  1211.   bi.hwndOwner = windowOwner;
  1212.   TPidl fullPidl = GetFullyQualifiedPidl();
  1213.   bi.pidlRoot = fullPidl;
  1214.   bi.pszDisplayName = displayName;
  1215.   bi.lpszTitle = title;
  1216.   bi.ulFlags = flags;
  1217.   if (includeStatus)
  1218.     bi.ulFlags |= BIF_STATUSTEXT;
  1219.   bi.lpfn = func;
  1220.   bi.lParam = param;
  1221.  
  1222.   TPidl pidl = ::SHBrowseForFolder(&bi);
  1223.   if (!pidl)
  1224.     return false;
  1225.   else {
  1226.     if (image)
  1227.       *image = bi.iImage;
  1228.     TShellItem desktop(Desktop);
  1229.     cs.Pidl = pidl.GetLastItem();
  1230.     HRESULT hr = desktop->BindToObject(pidl.StripLastItem(), 0, IID_IShellFolder,
  1231.          REINTERPRET_CAST(void **, STATIC_CAST(IShellFolder**, cs.ParentFolder)));
  1232.     WARNX(OwlShell, FAILED(hr), 0, "IShellFolder::BindToObject failed."
  1233.           << "  TShellItem* = " << hex << (LPVOID)this
  1234.           << "  Desktop IShellFolder* = " << STATIC_CAST(IShellFolder*, desktop));
  1235.     TXShell::Check(hr, IDS_BINDTOOBJECTFAIL);
  1236.  
  1237.     return true;
  1238.   }
  1239. }
  1240.  
  1241. //
  1242. //  ParseDisplayName parses a "for parsing" display name into a TCreateStruct
  1243. //    (which can be used to create a TShellItem).  In general, it is not necessary
  1244. //    to call this function when using OWL's shell classes.
  1245. //
  1246. //  Note:  It is only meaningful to call this function if the TShellItem is a
  1247. //    folder;  consequently, if this function is called on a TShellItem that is
  1248. //    not a folder, an exception will be thrown.
  1249. //
  1250. //  Additional Documentation:  See MS doc on IShellFolder::ParseDisplayName for
  1251. //    more info, Programmer's Guide to MS Windows 95, MS Press, pp. 191-192.
  1252. //
  1253. HRESULT
  1254. TShellItem::ParseDisplayName(TCreateStruct& cs, const char* displayName,
  1255.                              ulong* eaten, HWND windowOwner,
  1256.                              ulong* attrib) const
  1257. {
  1258.   EnforceValidity();
  1259.   TPidl pidl;
  1260.   ulong charsEaten;
  1261.   ulong attributes;
  1262.   RetrieveIShellFolder();
  1263.  
  1264.   HRESULT hr = I->ParseDisplayName(windowOwner, 0, TString(displayName),
  1265.                                    &charsEaten, pidl, &attributes);
  1266.  
  1267.   if (hr == NOERROR) {
  1268.     if (eaten)
  1269.       *eaten = charsEaten;
  1270.     if (attrib)
  1271.      *attrib = attributes;
  1272.     cs.Pidl = pidl;
  1273.     cs.ParentFolder = *this;
  1274.   }
  1275.  
  1276.   return hr;
  1277. }
  1278.  
  1279. //
  1280. //  TShellItemIterator constructor.
  1281. //
  1282. //  Note:  It is only meaningful to construct iterators on folders;  therefore,
  1283. //    if this constructor is passed a TShellItem that is not a folder, an exception
  1284. //    will be thrown.
  1285. //
  1286. //  Additional Documentation:  See MS doc on IEnumIDList for more info,
  1287. //    Programmer's Guide to MS Windows 95, MS Press, pp. 199-201.
  1288. //
  1289. TShellItemIterator::TShellItemIterator(const TShellItem& folder, HWND windowOwner,
  1290.                                        const int kind)
  1291. :
  1292.   Index(0),
  1293.   Pidl(0),
  1294.   Folder(folder)
  1295. {
  1296.   folder.EnumObjects(*this, windowOwner, kind);
  1297.   Folder = folder; // even though filled in above, the IShellFolder* may not have
  1298.                    // yet have been filled in.  (See RetrieveIShellFolder)
  1299.   Next();
  1300. }
  1301.  
  1302. //
  1303. //  TShellItemIterator copy constructor.
  1304. //
  1305. //  Note:  This function does not work with the intial release of Win95 because
  1306. //    Win95's IEnumIDList::Clone is broken (it returns E_FAIL (unspecified error))
  1307. //
  1308. TShellItemIterator::TShellItemIterator(const TShellItemIterator& source)
  1309. :
  1310.   Index(source.Index),
  1311.   Pidl(source.Pidl),
  1312.   Folder(source.Folder)
  1313. {
  1314.   if (!source.I)
  1315.     I = 0;
  1316.   else {
  1317.     HRESULT hr = source.I->Clone(*this);
  1318.     WARNX(OwlShell, FAILED(hr), 0, "IEnumIDList::Clone failed."
  1319.           << "  TShellItemIterator* = " << hex << (LPVOID)this
  1320.           << "  source IEnumIDList* = "
  1321.           << STATIC_CAST(IEnumIDList*, CONST_CAST(TShellItemIterator&, source)));
  1322.     TXShell::Check(hr, IDS_CLONEFAIL);
  1323.   }
  1324. }
  1325.  
  1326. //
  1327. //  TShellItemIterator assignment operator
  1328. //
  1329. //  Note:  This function does not work with the intial release of Win95 because
  1330. //    Win95's IEnumIDList::Clone is broken (it returns E_FAIL (unspecified error))
  1331. //
  1332. TShellItemIterator& TShellItemIterator::operator = (const TShellItemIterator& source)
  1333. {
  1334.   if (&source != this) {
  1335.     if (!source.I)
  1336.       I = 0;
  1337.     else {
  1338.       HRESULT hr = source.I->Clone(*this);
  1339.       WARNX(OwlShell, FAILED(hr), 0, "IEnumIDList::Clone failed."
  1340.           << "  TShellItemIterator* = " << hex << (LPVOID)this << "  source IEnumIDList* = "
  1341.           << STATIC_CAST(IEnumIDList*, CONST_CAST(TShellItemIterator&, source)));
  1342.       TXShell::Check(hr, IDS_CLONEFAIL);
  1343.       Index = source.Index;
  1344.       Pidl = source.Pidl;
  1345.       Folder = source.Folder;
  1346.     }
  1347.   }
  1348.   return *this;
  1349. }
  1350.  
  1351. //
  1352. //  operator IEnumIDList** resets the interface pointer and returns a pointer
  1353. //    to this interface pointer.
  1354. //
  1355. TShellItemIterator::operator IEnumIDList**()
  1356. {
  1357.   return TComRef<IEnumIDList>::operator IEnumIDList**();
  1358. }
  1359.  
  1360. //
  1361. //  operator ++ increments the "cursor" in the iterator, then returns
  1362. //    the item pointed to by the cursor
  1363. //
  1364. //  The item is returned as a TShellItem::TCreateStruct structure.  For more
  1365. //    information about TCreateStruct, see the comments in the
  1366. //    TShellItem::TShellItem(const TCreateStruct& cs) constructor.
  1367. //
  1368. TShellItem::TCreateStruct TShellItemIterator::operator ++()
  1369. {
  1370.   EnforceValidInterface();
  1371.   return operator[] (Index + 1);
  1372. }
  1373.  
  1374. //
  1375. //  operator ++(int) returns the item pointed to by the "cursor," then increments
  1376. //    the cursor.
  1377. //
  1378. //  The item is returned as a TShellItem::TCreateStruct structure.  For more
  1379. //    information about TCreateStruct, see the comments in the
  1380. //    TShellItem::TShellItem(const TCreateStruct& cs) constructor.
  1381. //
  1382. TShellItem::TCreateStruct
  1383. TShellItemIterator::operator ++(int)
  1384. {
  1385.   EnforceValidInterface();
  1386.   WARNX(OwlShell, Index == -1, 0, "Attempt to read past end of TShellItemIterator"
  1387.         << "  TShellItemIterator* = " << hex << (LPVOID)this << "  IEnumIDList* = "
  1388.         << STATIC_CAST(IEnumIDList*, *CONST_CAST(TShellItemIterator*, this)));
  1389.   if (Index == -1)
  1390.       TXShell::Raise(IDS_SHELLITERATORATEND);
  1391.   TShellItem::TCreateStruct cs(Pidl, Folder);
  1392.   Next();
  1393.   if (Index != -1)
  1394.     Index++;
  1395.   return cs;
  1396. }
  1397.  
  1398. //
  1399. //  operator -- decrements the "cursor" in the iterator, then returns
  1400. //    the item pointed to by the cursor
  1401. //
  1402. //  The item is returned as a TShellItem::TCreateStruct structure.  For more
  1403. //    information about TCreateStruct, see the comments in the
  1404. //    TShellItem::TShellItem(const TCreateStruct& cs) constructor.
  1405. //
  1406. //  Note:  This function does not work with the intial release of Win95 because
  1407. //    it requires IEnumIDList::Reset to be called and IEnumIDList::Reset returns
  1408. //    E_NOTIMPL (not implemented) in the intitial Win95 release.
  1409. //
  1410. TShellItem::TCreateStruct
  1411. TShellItemIterator::operator --()
  1412. {
  1413.   EnforceValidInterface();
  1414.   return operator[] (Index - 1);
  1415. }
  1416.  
  1417. //
  1418. //  operator --(int) returns the item pointed to by the "cursor," then decrements
  1419. //    the cursor.
  1420. //
  1421. //  The item is returned as a TShellItem::TCreateStruct structure.  For more
  1422. //    information about TCreateStruct, see the comments in the
  1423. //    TShellItem::TShellItem(const TCreateStruct& cs) constructor.
  1424. //
  1425. //  Note:  This function does not work with the intial release of Win95 because
  1426. //    it requires IEnumIDList::Reset to be called and IEnumIDList::Reset returns
  1427. //    E_NOTIMPL (not implemented) in the intitial Win95 release.
  1428. //
  1429. TShellItem::TCreateStruct
  1430. TShellItemIterator::operator --(int)
  1431. {
  1432.   EnforceValidInterface();
  1433.   WARNX(OwlShell, Index == -1, 0, "Attempt to read past end of TShellItemIterator"
  1434.         << "  TShellItemIterator* = " << hex << (LPVOID)this << "  IEnumIDList* = "
  1435.         << STATIC_CAST(IEnumIDList*, *CONST_CAST(TShellItemIterator*, this)));
  1436.   if (Index == -1)
  1437.       TXShell::Raise(IDS_SHELLITERATORATEND);
  1438.   TShellItem::TCreateStruct cs(Pidl, Folder);
  1439.   Reset();
  1440.   Skip(--Index);
  1441.   Next();
  1442.   return cs;
  1443. }
  1444.  
  1445. //
  1446. //  operator Current returns the item pointed to by the "cursor"
  1447. //
  1448. //  The item is returned as a TShellItem::TCreateStruct structure.  For more
  1449. //    information about TCreateStruct, see the comments in the
  1450. //    TShellItem::TShellItem(const TCreateStruct& cs) constructor.
  1451. //
  1452. TShellItem::TCreateStruct
  1453. TShellItemIterator::Current()
  1454. {
  1455.   EnforceValidInterface();
  1456.   WARNX(OwlShell, Index == -1, 0, "Attempt to read past end of TShellItemIterator"
  1457.         << "  TShellItemIterator* = " << hex << (LPVOID)this << "  IEnumIDList* = "
  1458.         << STATIC_CAST(IEnumIDList*, *CONST_CAST(TShellItemIterator*, this)));
  1459.   if (Index == -1)
  1460.       TXShell::Raise(IDS_SHELLITERATORATEND);
  1461.   return TShellItem::TCreateStruct(Pidl, Folder);
  1462. }
  1463.  
  1464. //
  1465. //  Next is a protected function that increments the cursor.  Equivalent to Skip(1).
  1466. //
  1467. void TShellItemIterator::Next()
  1468. {
  1469.   EnforceValidInterface();
  1470.  
  1471.   WARNX(OwlShell, Index == -1, 0, "Attempt to read past end of TShellItemIterator"
  1472.         << "  TShellItemIterator* = " << hex << (LPVOID)this << "  IEnumIDList* = "
  1473.         << STATIC_CAST(IEnumIDList*, *CONST_CAST(TShellItemIterator*, this)));
  1474.   if (Index == -1)
  1475.     TXShell::Raise(IDS_SHELLITERATORATEND);
  1476.  
  1477.   HRESULT hr = I->Next(1, Pidl, 0);
  1478.   WARNX(OwlShell, FAILED(hr), 0, "IShellItemIterator::Next failed."
  1479.         << "  TShellItemIterator* = " << hex << (LPVOID)this << "  IEnumIDList* = "
  1480.         << STATIC_CAST(IEnumIDList*, *CONST_CAST(TShellItemIterator*, this)));
  1481.   TXShell::Check(hr, IDS_IDLISTNEXTFAIL);
  1482.   if (hr == S_FALSE)
  1483.     Index = -1;
  1484. }
  1485.  
  1486. //
  1487. //  Skip advances the cursor <count> times.  Equivalent to calling Next <count>
  1488. //    times.
  1489. //
  1490. //  Note:  This function does not work with the intial release of Win95 because
  1491. //    IEnumIDList::Skip returns E_NOTIMPL (not implemented) in the intitial Win95
  1492. //    release.
  1493. //
  1494. void
  1495. TShellItemIterator::Skip(const ulong count)
  1496. {
  1497.   EnforceValidInterface();
  1498.   if (count) {
  1499.     HRESULT hr = I->Skip(count);
  1500.     WARNX(OwlShell, FAILED(hr), 0, "IShellItemIterator::Skip failed."
  1501.           << "  TShellItemIterator* = " << hex << (LPVOID)this << "  IEnumIDList* = "
  1502.           << STATIC_CAST(IEnumIDList*, *CONST_CAST(TShellItemIterator*, this))
  1503.           << "  count = " << count);
  1504.     TXShell::Check(hr, IDS_IDLISTSKIPFAIL);
  1505.     if (hr == S_FALSE)
  1506.       Index = -1;
  1507.     else
  1508.       Index += count;
  1509.   }
  1510. }
  1511.  
  1512. //
  1513. //  Reset resets the cursor to the beginning.
  1514. //
  1515. //  Note:  This function does not work with the intial release of Win95 because
  1516. //    IEnumIDList::Reset returns E_NOTIMPL (not implemented) in the intitial Win95
  1517. //    release.
  1518. //
  1519. void
  1520. TShellItemIterator::Reset()
  1521. {
  1522.   EnforceValidInterface();
  1523.   HRESULT hr = I->Reset();
  1524.   WARNX(OwlShell, FAILED(hr), 0, "IShellItemIterator::Reset failed."
  1525.         << "  TShellItemIterator* = " << hex << this << "  IEnumIDList* = "
  1526.         << STATIC_CAST(IEnumIDList*, *CONST_CAST(TShellItemIterator*, this)));
  1527.   TXShell::Check(hr, IDS_IDLISTRESETFAIL);
  1528.   Index = 0;
  1529. }
  1530.  
  1531. //
  1532. //  operator [] returns the item at the <index> location.  index is zero based.
  1533. //
  1534. //  The item is returned as a TShellItem::TCreateStruct structure.  For more
  1535. //    information about TCreateStruct, see the comments in the
  1536. //    TShellItem::TShellItem(const TCreateStruct& cs) constructor.
  1537. //
  1538. //  Note:  operator[] doesn't work with the intial release of Win95 because it
  1539. //    calls Skip and Reset wich are broken in the intial Win95 release.  Both of
  1540. //    these functions return E_NOTIMPL (not implemented).  The only way operator[]
  1541. //    will work is to call it sequentially, beginning at index 0 (i.e., to use it
  1542. //    like operator ++().
  1543. //
  1544. TShellItem::TCreateStruct
  1545. TShellItemIterator::operator [](const long index)
  1546. {
  1547.   EnforceValidInterface();
  1548.   if (Index == index)
  1549.     return TShellItem::TCreateStruct(Pidl, Folder);
  1550.   if (Index < index)
  1551.     Skip(index - Index - 1);
  1552.   else if (Index > index) {
  1553.     Reset();
  1554.     Skip(index);
  1555.     }
  1556.   Next();
  1557.   WARNX(OwlShell, Index == -1, 0, "Attempt to read past end of TShellItemIterator"
  1558.         << "  TShellItemIterator* = " << hex << this << "  IEnumIDList* = "
  1559.         << STATIC_CAST(IEnumIDList*, *CONST_CAST(TShellItemIterator*, this)));
  1560.   if (Index == -1) {
  1561.     TXShell::Raise(IDS_SHELLITERATORATEND);
  1562.     return TShellItem::TCreateStruct();                   // To satisfy compiler
  1563.   }
  1564.   else
  1565.     return TShellItem::TCreateStruct(Pidl, Folder);
  1566. }
  1567.  
  1568. //
  1569. //  GetCount returns the number of items in the iterator's list
  1570. //
  1571. //  Note:  This function does not work with the intial release of Win95 because
  1572. //    Clone and Reset are borken in the intitial Win95 release.
  1573. //
  1574. long
  1575. TShellItemIterator::GetCount() const
  1576. {
  1577.   EnforceValidInterface();
  1578.   TShellItemIterator list(*this);  // clone so we don't affect position
  1579.   list.Reset();
  1580.   if (list.Index == -1)
  1581.     return 0;
  1582.   long cnt = 1;
  1583.   while (list.Skip(1), Index != -1)
  1584.     cnt++;
  1585.   return cnt;
  1586. }
  1587.  
  1588. //
  1589. //  EnforceValidInterface is a protected function that checks to see that this
  1590. //    TShellItemIterator contains a valid IEnumIDList interface pointer.  If it
  1591. //    doesn't, it throws an exception.
  1592. //
  1593. void
  1594. TShellItemIterator::EnforceValidInterface() const
  1595. {
  1596.   WARNX(OwlShell, !I, 0, "TShellItemIterator is not valid (IEnumIDList* == 0)."
  1597.         << "  TShellItemIterator* = " << hex
  1598.         << STATIC_CAST(IEnumIDList*, *CONST_CAST(TShellItemIterator*, this)));
  1599.   if (!I) {
  1600.     TXShell::Raise(IDS_IDLISTZEROPOINTER);
  1601.   }
  1602. }
  1603.  
  1604. //
  1605. //
  1606. //
  1607. TXShell::TXShell(uint resId, HANDLE handle)
  1608. :
  1609.   TXOwl(MakeMessage(resId, uint(handle)), resId)
  1610. {
  1611. }
  1612.  
  1613. #if defined(BI_NO_COVAR_RET)
  1614. TXBase* TXShell::Clone()
  1615. #else
  1616. TXShell* TXShell::Clone()
  1617. #endif
  1618. {
  1619.   return new TXShell(*this);
  1620. }
  1621.  
  1622. //
  1623. //
  1624. //
  1625. void TXShell::Throw()
  1626. {
  1627.   THROW(*this);
  1628. }
  1629.  
  1630. //
  1631. //
  1632. //
  1633. void TXShell::Raise(uint resId, HANDLE handle)
  1634. {
  1635.   TXShell(resId, handle).Throw();
  1636. }
  1637.  
  1638. //
  1639. //
  1640. //
  1641. void TXShell::Check(HRESULT hr, uint resID, HANDLE handle)
  1642. {
  1643.   if FAILED(hr)
  1644.     Raise(resID, handle);
  1645. }
  1646.  
  1647.