home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / FileOp.pm < prev    next >
Encoding:
Perl POD Document  |  2003-07-19  |  84.4 KB  |  2,778 lines

  1. package Win32::FileOp;
  2.  
  3. use vars qw($VERSION);
  4. $VERSION = '0.14.1';
  5.  
  6. use Win32::API;
  7. use File::Find;
  8. use File::Path;
  9. use File::DosGlob qw(glob);
  10. use Cwd;
  11. use strict ;# 'vars';
  12. use Carp;
  13.  
  14. #http://Jenda.Krynicky.cz/
  15. use Data::Lazy;
  16. use Win32::AbsPath qw(Relative2Absolute RelativeToAbsolute);
  17.  
  18. require Exporter;
  19. @Win32::FileOp::ISA = qw(Exporter);
  20.  
  21. $Win32::FileOp::BufferSize = 65534;
  22.  
  23. my @FOF_flags = qw(
  24.     FOF_SILENT FOF_RENAMEONCOLLISION FOF_NOCONFIRMATION FOF_ALLOWUNDO
  25.     FOF_FILESONLY FOF_SIMPLEPROGRESS FOF_NOCONFIRMMKDIR FOF_NOERRORUI
  26.     FOF_NOCOPYSECURITYATTRIBS FOF_MULTIDESTFILES FOF_CREATEPROGRESSDLG
  27. );
  28.  
  29. my @OFN_flags = qw(
  30.     OFN_READONLY OFN_OVERWRITEPROMPT OFN_HIDEREADONLY OFN_NOCHANGEDIR OFN_SHOWHELP
  31.     OFN_ENABLEHOOK OFN_ENABLETEMPLATE OFN_ENABLETEMPLATEHANDLE OFN_NOVALIDATE
  32.     OFN_ALLOWMULTISELECT OFN_EXTENSIONDIFFERENT OFN_PATHMUSTEXIST OFN_FILEMUSTEXIST
  33.     OFN_CREATEPROMPT OFN_SHAREAWARE OFN_NOREADONLYRETURN OFN_NOTESTFILECREATE
  34.     OFN_NONETWORKBUTTON OFN_NOLONGNAMES OFN_EXPLORER OFN_NODEREFERENCELINKS
  35.     OFN_LONGNAMES OFN_SHAREFALLTHROUGH OFN_SHARENOWARN OFN_SHAREWARN
  36. );
  37.  
  38. my @BIF_flags = qw(
  39.     BIF_RETURNONLYFSDIRS BIF_DONTGOBELOWDOMAIN BIF_STATUSTEXT BIF_RETURNFSANCESTORS
  40.     BIF_BROWSEFORCOMPUTER BIF_BROWSEFORPRINTER BIF_BROWSEINCLUDEFILES
  41. );
  42.  
  43. my @CSIDL_flags = qw(
  44.     CSIDL_DESKTOP CSIDL_PROGRAMS CSIDL_CONTROLS CSIDL_PRINTERS CSIDL_PERSONAL
  45.     CSIDL_FAVORITES CSIDL_STARTUP CSIDL_RECENT CSIDL_SENDTO CSIDL_BITBUCKET
  46.     CSIDL_STARTMENU CSIDL_DESKTOPDIRECTORY CSIDL_DRIVES CSIDL_NETWORK CSIDL_NETHOOD
  47.     CSIDL_FONTS CSIDL_TEMPLATES CSIDL_COMMON_STARTMENU CSIDL_COMMON_PROGRAMS
  48.     CSIDL_COMMON_STARTUP CSIDL_COMMON_DESKTOPDIRECTORY CSIDL_APPDATA CSIDL_PRINTHOOD
  49. );
  50.  
  51. my @CONNECT_flags = qw(
  52.     CONNECT_UPDATE_PROFILE CONNECT_UPDATE_RECENT CONNECT_TEMPORARY CONNECT_INTERACTIVE
  53.     CONNECT_PROMPT CONNECT_NEED_DRIVE CONNECT_REFCOUNT CONNECT_REDIRECT CONNECT_LOCALDRIVE
  54.     CONNECT_CURRENT_MEDIA CONNECT_DEFERRED CONNECT_RESERVED
  55. );
  56.  
  57. my @SW_flags = qw(
  58.     SW_HIDE SW_MAXIMIZE SW_MINIMIZE SW_RESTORE SW_SHOW
  59.     SW_SHOWDEFAULT SW_SHOWMAXIMIZED SW_SHOWMINIMIZED
  60.     SW_SHOWMINNOACTIVE SW_SHOWNA SW_SHOWNOACTIVATE SW_SHOWNORMAL
  61. );
  62.  
  63. @Win32::FileOp::EXPORT = (
  64.  qw(  Recycle RecycleConfirm RecycleConfirmEach RecycleEx
  65.       Delete DeleteConfirm DeleteConfirmEach DeleteEx
  66.       Copy CopyConfirm CopyConfirmEach CopyEx
  67.       Move MoveConfirm MoveConfirmEach MoveEx
  68.       MoveAtReboot DeleteAtReboot MoveFile MoveFileEx CopyFile
  69.       FillInDir UpdateDir
  70.       FindInPATH FindInPath Relative2Absolute RelativeToAbsolute
  71.       AddToRecentDocs EmptyRecentDocs
  72.       ReadINISectionKeys ReadINISections
  73.       WriteToINI WriteToWININI ReadINI ReadWININI DeleteFromINI DeleteFromWININI
  74.       OpenDialog SaveAsDialog BrowseForFolder
  75.       recycle
  76.       DesktopHandle GetDesktopHandle WindowHandle GetWindowHandle
  77.       Compress Uncompress UnCompress Compressed SetCompression GetCompression CompressedSize CompressDir UncompressDir UnCompressDir
  78.       Map Connect Unmap Disconnect Mapped
  79.       Subst Unsubst Substed SubstDev
  80.       GetLargeFileSize GetDiskFreeSpace ShellExecute
  81.  ),
  82.  @FOF_flags,
  83.  @OFN_flags,
  84.  @BIF_flags,
  85.  @CSIDL_flags,
  86.  @SW_flags
  87. );
  88. #     FOF_CONFIRMMOUSE FOF_WANTMAPPINGHANDLE
  89.  
  90. *Win32::FileOp::EXPORT_OK = [@Win32::FileOp::EXPORT, @CONNECT_flags];
  91.  
  92. %Win32::FileOp::EXPORT_TAGS = (
  93.     INI => [qw( ReadINISectionKeys ReadINISections WriteToINI WriteToWININI ReadINI ReadWININI DeleteFromINI DeleteFromWININI )],
  94.     DIALOGS => [qw( OpenDialog SaveAsDialog BrowseForFolder),
  95.                @OFN_flags, @BIF_flags, @CSIDL_flags],
  96.     _DIALOGS => [@OFN_flags, @BIF_flags, @CSIDL_flags],
  97.     HANDLES => [qw( DesktopHandle GetDesktopHandle WindowHandle GetWindowHandle )],
  98.     BASIC => [qw(
  99.                Delete DeleteConfirm DeleteConfirmEach DeleteEx
  100.                Copy CopyConfirm CopyConfirmEach CopyEx
  101.                Move MoveConfirm MoveConfirmEach MoveEx
  102.                MoveAtReboot DeleteAtReboot MoveFile MoveFileEx CopyFile
  103.              ),
  104.              @FOF_flags],
  105.     _BASIC => [@FOF_flags],
  106.     RECENT => [qw(AddToRecentDocs EmptyRecentDocs)],
  107.     DIRECTORY => [qw(UpdateDir FillInDir)],
  108.     COMPRESS => [qw(Compress Uncompress UnCompress Compressed SetCompression GetCompression CompressedSize CompressDir UncompressDir UnCompressDir)],
  109.     MAP => [qw(Map Connect Unmap Disconnect Mapped)],
  110.     _MAP => \@CONNECT_flags,
  111.     SUBST => [qw(Subst Unsubst Substed SubstDev)],
  112.     EXECUTE => ['ShellExecute', @SW_flags],
  113.     _EXECUTE => \@SW_flags,
  114. );
  115.  
  116.  
  117. use vars qw($ReadOnly $DesktopHandle $fileop $ProgressTitle);
  118. $Win32::FileOp::DesktopHandle = 0;
  119. $Win32::FileOp::WindowHandle = 0;
  120. sub Win32::FileOp::GetDesktopHandle;
  121. sub Win32::FileOp::GetWindowHandle;
  122. $Win32::FileOp::fileop = 0;
  123. $Win32::FileOp::ProgressTitle = '';
  124.  
  125. sub FO_MOVE     () { 0x01 }
  126. sub FO_COPY     () { 0x02 }
  127. sub FO_DELETE   () { 0x03 }
  128. sub FO_RENAME   () { 0x04 }
  129.  
  130. sub FOF_CREATEPROGRESSDLG     () { 0x0000 } # default
  131. sub FOF_MULTIDESTFILES        () { 0x0001 } # more than one dest for files
  132. #sub FOF_CONFIRMMOUSE         () { 0x0002 } # not implemented
  133. sub FOF_SILENT                () { 0x0004 } # don't create progress/report
  134. sub FOF_RENAMEONCOLLISION     () { 0x0008 } # rename if coliding
  135. sub FOF_NOCONFIRMATION        () { 0x0010 } # Don't prompt the user.
  136. #sub FOF_WANTMAPPINGHANDLE    () { 0x0020 } # Fill in FILEOPSTRUCT.hNameMappings
  137. sub FOF_ALLOWUNDO             () { 0x0040 } # recycle bin instead of delete
  138. sub FOF_FILESONLY             () { 0x0080 } # on *.*, do only files
  139. sub FOF_SIMPLEPROGRESS        () { 0x0100 } # means don't show names of files
  140. sub FOF_NOCONFIRMMKDIR        () { 0x0200 } # don't confirm making needed dirs
  141. sub FOF_NOERRORUI             () { 0x0400 } # don't put up error UI
  142. sub FOF_NOCOPYSECURITYATTRIBS () { 0x0800 } # dont copy file Security Attributes
  143.  
  144. sub MOVEFILE_REPLACE_EXISTING   () { 0x00000001 }
  145. sub MOVEFILE_COPY_ALLOWED       () { 0x00000002 }
  146. sub MOVEFILE_DELAY_UNTIL_REBOOT () { 0x00000004 }
  147.  
  148. sub OFN_READONLY              () { 0x00000001}
  149. sub OFN_OVERWRITEPROMPT       () { 0x00000002}
  150. sub OFN_HIDEREADONLY          () { 0x00000004}
  151. sub OFN_NOCHANGEDIR           () { 0x00000008}
  152. sub OFN_SHOWHELP              () { 0x00000010}
  153. sub OFN_ENABLEHOOK            () { #0x00000020;
  154.     carp "OFN_ENABLEHOOK not implemented" }
  155. sub OFN_ENABLETEMPLATE        () { #0x00000040;
  156.     carp "OFN_ENABLEHOOK not implemented" }
  157. sub OFN_ENABLETEMPLATEHANDLE  () { #0x00000080;
  158.     carp "OFN_ENABLEHOOK not implemented" }
  159. sub OFN_NOVALIDATE            () { 0x00000100}
  160. sub OFN_ALLOWMULTISELECT      () { 0x00000200}
  161. sub OFN_EXTENSIONDIFFERENT    () { 0x00000400}
  162. sub OFN_PATHMUSTEXIST         () { 0x00000800}
  163. sub OFN_FILEMUSTEXIST         () { 0x00001000}
  164. sub OFN_CREATEPROMPT          () { 0x00002000}
  165. sub OFN_SHAREAWARE            () { 0x00004000}
  166. sub OFN_NOREADONLYRETURN      () { 0x00008000}
  167. sub OFN_NOTESTFILECREATE      () { 0x00010000}
  168. sub OFN_NONETWORKBUTTON       () { 0x00020000}
  169. sub OFN_NOLONGNAMES           () { 0x00040000} # // force no long names for 4.x modules
  170.                                                #if(WINVER >() { 0x0400)
  171. sub OFN_EXPLORER              () { 0x00080000} # // new look commdlg
  172. sub OFN_NODEREFERENCELINKS    () { 0x00100000}
  173. sub OFN_LONGNAMES             () { 0x00200000} # // force long names for 3.x modules
  174.  
  175. sub OFN_SHAREFALLTHROUGH  () { 2}
  176. sub OFN_SHARENOWARN       () { 1}
  177. sub OFN_SHAREWARN         () { 0}
  178.  
  179.  
  180. sub BIF_RETURNONLYFSDIRS   () { 0x0001 } #// For finding a folder to start document searching
  181. sub BIF_DONTGOBELOWDOMAIN  () { 0x0002 } #// For starting the Find Computer
  182. sub BIF_STATUSTEXT         () { 0x0004 } # Includes a status area in the dialog box.
  183.       # The callback function can set the status text
  184.       # by sending messages to the dialog box.
  185. sub BIF_RETURNFSANCESTORS  () { 0x0008 }
  186. sub BIF_BROWSEFORCOMPUTER  () { 0x1000 } #// Browsing for Computers.
  187. sub BIF_BROWSEFORPRINTER   () { 0x2000 } #// Browsing for Printers
  188. sub BIF_BROWSEINCLUDEFILES () { 0x4000 } #// Browsing for Everything
  189.  
  190. #BIF_BROWSEFORCOMPUTER    Only returns computers. If the user selects
  191. #anything other than a computer, the OK button is grayed.
  192.  
  193. #BIF_BROWSEFORPRINTER    Only returns printers. If the user selects
  194. #anything other than a printer, the OK button is grayed.
  195.  
  196. #BIF_DONTGOBELOWDOMAIN    Does not include network folders below the
  197. #domain level in the tree view control.
  198.  
  199. #BIF_RETURNFSANCESTORS    Only returns file system ancestors. If the user
  200. #selects anything other than a file system ancestor, the OK button is
  201. #grayed.
  202.  
  203. #BIF_RETURNONLYFSDIRS    Only returns file system directories. If the
  204. #user selects folders that are not part of the file system, the OK button
  205. #is grayed.
  206.  
  207. #BIF_STATUSTEXT    Includes a status area in the dialog box. The callback
  208. #function can set the status text by sending messages to the dialog box.
  209.  
  210. sub CSIDL_DESKTOP                   () { 0x0000 }
  211. sub CSIDL_PROGRAMS                  () { 0x0002 }
  212. sub CSIDL_CONTROLS                  () { 0x0003 }
  213. sub CSIDL_PRINTERS                  () { 0x0004 }
  214. sub CSIDL_PERSONAL                  () { 0x0005 }
  215. sub CSIDL_FAVORITES                 () { 0x0006 }
  216. sub CSIDL_STARTUP                   () { 0x0007 }
  217. sub CSIDL_RECENT                    () { 0x0008 }
  218. sub CSIDL_SENDTO                    () { 0x0009 }
  219. sub CSIDL_BITBUCKET                 () { 0x000a }
  220. sub CSIDL_STARTMENU                 () { 0x000b }
  221. sub CSIDL_DESKTOPDIRECTORY          () { 0x0010 }
  222. sub CSIDL_DRIVES                    () { 0x0011 }
  223. sub CSIDL_NETWORK                   () { 0x0012 }
  224. sub CSIDL_NETHOOD                   () { 0x0013 }
  225. sub CSIDL_FONTS                     () { 0x0014 }
  226. sub CSIDL_TEMPLATES                 () { 0x0015 }
  227. sub CSIDL_COMMON_STARTMENU          () { 0x0016 }
  228. sub CSIDL_COMMON_PROGRAMS           () { 0x0017 }
  229. sub CSIDL_COMMON_STARTUP            () { 0x0018 }
  230. sub CSIDL_COMMON_DESKTOPDIRECTORY   () { 0x0019 }
  231. sub CSIDL_APPDATA                   () { 0x001a }
  232. sub CSIDL_PRINTHOOD                 () { 0x001b }
  233.  
  234. #=rem
  235. #sub FILE_SHARE_READ                 () { 0x00000001  }
  236. #sub FILE_SHARE_WRITE                () { 0x00000002  }
  237. #sub FILE_SHARE_DELETE               () { 0x00000004  }
  238. #
  239. #sub FILE_FLAG_WRITE_THROUGH         () { 0x80000000 }
  240. #sub FILE_FLAG_OVERLAPPED            () { 0x40000000 }
  241. #sub FILE_FLAG_NO_BUFFERING          () { 0x20000000 }
  242. #sub FILE_FLAG_RANDOM_ACCESS         () { 0x10000000 }
  243. #sub FILE_FLAG_SEQUENTIAL_SCAN       () { 0x08000000 }
  244. #sub FILE_FLAG_DELETE_ON_CLOSE       () { 0x04000000 }
  245. #sub FILE_FLAG_BACKUP_SEMANTICS      () { 0x02000000 }
  246. #sub FILE_FLAG_POSIX_SEMANTICS       () { 0x01000000 }
  247. #
  248. #
  249. #sub CREATE_NEW          () { 1 }
  250. #sub CREATE_ALWAYS       () { 2 }
  251. #sub OPEN_EXISTING       () { 3 }
  252. #sub OPEN_ALWAYS         () { 4 }
  253. #sub TRUNCATE_EXISTING   () { 5 }
  254. #=cut
  255.  
  256. sub DDD_RAW_TARGET_PATH         () { 0x00000001 }
  257. sub DDD_REMOVE_DEFINITION       () { 0x00000002 }
  258. sub DDD_EXACT_MATCH_ON_REMOVE   () { 0x00000004 }
  259. sub DDD_NO_BROADCAST_SYSTEM     () { 0x00000008 }
  260.  
  261. sub CONNECT_UPDATE_PROFILE () {0x00000001}
  262. sub CONNECT_UPDATE_RECENT () {0x00000002}
  263. sub CONNECT_TEMPORARY () {0x00000004}
  264. sub CONNECT_INTERACTIVE () {0x00000008}
  265. sub CONNECT_PROMPT () {0x00000010}
  266. sub CONNECT_NEED_DRIVE () {0x00000020}
  267. sub CONNECT_REFCOUNT () {0x00000040}
  268. sub CONNECT_REDIRECT () {0x00000080}
  269. sub CONNECT_LOCALDRIVE () {0x00000100}
  270. sub CONNECT_CURRENT_MEDIA () {0x00000200}
  271. sub CONNECT_DEFERRED () {0x00000400}
  272. sub CONNECT_RESERVED () {0xFF000000}
  273.  
  274. sub SW_HIDE () { 0 }
  275. sub SW_SHOWNORMAL () { 1 }
  276. sub SW_NORMAL () { 1 }
  277. sub SW_SHOWMINIMIZED () { 2 }
  278. sub SW_SHOWMAXIMIZED () { 3 }
  279. sub SW_MAXIMIZE () { 3 }
  280. sub SW_SHOWNOACTIVATE () { 4 }
  281. sub SW_SHOW () { 5 }
  282. sub SW_MINIMIZE () { 6 }
  283. sub SW_SHOWMINNOACTIVE () { 7 }
  284. sub SW_SHOWNA () { 8 }
  285. sub SW_RESTORE () { 9 }
  286. sub SW_SHOWDEFAULT () { 10 }
  287. sub SW_FORCEMINIMIZE () { 11 }
  288. sub SW_MAX () { 11 }
  289.  
  290. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  291.  
  292. tie $Win32::FileOp::fileop, 'Data::Lazy', sub {
  293.   new Win32::API("shell32", "SHFileOperation", ['P'], 'I')
  294.   or
  295.   die "new Win32::API::SHFileOperation: $!\n"
  296. }, &LAZY_READONLY;
  297.  
  298. tie $Win32::FileOp::copyfile, 'Data::Lazy', sub {
  299.   new Win32::API("KERNEL32", "CopyFile", [qw(P P I)], 'I')
  300.   or
  301.   die "new Win32::API::CopyFile: $!\n";
  302. }, &LAZY_READONLY;
  303.  
  304. tie $Win32::FileOp::movefileexDel, 'Data::Lazy', sub {
  305.     new Win32::API("KERNEL32", "MoveFileEx", ['P','L','N'], 'I')
  306.     or
  307.     die "new Win32::API::MoveFileEx for delete: $!\n";
  308. }, &LAZY_READONLY;
  309.  
  310. tie $Win32::FileOp::movefileex, 'Data::Lazy', sub {
  311.     new Win32::API("KERNEL32", "MoveFileEx", ['P','P','N'], 'I')
  312.     or
  313.     die "new Win32::API::MoveFileEx: $!\n";
  314. }, &LAZY_READONLY;
  315.  
  316. tie $Win32::FileOp::SHAddToRecentDocs, 'Data::Lazy', sub {
  317.     new Win32::API("shell32", "SHAddToRecentDocs", ['I','P'], 'I')
  318.     or
  319.     die "new Win32::API::SHAddToRecentDocs: $!\n";
  320. }, &LAZY_READONLY;
  321.  
  322. tie $Win32::FileOp::writeINI, 'Data::Lazy', sub {
  323.     new Win32::API("KERNEL32", "WritePrivateProfileString", [qw(P P P P)], 'I')
  324.     or
  325.     die "new Win32::API::WritePrivateProfileString: $!\n"
  326. }, &LAZY_READONLY;
  327.  
  328.  
  329. tie $Win32::FileOp::writeWININI, 'Data::Lazy', sub {
  330.     new Win32::API("KERNEL32", "WriteProfileString", [qw(P P P)], 'I')
  331.     or
  332.     die "new Win32::API::WriteProfileString: $!\n"
  333. }, &LAZY_READONLY;
  334.  
  335. tie $Win32::FileOp::deleteINI, 'Data::Lazy', sub {
  336.     new Win32::API("KERNEL32", "WritePrivateProfileString", [qw(P P L P)], 'I')
  337.     or
  338.     die "new Win32::API::WritePrivateProfileString for delete: $!\n"
  339. }, &LAZY_READONLY;
  340.  
  341. tie $Win32::FileOp::deleteWININI, 'Data::Lazy', sub {
  342.     new Win32::API("KERNEL32", "WriteProfileString", [qw(P P L)], 'I')
  343.     or
  344.     die "new Win32::API::WriteProfileString for delete: $!\n"
  345. }, &LAZY_READONLY;
  346.  
  347. tie $Win32::FileOp::readINI, 'Data::Lazy', sub {
  348.     new Win32::API("KERNEL32", "GetPrivateProfileString", [qw(P P P P N P)], 'N')
  349.     or
  350.     die "new Win32::API::GetPrivateProfileString: $!\n"
  351. }, &LAZY_READONLY;
  352.  
  353. tie $Win32::FileOp::readWININI, 'Data::Lazy', sub {
  354.     new Win32::API("KERNEL32", "GetProfileString", [qw(P P P P N)], 'N')
  355.     or
  356.     die "new Win32::API::GetProfileString: $!\n"
  357. }, &LAZY_READONLY;
  358.  
  359. tie $Win32::FileOp::GetOpenFileName, 'Data::Lazy', sub {
  360.     new Win32::API("comdlg32", "GetOpenFileName", ['P'], 'N')
  361.     or
  362.     die "new Win32::API::GetOpenFileName: $!\n"
  363. }, &LAZY_READONLY;
  364.  
  365. tie $Win32::FileOp::GetSaveFileName, 'Data::Lazy', sub {
  366.     new Win32::API("comdlg32", "GetSaveFileName", ['P'], 'N')
  367.     or
  368.     die "new Win32::API::GetSaveFileName: $!\n"
  369. }, &LAZY_READONLY;
  370.  
  371. tie $Win32::FileOp::CommDlgExtendedError, 'Data::Lazy', sub {
  372.     new Win32::API("comdlg32", "CommDlgExtendedError", [], 'N')
  373.     or
  374.     die "new Win32::API::CommDlgExtendedError: $!\n"
  375. }, &LAZY_READONLY;
  376.  
  377.  
  378. tie $Win32::FileOp::CreateFile, 'Data::Lazy', sub {
  379.     new Win32::API( "kernel32", "CreateFile", [qw(P N N P N N P)], 'N')
  380.     or
  381.     die "new Win32::API::CreateFile: $!\n"
  382. }, &LAZY_READONLY;
  383.  
  384. tie $Win32::FileOp::CloseHandle, 'Data::Lazy', sub {
  385.     new Win32::API( "kernel32", "CloseHandle", ['N'], 'N')
  386.     or
  387.     die "new Win32::API::CloseHandle: $!\n"
  388. };
  389.  
  390. tie $Win32::FileOp::GetFileSize, 'Data::Lazy', sub {
  391.     new Win32::API( "kernel32", "GetFileSize", ['N','P'], 'N')
  392.     or
  393.     die "new Win32::API::GetFileSize: $!\n"
  394. };
  395.  
  396. tie $Win32::FileOp::GetDiskFreeSpaceEx, 'Data::Lazy', sub {
  397.     new Win32::API( "kernel32", "GetDiskFreeSpaceEx", ['P','P','P','P'], 'N')
  398.     or
  399.     die "new Win32::API::GetDiskFreeSpaceEx: $!\n"
  400. };
  401.  
  402. tie $Win32::FileOp::DeviceIoControl, 'Data::Lazy', sub {
  403.     new Win32::API( "kernel32", "DeviceIoControl", ['N', 'N', 'P', 'N', 'P', 'N', 'P', 'P'], 'N')
  404.     or
  405.     die "new Win32::API::DeviceIoControl: $!\n"
  406. }, &LAZY_READONLY;
  407.  
  408. tie $Win32::FileOp::SHBrowseForFolder, 'Data::Lazy', sub {
  409.    new Win32::API("shell32", "SHBrowseForFolder", ['P'], 'N')
  410.    or
  411.    die "new Win32::API::SHBrowseForFolder: $!\n"
  412. }, &LAZY_READONLY;
  413.  
  414. tie $Win32::FileOp::SHGetPathFromIDList, 'Data::Lazy', sub {
  415.    new Win32::API("shell32", "SHGetPathFromIDList", ['N','P'], 'I')
  416.    or
  417.    die "new Win32::API::SHGetPathFromIDList: $!\n"
  418. }, &LAZY_READONLY;
  419.  
  420. tie $Win32::FileOp::SHGetSpecialFolderLocation, 'Data::Lazy', sub {
  421.    new Win32::API("shell32", "SHGetSpecialFolderLocation", ['N','I','P'], 'I')
  422.    or
  423.    die "new Win32::API::SHGetSpecialFolderLocation: $!\n"
  424. }, &LAZY_READONLY;
  425.  
  426.  
  427. tie $Win32::FileOp::GetFileVersionInfoSize, 'Data::Lazy', sub {
  428.    new Win32::API( "version", "GetFileVersionInfoSize", ['P', 'P'], 'N')
  429.    or
  430.    die "new Win32::API::GetFileVersionInfoSize: $!\n"
  431. }, &LAZY_READONLY;
  432.  
  433. tie $Win32::FileOp::GetFileVersionInfo, 'Data::Lazy', sub {
  434.    new Win32::API( "version", "GetFileVersionInfo", ['P', 'N', 'N', 'P'], 'N')
  435.    or
  436.    die "new Win32::API::GetFileVersionInfo: $!\n"
  437. }, &LAZY_READONLY;
  438.  
  439. tie $Win32::FileOp::GetCompressedFileSize, 'Data::Lazy', sub {
  440.    new Win32::API("kernel32", "GetCompressedFileSize", ['P','P'], 'L')
  441.    or
  442.    die "new Win32::API::GetCompressedFileSize: $!\n"
  443. }, &LAZY_READONLY;
  444.  
  445. tie $Win32::FileOp::VerQueryValue, 'Data::Lazy', sub {
  446.    new Win32::API( "version", "VerQueryValue", ['P', 'P', 'P', 'P'], 'N')
  447.    or
  448.    die "new Win32::API::VerQueryValue: $!\n"
  449. }, &LAZY_READONLY;
  450.  
  451. tie $Win32::FileOp::WNetAddConnection3, 'Data::Lazy', sub {
  452.   new Win32::API("mpr.dll", "WNetAddConnection3", ['L','P','P','P','L'], 'L')
  453.   or
  454.   die "new Win32::API::WNetAddConnection3: $!\n"
  455. }, &LAZY_READONLY;
  456.  
  457. tie $Win32::FileOp::WNetGetConnection, 'Data::Lazy', sub {
  458.   new Win32::API("mpr.dll", "WNetGetConnection", ['P','P','P'], 'L')
  459.   or
  460.   die "new Win32::API::WNetGetConnection: $!\n"
  461. }, &LAZY_READONLY;
  462.  
  463. tie $Win32::FileOp::WNetCancelConnection2, 'Data::Lazy', sub {
  464.   new Win32::API("mpr.dll", "WNetCancelConnection2", ['P','L','I'], 'L')
  465.   or
  466.   die "new Win32::API::WNetCancelConnection2: $!\n"
  467. }, &LAZY_READONLY;
  468.  
  469. tie $Win32::FileOp::GetLogicalDrives, 'Data::Lazy', sub {
  470.   new Win32::API("kernel32.dll", "GetLogicalDrives", [], 'N')
  471.   or
  472.   die "new Win32::API::GetLogicalDrives: $!\n"
  473. }, &LAZY_READONLY;
  474.  
  475.  
  476. tie $Win32::FileOp::QueryDosDevice, 'Data::Lazy', sub {
  477.   new Win32::API("kernel32.dll", "QueryDosDevice", ['P','P','L'], 'L')
  478.   or
  479.   die "new Win32::API::QueryDosDevice: $!\n"
  480. }, &LAZY_READONLY;
  481.  
  482. tie $Win32::FileOp::DefineDosDevice, 'Data::Lazy', sub {
  483.   new Win32::API("kernel32.dll", "DefineDosDevice", ['L','P','P'],'I')
  484.   or
  485.   die "new Win32::API::DefineDosDevice: $!\n"
  486. }, &LAZY_READONLY;
  487.  
  488. tie $Win32::FileOp::ShellExecute, 'Data::Lazy', sub {
  489.   new Win32::API("shell32", "ShellExecute", ['N','P','P','P','P','N'], 'I')
  490.   or
  491.   die "new Win32::API::ShellExecute: $!\n"
  492. }, &LAZY_READONLY;
  493.  
  494.  
  495. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  496.  
  497. sub ShellExecute {
  498.     my ($operation, $file, $params, $dir, $show, $handle) = @_;
  499.     if (@_ == 1) { #ShellExecute( $file)
  500.         $file = $operation;
  501.         $operation = undef;
  502.     } elsif (ref $file) { #ShellExecute( $file, {options})
  503.         ($params, $file, $operation) = ($file, $operation, undef);
  504.     }
  505.     if (ref $params) {
  506.         $params = { map {lc($_) => $params->{$_}} keys %$params}; # lowercase the keys
  507.         $show = $params->{show};
  508.         $dir = $params->{dir};
  509.         $handle = $params->{handle};
  510.         $params = $params->{params};
  511.     }
  512.     if (defined $show) {
  513.         $show+=0;
  514.     } else {
  515.         $show = SW_SHOWDEFAULT;
  516.     }
  517.     $handle = Win32::FileOp::GetWindowHandle unless defined $handle;
  518.  
  519.     my $result = $Win32::FileOp::ShellExecute->Call( $handle, $operation, $file, $params, $dir, $show);
  520.     return $result > 32;
  521. }
  522.  
  523. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  524.  
  525. sub Recycle {
  526.     &DeleteEx (@_, FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT |
  527.       FOF_NOERRORUI);
  528. }
  529.  
  530. sub RecycleConfirm { &DeleteEx (@_, FOF_ALLOWUNDO); }
  531.  
  532. sub RecycleEx { my $opt = pop; $opt |= FOF_ALLOWUNDO; &DeleteEx (@_, $opt); }
  533.  
  534. sub Delete {
  535.     &DeleteEx (@_, FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI);
  536. }
  537.  
  538. sub DeleteConfirm { &DeleteEx (@_, FOF_CREATEPROGRESSDLG); }
  539.  
  540. sub DeleteEx {
  541.     undef $Win32::FileOp::Error;
  542.     my $options = pop;
  543.     my ($opstruct, $filename);
  544.     my @files = map {if (/[*?]/) {glob($_)} elsif (-e $_) {$_} else {()}} @_; # since we change the names, make a copy of the list
  545.     return undef unless @files;
  546.  
  547.     # pass all files at once, join them by \0 and end by \0\0
  548.  
  549.     # fix to full paths
  550.     Relative2Absolute @files;
  551.  
  552.     $filename = join "\0", @files;
  553.     $filename .= "\0\0";        # double term the filename
  554.  
  555.     # pack fileop structure (really more like lLppIilP)
  556.     # sizeof args = l4, L4, p4, p4, I4, i4, l4, P4 = 32 bytes
  557.  
  558.     if ($Win32::FileOp::ProgressTitle and $options & FOF_SIMPLEPROGRESS) {
  559.  
  560.         $Win32::FileOp::ProgressTitle .= "\0" unless $Win32::FileOp::ProgressTitle =~ /\0$/;
  561.         $opstruct = pack ('LLpLILC2p', Win32::FileOp::GetWindowHandle, FO_DELETE,
  562.                             $filename, 0, $options, 0, 0,0, $Win32::FileOp::ProgressTitle);
  563.  
  564.     } else {
  565.  
  566.         $opstruct = pack ('LLpLILLL', Win32::FileOp::GetWindowHandle, FO_DELETE,
  567.                             $filename, 0, $options, 0, 0, 0);
  568.     }
  569.     # call delete SHFileOperation with structure
  570.  
  571.     unless ($Win32::FileOp::fileop->Call($opstruct)) {
  572.         return 1;
  573.     } else {
  574.         $! = Win32::GetLastError();
  575.         return undef;
  576.     }
  577. }
  578.  
  579. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  580.  
  581. sub RecycleConfirmEach { &_DeleteConfirmEach (@_, FOF_ALLOWUNDO); }
  582.  
  583. sub DeleteConfirmEach  { &_DeleteConfirmEach (@_, FOF_CREATEPROGRESSDLG); }
  584.  
  585. sub _DeleteConfirmEach {
  586.     undef $Win32::FileOp::Error;
  587.     my $options =  pop;
  588.  
  589.     return undef unless @_;
  590.  
  591.     my $res = 0;
  592.     my ($filename,$opstruct);
  593.     while (defined($filename = shift)) {
  594.  
  595.         Relative2Absolute $filename;
  596.         $filename .= "\0\0";        # double term the filename
  597.         my $was = -e $filename;
  598.  
  599.         if ($Win32::FileOp::ProgressTitle and $options & FOF_SIMPLEPROGRESS) {
  600.  
  601.             $Win32::FileOp::ProgressTitle .= "\0" unless $Win32::FileOp::ProgressTitle =~ /\0$/;
  602.             $opstruct = pack ('LLpLILC2p', Win32::FileOp::GetWindowHandle, FO_DELETE,
  603.                                 $filename, 0, $options, 0, 0,0, $Win32::FileOp::ProgressTitle);
  604.  
  605.         } else {
  606.  
  607.             $opstruct = pack ('LLpLILLL', Win32::FileOp::GetWindowHandle, FO_DELETE,
  608.                                 $filename, 0, $options, 0, 0, 0);
  609.         }
  610.  
  611.         # call delete SHFileOperation with structure
  612.  
  613.         unless ($Win32::FileOp::fileop->Call($opstruct)) {
  614.             $res++ if ($was and !-e $filename);
  615.         } else {
  616.             $! = Win32::GetLastError();
  617.         }
  618.     }
  619.     $res;
  620. }
  621.  
  622. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  623.  
  624. sub Copy {
  625.     &_MoveOrCopyEx (@_, FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR |
  626.     FOF_SILENT # | FOF_NOERRORUI
  627.       , FO_COPY);
  628. }
  629.  
  630. sub CopyConfirm { &_MoveOrCopyEx (@_, FOF_CREATEPROGRESSDLG, FO_COPY); }
  631.  
  632. *CopyConfirmEach = \&CopyConfirm;
  633.  
  634. sub CopyEx { &_MoveOrCopyEx (@_, FO_COPY); }
  635.  
  636. sub Move   {
  637.     &_MoveOrCopyEx (@_, FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_SILENT # | FOF_NOERRORUI
  638.       , FO_MOVE);
  639. }
  640.  
  641. sub MoveConfirm { &_MoveOrCopyEx (@_, FOF_CREATEPROGRESSDLG, FO_MOVE); }
  642.  
  643. *MoveConfirmEach = \&MoveConfirm;
  644.  
  645. sub MoveEx { &_MoveOrCopyEx (@_, FO_MOVE); }
  646.  
  647. sub _MoveOrCopyEx {
  648.     undef $Win32::FileOp::Error;
  649.     my $func = pop;
  650.     my $options = pop;
  651.     my ($opstruct, $filename, $hash, $res, $from, $to);
  652.  
  653.     if (@_ % 2) { die "Wrong number of arguments to Win32::FileOp::CopyEx!\n" };
  654.  
  655.     my $i = 0;
  656.     while (defined ($from = $_[$i++]) and defined ($to = $_[$i++])) {
  657.  
  658.     # fix to full paths
  659.  
  660.         if (UNIVERSAL::isa($from, "ARRAY")) {
  661.  
  662.             my @files = map {
  663.                 my $s = $_;
  664.                 Relative2Absolute $s;
  665.                 $s;
  666.             } @$from;
  667.             $from = join "\0", @files;
  668.  
  669.         } else {
  670.  
  671.             Relative2Absolute $from;
  672.             $from =~ s#/#\\#g;
  673.  
  674.             # if to ends in slash, get filename from from
  675.  
  676.             if ($to =~ m{[\\/]$} and $to !~ /^\w:\\$/) {
  677.                 my $tmp = $from;
  678.                 $tmp =~ s#^.*[\\/](.*?)$#$1#;
  679.                 $to .= $tmp;
  680.             }
  681.             $to .= '\\' if $to =~ /:$/;
  682.         }
  683.         $from .= "\0\0";        # double term the filename
  684.  
  685.         my $options = $options;
  686.         if (UNIVERSAL::isa($to, "ARRAY")) {
  687.             my $strto='';
  688.             foreach (@$to) {
  689.                 $strto .= RelativeToAbsolute($_) . "\0";
  690.             }
  691.             $to = $strto;
  692.             $options |= FOF_MULTIDESTFILES;
  693.         } else {
  694.             Relative2Absolute($to);
  695.         }
  696.         $to .= "\0\0";        # double term the filename
  697.         $to =~ s#/#\\#g;
  698.  
  699.         if ($Win32::FileOp::ProgressTitle and $options & FOF_SIMPLEPROGRESS) {
  700.  
  701.             $Win32::FileOp::ProgressTitle .= "\0" unless $Win32::FileOp::ProgressTitle =~ /\0$/;
  702.             $opstruct = pack ('LLppILC2p', Win32::FileOp::GetWindowHandle, $func,
  703.               $from, $to, $options, 0, 0,0, $Win32::FileOp::ProgressTitle);
  704.  
  705.         } else {
  706.  
  707.             $opstruct = pack ('LLppILLL', Win32::FileOp::GetWindowHandle, $func,
  708.               $from, $to, $options, 0, 0, 0);
  709.  
  710.         }
  711.  
  712.         unless ($Win32::FileOp::fileop->Call($opstruct)) {
  713.             $res++;
  714.         } else {
  715.             $! = Win32::GetLastError();
  716.             return undef;
  717.         }
  718.     }
  719.     $res;
  720. }
  721.  
  722. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  723.  
  724. sub MoveFile {
  725.     MoveFileEx(@_,MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED);
  726. }
  727.  
  728. sub MoveAtReboot {
  729.     if (Win32::IsWinNT) {
  730.         MoveFileEx(@_,MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT);
  731.     } else {
  732.         undef $Win32::FileOp::Error;
  733.         my @a;
  734.         my $i=0;
  735.         while ($_[$i]) {
  736.             $a[$i+1]= Win32::GetShortPathName $_[$i];
  737.             ($a[$i]= $_[$i+1]) =~ s#^(.*)([/\\].*?)$#Win32::GetShortPathName($1).$2#e;
  738.             $i+=2;
  739.         }
  740.         Relative2Absolute(@a);
  741.         WriteToINI($ENV{WINDIR}.'\\wininit.ini','Rename',@a);
  742.     }
  743. }
  744.  
  745. sub CopyFile {
  746.     undef $Win32::FileOp::Error;
  747.     my ($from,$to);
  748.  
  749.     while (defined($from = shift) and defined($to = shift)) {
  750. #        Relative2Absolute($to,$from);
  751.         $to .= "\0";
  752.         $from .= "\0";
  753.         $Win32::FileOp::copyfile->Call($from,$to, 0);
  754.     }
  755. }
  756.  
  757.  
  758. sub DeleteAtReboot {
  759.     undef $Win32::FileOp::Error;
  760.     if (Win32::IsWinNT)  {
  761.         my $file;
  762.         while (defined($file = shift)) {
  763.             Relative2Absolute($file);
  764.             $Win32::FileOp::movefileexDel->Call($file, 0, MOVEFILE_DELAY_UNTIL_REBOOT);
  765.         }
  766.     } else {
  767.         my @a;
  768.         foreach (@_) {
  769.             my $tmp=$_;
  770.             Relative2Absolute($tmp);
  771.             $tmp = Win32::GetShortPathName $tmp;
  772.             push @a, 'NUL', $tmp;
  773.         }
  774.         WriteToINI($ENV{WINDIR}.'\\wininit.ini','Rename',@a);
  775.     }
  776.     1;
  777. }
  778.  
  779. sub MoveFileEx {
  780.     undef $Win32::FileOp::Error;
  781.     my $options = pop;
  782.  
  783.     my ($from,$to);
  784.     while (defined($from = shift) and defined($to = shift)) {
  785.         Relative2Absolute($to,$from);
  786.         $to .= "\0";
  787.         $from .= "\0";
  788.         $Win32::FileOp::movefileex->Call($from,$to, $options);
  789.     }
  790. }
  791.  
  792. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  793.  
  794. sub UpdateDir {
  795.  undef $Win32::FileOp::Error;
  796.  local ($Win32::FileOp::from,$Win32::FileOp::to,$Win32::FileOp::callback) = @_;
  797.  -d $Win32::FileOp::from or return undef;
  798.  -d $Win32::FileOp::to or File::Path::mkpath $Win32::FileOp::to, 0777 or return undef;
  799.  Relative2Absolute($Win32::FileOp::to);
  800.  my $olddir = cwd;
  801.  chdir $Win32::FileOp::from;
  802.  find(\&_UpdateDir, '.');
  803.  chdir $olddir;
  804. }
  805.  
  806. sub _UpdateDir {
  807.   undef $Win32::FileOp::Error;
  808.   my $fullto = "$Win32::FileOp::to\\$File::Find::dir\\$_";
  809.   $fullto =~ s#/#\\#g;
  810.   $fullto =~ s#\\\.\\#\\#;
  811.   if (-d $_) {
  812.     return if /^\.\.?$/ or -d $fullto;
  813.     mkdir $fullto, 0777;
  814.   } else {
  815.     my $age = -M($fullto);
  816.     if (! -e($fullto) or $age > -M($_)) {
  817.       if (! defined $Win32::FileOp::callback or &$Win32::FileOp::callback()) {
  818.         CopyFile $_, $fullto;
  819.       }
  820.     }
  821.   }
  822. }
  823.  
  824.  
  825. sub FillInDir {
  826.  undef $Win32::FileOp::Error;
  827.  local ($Win32::FileOp::from,$Win32::FileOp::to,$Win32::FileOp::callback) = @_;
  828.  -d $Win32::FileOp::from or return undef;
  829.  -d $Win32::FileOp::to or File::Path::mkpath $Win32::FileOp::to, 0777 or return undef;
  830.  Relative2Absolute($Win32::FileOp::to);
  831.  my $olddir = cwd;
  832.  chdir $Win32::FileOp::from;
  833.  find(\&_FillInDir, '.');
  834.  chdir $olddir;
  835. }
  836.  
  837. sub _FillInDir {
  838.   my $fullto = "$Win32::FileOp::to\\$File::Find::dir\\$_";
  839.   $fullto =~ s#/#\\#g;
  840.   $fullto =~ s#\\\.\\#\\#;
  841.   if (-d $_) {
  842.     return if /^\.\.?$/ or -d $fullto;
  843.     mkdir $fullto, 0777;
  844.   } else {
  845.     if (! -e($fullto)) {
  846.       if (! defined $Win32::FileOp::callback or &$Win32::FileOp::callback()) {
  847.         CopyFile $_, $fullto;
  848.       }
  849.     }
  850.   }
  851. }
  852.  
  853. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  854.  
  855. sub AddToRecentDocs {
  856.  undef $Win32::FileOp::Error;
  857.  
  858.  my $file;
  859.  my $res=0;
  860.  while (defined($file = shift)) {
  861.   next unless -e $file;
  862.   Relative2Absolute($file);
  863.   $file .= "\0";
  864.   $Win32::FileOp::SHAddToRecentDocs->Call(2,$file);
  865.   $res++;
  866.  }
  867.  $res;
  868. }
  869.  
  870. sub EmptyRecentDocs {
  871.  undef $Win32::FileOp::Error;
  872.  my $x = 0;
  873.  $Win32::FileOp::SHAddToRecentDocs->Call(2,$x);
  874. }
  875.  
  876. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  877.  
  878. sub WriteToINI {
  879.     undef $Win32::FileOp::Error;
  880.     my $INI = RelativeToAbsolute(shift());$INI .= "\0";
  881.     my $section = shift;$section .= "\0";
  882.     my ($name,$value);
  883.     while (defined($name = shift) and defined($value = shift)) {
  884.         $name .= "\0";$value .= "\0";
  885.         $Win32::FileOp::writeINI->Call($section,$name,$value,$INI)
  886.         or return undef;
  887.     }
  888.     1;
  889. }
  890.  
  891. sub WriteToWININI {
  892.     undef $Win32::FileOp::Error;
  893.     my $section = shift;$section .= "\0";
  894.     my ($name,$value);
  895.     while (defined($name = shift) and defined($value = shift)) {
  896.         $name .= "\0";$value .= "\0";
  897.         $Win32::FileOp::writeWININI->Call($section,$name,$value)
  898.         or return undef;
  899.     }
  900.     1;
  901. }
  902.  
  903. sub DeleteFromINI {
  904.     undef $Win32::FileOp::Error;
  905.     my $INI = RelativeToAbsolute(shift());$INI .= "\0";
  906.     my $section = shift;$section .= "\0";
  907.     my $name;
  908.     while (defined($name = shift)) {
  909.         $name .= "\0";
  910.         $Win32::FileOp::deleteINI->Call($section,$name,0,$INI)
  911.         or return undef;
  912.     }
  913.     1;
  914. }
  915.  
  916. sub DeleteFromWININI {
  917.     undef $Win32::FileOp::Error;
  918.     my $section = shift;$section .= "\0";
  919.     my $name;
  920.     while (defined($name = shift)) {
  921.         $name .= "\0";
  922.         $Win32::FileOp::deleteWININI->Call($section,$name,0)
  923.         or return undef;
  924.     }
  925.     1;
  926. }
  927.  
  928. sub ReadINI {
  929.     undef $Win32::FileOp::Error;
  930.     my $INI = RelativeToAbsolute(shift());$INI .= "\0";
  931.     my $section = shift;$section .= "\0";
  932.     my $name = shift;$name .= "\0";
  933.     my $default = shift;$default .= "\0";
  934.     my $value = _ReadINI($section,$name,$default,$INI);
  935.  
  936.     $value =~ s/\0.*$// or return;
  937.     return $value;
  938. }
  939.  
  940. # MTY hack : Michael Yamada <myamada@gj.com>
  941. sub ReadINISectionKeys {
  942.     undef $Win32::FileOp::Error;
  943.     my $INI = RelativeToAbsolute(shift());$INI='win.ini' unless $INI;$INI .= "\0";
  944.     my $section = shift;$section .= "\0";
  945.     my $name = 0; # pass null to API
  946.     my $default = "\0";
  947.     my @values;
  948.  
  949.     @values = split(/\0/,_ReadINI($section,$name,$default,$INI));
  950.     @{$_[0]} = @values if (UNIVERSAL::isa($_[0], "ARRAY"));
  951.     return wantarray() ? @values : (@values ? \@values : undef);
  952. }
  953. # END MTY Hack
  954.  
  955. sub ReadINISections {
  956.     undef $Win32::FileOp::Error;
  957.     my $INI = RelativeToAbsolute(shift());$INI='win.ini' unless $INI;$INI .= "\0";
  958.     my $section = 0; # pass null to API
  959.     my $name = 0;
  960.     my $default = "\0";
  961.     my @values;
  962.  
  963.     @values = split(/\0/,_ReadINI($section,$name,$default,$INI));
  964.     @{$_[0]} = @values if (UNIVERSAL::isa($_[0], "ARRAY"));
  965.     return wantarray() ? @values : (@values ? \@values : undef);
  966. }
  967.  
  968.  
  969. sub ReadWININI {
  970.     undef $Win32::FileOp::Error;
  971.     my $section = shift;$section .= "\0";
  972.     my $name = shift;$name .= "\0";
  973.     my $default = shift;$default .= "\0";
  974.     my $value = "\0" x 2048;
  975.  
  976.     $Win32::FileOp::readWININI->Call($section,$name,$default,$value,256)
  977.     or return undef;
  978.  
  979.     $value =~ s/\0.*$// or return;
  980.     return $value;
  981. }
  982.  
  983. sub _ReadINI { # $section, $name, $default, $INI
  984.     my $size = 10;#24;
  985.     my $value = "\0" x $size; # large buffer to accomodate many keys
  986.     my $retsize = $size-2;
  987.     while ($size-$retsize <=2) {
  988.      $size*=2;$value = "\0" x $size;
  989.      $retsize = $Win32::FileOp::readINI->Call($_[0],$_[1],$_[2],$value,$size,$_[3])
  990.      or return '';
  991.     }
  992.     return $value;
  993. }
  994.  
  995. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  996.  
  997. sub OpenDialog {
  998.    OpenOrSaveDialog($Win32::FileOp::GetOpenFileName,@_);
  999. }
  1000.  
  1001. sub SaveAsDialog {
  1002.    OpenOrSaveDialog($Win32::FileOp::GetSaveFileName,@_);
  1003. }
  1004.  
  1005. sub OpenOrSaveDialog {
  1006.     undef $Win32::FileOp::Error;
  1007.     my $fun = shift;
  1008.     my $params;
  1009.     if (UNIVERSAL::isa($_[0], "HASH")) {
  1010.         $params = $_[0];
  1011.         $params->{filename} = $_[1] if defined $_[1];
  1012.     } else {
  1013.         if (@_ % 2) {
  1014.             my $filename = pop;
  1015.             $params = {@_};
  1016.             $params->{filename} = $filename;
  1017.         } else {
  1018.             $params = {@_};
  1019.         }
  1020.     }
  1021.     foreach (grep {s/^-//} keys %$params) {$params->{$_} = $params->{"-$_"};delete $params->{"-$_"}};
  1022.  
  1023.     $params->{handle} = 'self' unless exists $params->{handle};
  1024.     $params->{options} = 0 unless exists $params->{options};
  1025.  
  1026.  
  1027.     my $lpstrFilter = '';
  1028.     if (UNIVERSAL::isa($params->{filters}, "HASH")) {
  1029.         foreach (keys %{$params->{filters}}) {
  1030.             $lpstrFilter .= $_ . "\0" . $params->{filters}->{$_} . "\0";
  1031.         }
  1032.     } elsif (UNIVERSAL::isa($params->{filters}, "ARRAY")) {
  1033.         my ($title,$filter,$i);
  1034.         $i=0;$lpstrFilter='';
  1035.         while ($title = ${$params->{filters}}[$i++] and $filter = ${$params->{filters}}[$i++]) {
  1036.             $lpstrFilter .= $title . "\0" . $filter . "\0";
  1037.         }
  1038.         $params->{defaultfilter} = $title if $title && !$params->{defaultfilter};
  1039.     } elsif ($params->{filters}) {
  1040.         $lpstrFilter = $params->{filters};
  1041.         $lpstrFilter .= "\0\0" unless $lpstrFilter =~ /\0\0$/
  1042.     } else {
  1043.         $lpstrFilter = "\0\0";
  1044.     }
  1045.  
  1046. local $^W = 0;
  1047.  
  1048.     my $nFilterIndex = $params->{defaultfilter};
  1049.     $nFilterIndex = 1 unless $nFilterIndex>0; # to be sure it's a reasonable number
  1050.  
  1051.     my $lpstrFile = $params->{filename}."\0".
  1052.     ($params->{options} & OFN_ALLOWMULTISELECT
  1053.      ? ' ' x ($Win32::FileOp::BufferSize - length $params->{filename})
  1054.      : ' ' x 256
  1055.     );
  1056.  
  1057.     my $lpstrFileTitle = "\0";
  1058.     my $lpstrInitialDir = $params->{dir} . "\0";
  1059.     my $lpstrTitle  = $params->{title} . "\0";
  1060.     my $Flags = $params->{options};
  1061.     my $nFileExtension = "\0\0";
  1062.     my $lpstrDefExt = $params->{extension}."\0";
  1063.     my $lpTemplateName = "\0";
  1064.     my $Handle = $params->{handle};
  1065.     if ($Handle =~ /^self$/i) {$Handle = GetWindowHandle()};
  1066.  
  1067. #    my $struct = pack "LLLpLLLpLpLppLIIpLLp",
  1068.     my $struct = pack "LLLpLLLpLpLppLIppLLp",
  1069.      (
  1070.       76,                        #'lStructSize'       #  DWORD
  1071.       $Handle,                   #'hwndOwner'         #  HWND
  1072.       0,                         #'hInstance'         #  HINSTANCE
  1073.       $lpstrFilter,              #'lpstrFilter'       #  LPCTSTR
  1074.       0,
  1075.       0,
  1076. #     $lpstrCustomFilter,        #'lpstrCustomFilter' #  LPTSTR
  1077. #     length $lpstrCustomFilter, #'nMaxCustFilter'    #  DWORD
  1078. #I'm not able to make it work with CustomFilter
  1079.  
  1080.       $nFilterIndex,                         #'nFilterIndex'      #  DWORD
  1081.       $lpstrFile,                #'lpstrFile'         #  LPTSTR
  1082.       length $lpstrFile,         #'nMaxFile'          #  DWORD
  1083.       $lpstrFileTitle,           #'lpstrFileTitle'    #  LPTSTR
  1084.       length $lpstrFileTitle,    #'nMaxFileTitle'     #  DWORD
  1085.       $lpstrInitialDir,          #'lpstrInitialDir'   #  LPCTSTR
  1086.       $lpstrTitle,               #'lpstrTitle'        #  LPCTSTR
  1087.       $Flags,                    #'Flags'             #  DWORD
  1088.       0,                         #'nFileOffset'       #  WORD
  1089. #      0,                         #'nFileExtension'    #  WORD
  1090.       $nFileExtension,           #'nFileExtension'    #  WORD
  1091.       $lpstrDefExt,              #'lpstrDefExt'       #  LPCTSTR
  1092.       0,                         #'lCustData'         #  DWORD
  1093.       0,                         #'lpfnHook'          #  LPOFNHOOKPROC
  1094.       $lpTemplateName            #'lpTemplateName'    #  LPCTSTR
  1095.      );
  1096.  
  1097.    if ($fun->Call($struct)) {
  1098.         $Flags = unpack("L", substr $struct, 52, 4);
  1099.         $Win32::FileOp::SelectedFilter = unpack("L", substr $struct, 6*4, 4);
  1100.  
  1101.         $Win32::FileOp::ReadOnly = ($Flags & OFN_READONLY);
  1102.  
  1103.         if ($Flags & OFN_ALLOWMULTISELECT) {
  1104.             $lpstrFile =~ s/\0\0.*$//;
  1105.             my @result;
  1106.             if ($Flags & OFN_EXPLORER) {
  1107.                 @result = split "\0", $lpstrFile;
  1108.             } else {
  1109.                 @result = split " ", $lpstrFile;
  1110.             }
  1111.             my $dir = shift @result;
  1112.             $dir =~ s/\\$//; # only happens in root
  1113.             return $dir unless @result;
  1114.             return map {$dir . '\\' . $_} @result;
  1115.         } else {
  1116.            $lpstrFile =~ s/\0.*$//;
  1117.            return $lpstrFile;
  1118.         }
  1119. #   } else {
  1120. #    my $err = $Win32::FileOp::Error = $Win32::FileOp::CommDlgExtendedError->Call();
  1121. #    if ($err == 12291)  {
  1122. #        print "Shit, the buffer was too small!\n";
  1123. #        $fun->Call($struct);
  1124. #    }
  1125.    }
  1126.    return;
  1127. }
  1128.  
  1129. #=======================
  1130.  
  1131. sub BrowseForFolder {
  1132.    undef $Win32::FileOp::Error;
  1133.    my ($hwndOwner, $pidlRoot, $pszDisplayName,
  1134.        $lpszTitle, $nFolder, $ulFlags,
  1135.        $lpfn, $lParam, $iImage, $pszPath)
  1136.       =
  1137.       (GetWindowHandle(), "\0"x260, "\0"x260,
  1138.        shift() || "\0", shift() || 0, (shift() || 0) | 0x0000,
  1139.        0, 0, 0, "\0"x260);
  1140.  
  1141.    $nFolder = CSIDL_DRIVES() unless defined $nFolder;
  1142.  
  1143.    $Win32::FileOp::SHGetSpecialFolderLocation->Call($hwndOwner, $nFolder, $pidlRoot)
  1144.    and return undef;
  1145. #   $pidlRoot =~ s/\0.*$//s;
  1146.    $pidlRoot = hex unpack 'H*',(join'', reverse split//, $pidlRoot);
  1147.  
  1148.    my $browseinfo = pack 'LLppILLI',
  1149.       ($hwndOwner, $pidlRoot, $pszDisplayName, $lpszTitle,
  1150.        $ulFlags, $lpfn, $lParam, $iImage);
  1151.  
  1152.    my $bool = $Win32::FileOp::SHGetPathFromIDList->Call(
  1153.                $Win32::FileOp::SHBrowseForFolder->Call($browseinfo),
  1154.                $pszPath
  1155.               );
  1156.  
  1157.    $pszPath =~ s/\0.*$//s;
  1158.    $bool ? $pszPath : undef;
  1159. }
  1160.  
  1161. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1162.  
  1163. sub FindInPATH {
  1164.     undef $Win32::FileOp::Error;
  1165.     my $file = shift;
  1166.     return $file if -e $file;
  1167.     foreach (split ';',$ENV{PATH}) {
  1168.         return $_.'/'.$file if -e $_.'/'.$file;
  1169.     }
  1170.     return undef;
  1171. }
  1172. *FindInPath = \&FindInPATH;
  1173.  
  1174.  
  1175. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1176.  
  1177. sub GetDesktopHandle {
  1178.     undef $Win32::FileOp::Error;
  1179.     my ($function, $handle);
  1180.  
  1181. # if handle already saved, use that one
  1182.  
  1183.     return $Win32::FileOp::DesktopHandle if $Win32::FileOp::DesktopHandle != 0;
  1184.  
  1185. # find GetDesktopWindow routine
  1186.  
  1187. $function = new Win32::API("user32", "GetDesktopWindow", [], 'I') or
  1188.   die "new Win32::API::GetDesktopHandle: $!\n";
  1189.  
  1190. # call it, get window handle back, save it and return it
  1191.  
  1192. $Win32::FileOp::DesktopHandle = $function->Call();
  1193.  
  1194. }
  1195.  
  1196. sub GetWindowHandle {
  1197.     undef $Win32::FileOp::Error;
  1198.     if (! $Win32::FileOp::WindowHandle) {
  1199.         my $GetConsoleTitle = new Win32::API("kernel32", "GetConsoleTitle", ['P','N'],'N');
  1200.         my $SetConsoleTitle = new Win32::API("kernel32", "SetConsoleTitle", ['P'],'N');
  1201.         my $SleepEx = new Win32::API("kernel32", "SleepEx", ['N','I'],'V');
  1202.         my $FindWindow = new Win32::API("user32", "FindWindow", ['P','P'],'N');
  1203.  
  1204.         my $oldtitle = " " x 1024;
  1205.         $GetConsoleTitle->Call($oldtitle, 1024);
  1206.         my $newtitle = sprintf("PERL-%d-%d", Win32::GetTickCount(), $$);
  1207.         $SetConsoleTitle->Call($newtitle);
  1208.         $SleepEx->Call(40,1);
  1209.         $Win32::FileOp::WindowHandle = $FindWindow->Call(0, $newtitle);
  1210.         $SetConsoleTitle->Call($oldtitle);
  1211.     }
  1212.     return $Win32::FileOp::WindowHandle;
  1213. }
  1214.  
  1215. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1216.  
  1217. sub SetCompression {
  1218.     undef $Win32::FileOp::Error;
  1219.     my $file;
  1220.     my $flag;
  1221.     if ($_[-1] eq ($_[-1]+0)) {
  1222.         $flag = pop
  1223.     } else {
  1224.         $flag = 1;
  1225.     }
  1226.     $_[0] = $_ unless @_;
  1227.     while (defined($file = shift)) {
  1228.  
  1229. #print "\t$file\n";
  1230.  
  1231.      my $handle;
  1232.      $handle = $Win32::FileOp::CreateFile->Call($file, 0xc0000000, # FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES |
  1233.         7, 0, 3, 0x2000000, 0);
  1234. #     $handle = $Win32::FileOp::CreateFile->Call($file, FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED,
  1235. #     FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0,
  1236. #     OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
  1237.  
  1238.      if($handle != -1) {
  1239.          my $br = pack("L", 0);
  1240.          my $inbuffer = pack("S", $flag);
  1241.          my $comp = $Win32::FileOp::DeviceIoControl->Call(
  1242.              $handle, 639040, $inbuffer, 2, 0, 0, $br, 0,
  1243.          );
  1244.          if(!$comp) {
  1245.              $Win32::FileOp::Error = "DeviceIoControl failed: "
  1246.                 . Win32::FormatMessage(Win32::GetLastError);
  1247.              return undef;
  1248.          }
  1249.          $Win32::FileOp::CloseHandle->Call($handle);
  1250.          next;
  1251.      } else {
  1252.          $Win32::FileOp::Error = "CreateFile failed: "
  1253.             . Win32::FormatMessage(Win32::GetLastError);
  1254.          return undef;
  1255.      }
  1256.     }
  1257.     return 1;
  1258. }
  1259.  
  1260. sub GetCompression {
  1261.     undef $Win32::FileOp::Error;
  1262.     my ($file) = @_;
  1263.     $file = $_ unless defined $file;
  1264.     my $permission = 0x0080; # FILE_READ_ATTRIBUTES
  1265.     my $handle = $Win32::FileOp::CreateFile->Call($file, $permission, 0, 0, 3, 0, 0);
  1266.     if($handle != -1) {
  1267.         my $br = pack("L", 0);
  1268.         my $outbuffer = pack("S", 0);
  1269.         my $comp = $Win32::FileOp::DeviceIoControl->Call(
  1270.             $handle, 589884, 0, 0, $outbuffer, 2, $br, 0,
  1271.         );
  1272.         if(!$comp) {
  1273.             $Win32::FileOp::Error = "DeviceIoControl failed: "
  1274.                . Win32::FormatMessage(Win32::GetLastError);
  1275.             return undef;
  1276.         }
  1277.         $Win32::FileOp::CloseHandle->Call($handle);
  1278.         return unpack("S", $outbuffer);
  1279.     } else {
  1280.         $Win32::FileOp::Error = "CreateFile failed: ",
  1281.          Win32::FormatMessage(Win32::GetLastError);
  1282.         return undef;
  1283.     }
  1284. }
  1285.  
  1286. sub Compress {SetCompression(@_,1)}
  1287. sub Uncompress {SetCompression(@_,0)}
  1288. *UnCompress = \&Uncompress;
  1289. sub Compressed {&GetCompression}
  1290.  
  1291. sub CompressedSize {
  1292.  my $file = $_[0];
  1293.  my $hsize = "\0" x 4;
  1294.  my $lsize = $Win32::FileOp::GetCompressedFileSize->Call( $file, $hsize);
  1295.  return $lsize + 0x10000*unpack('L',$hsize);
  1296. }
  1297.  
  1298. sub UncompressDir {
  1299.     undef $Win32::FileOp::Error;
  1300.     if (ref $_[-1] eq 'CODE') {
  1301.         my $fun = pop;
  1302.         find( sub{Uncompress if &$fun}, @_);
  1303.     } else {
  1304.         find( sub {Uncompress}, @_);
  1305.     }
  1306. }
  1307. *UnCompressDir = \&UncompressDir;
  1308.  
  1309. sub CompressDir {
  1310.     undef $Win32::FileOp::Error;
  1311.     if (ref $_[-1] eq 'CODE') {
  1312.         my $fun = pop;
  1313.         find( sub{Compress if &$fun}, @_);
  1314.     } else {
  1315.         find( sub {Compress}, @_);
  1316.     }
  1317. }
  1318.  
  1319. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1320.  
  1321. sub GetLargeFileSize {
  1322.     undef $Win32::FileOp::Error;
  1323.     my ($file) = @_;
  1324.     my $handle = $Win32::FileOp::CreateFile->Call($file, 0x0080, 0, 0, 3, 0, 0); # 0x0080 = FILE_READ_ATTRIBUTES
  1325.     if($handle != -1) {
  1326.         my $buff = "\0" x 4;
  1327.         my $size1 = $Win32::FileOp::GetFileSize->Call(
  1328.             $handle, $buff
  1329.         );
  1330.         $Win32::FileOp::CloseHandle->Call($handle);
  1331.         $size1 = $size1 & 0xFFFFFFFF;
  1332.         if (wantarray()) {
  1333.             return ($size1,unpack('L',$buff));
  1334.         } else {
  1335.             return unpack('L',$buff)*0xFFFFFFFF + $size1
  1336.         }
  1337.     } else {
  1338.         $Win32::FileOp::Error = "CreateFile failed: ".Win32::FormatMessage(Win32::GetLastError);
  1339.         return undef;
  1340.     }
  1341. }
  1342.  
  1343. sub GetDiskFreeSpace {
  1344.     undef $Win32::FileOp::Error;
  1345.     my ($file) = @_;
  1346.     $file .= '\\' if $file =~ /^\\\\/ and $file !~ /\\$/;
  1347.     $file .= ':' if $file =~ /^[a-zA-Z]$/;
  1348.     my ($freePerUser,$total, $free) = ("\x0" x 8) x 3;
  1349.  
  1350.     $Win32::FileOp::GetDiskFreeSpaceEx->Call($file, $freePerUser,$total, $free)
  1351.         or return;
  1352.  
  1353.     if (wantarray()) {
  1354.         my @res;
  1355.         for ($freePerUser,$total, $free) {
  1356.             my ($lo,$hi) = unpack('LL',$_);
  1357.             push @res, ($hi & 0xFFFFFFFF) * 0xFFFFFFFF + ($lo & 0xFFFFFFFF);
  1358.         }
  1359.         return @res;
  1360.     } else {
  1361.         my ($lo,$hi) = unpack('LL',$freePerUser);
  1362.         return ($hi & 0xFFFFFFFF) * 0xFFFFFFFF + ($lo & 0xFFFFFFFF);
  1363.     }
  1364. }
  1365.  
  1366. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1367.  
  1368. sub FreeDriveLetters {
  1369.    undef $Win32::FileOp::Error;
  1370.    my (@dr, $i);
  1371.  
  1372.    my $bitmask = $Win32::FileOp::GetLogicalDrives->Call();
  1373.    for $i(0..25) {
  1374.      push (@dr, ('A'..'Z')[$i]) unless $bitmask & 2**$i;
  1375.    }
  1376.    @dr;
  1377. }
  1378.  
  1379.  
  1380. sub Map {
  1381.  undef $Win32::FileOp::Error;
  1382.  my $disk = $_[0] =~ m#^[\\/]# ? (FreeDriveLetters())[-1] : shift;
  1383.  if (!defined $disk or $disk eq '') {
  1384.   undef $disk;
  1385.  } else {
  1386.   $disk =~ s/^(\w)(:)?$/$1:/;
  1387.   $disk .= "\0";
  1388.  }
  1389.  my $type = 0; # RESOURCETYPE_ANY
  1390.  my $share = shift || croak('Ussage: Win32::FileOp::Map([$drive,]$share[,\%options])',"\n");
  1391.  $share =~ s{/}{\\}g;
  1392.  $share .= "\0";
  1393.  
  1394.  my $opt = shift || {};
  1395.  croak 'Ussage: Win32::FileOp::Map([$drive,]$share[,\%options])',"\n"
  1396.   unless (UNIVERSAL::isa($opt, "HASH"));
  1397.  my $username = 0;
  1398.  if (defined $opt->{user}) {
  1399.   $username = $opt->{user}."\0";
  1400. #  $username =~ s/(.)/\0$1/g if Win32::IsWinNT;
  1401.  }
  1402.  my $passwd = 0;
  1403.  if (defined $opt->{passwd} or defined $opt->{password} or defined $opt->{pwd}) {
  1404.   $passwd = ($opt->{passwd} || $opt->{password} || $opt->{pwd})."\0";
  1405. #  $passwd =~ s/(.)/\0$1/g if Win32::IsWinNT;
  1406.  }
  1407.  my $options = 0;
  1408.  $options += CONNECT_UPDATE_PROFILE if $opt->{persistent};
  1409.  $options += CONNECT_INTERACTIVE if $opt->{interactive};
  1410.  $options += CONNECT_PROMPT if $opt->{prompt};
  1411.  $options += CONNECT_REDIRECT if $opt->{redirect};
  1412.  
  1413. $options += CONNECT_UPDATE_RECENT;
  1414.  
  1415.  my $struct = pack('LLLLppLL',0,$type,0,0,$disk,$share,0,0);
  1416.  my $res;
  1417.  my $handle = undef;
  1418.  if ($opt->{interactive}) {
  1419.      $handle = $opt->{interactive}+0;
  1420.      $handle = GetWindowHandle() || GetDesktopHandle();
  1421.  }
  1422.  
  1423.  if ($res = $Win32::FileOp::WNetAddConnection3->Call( $handle, $struct, $passwd, $username, $options)) {
  1424.     if (($res == 1202 or $res == 85) and ($opt->{overwrite} or $opt->{force_overwrite})) {
  1425.         Unmap($disk,{force => $opt->{force_overwrite}})
  1426.             or return;
  1427.         $Win32::FileOp::WNetAddConnection3->Call( $handle, $struct, $passwd, $username, $options)
  1428.             and return;
  1429.     } elsif ($res == 997) { # Overlapped I/O operation is in progress.
  1430.         return 1;
  1431.     } else {
  1432.         return;
  1433.     }
  1434.  }
  1435.  if (defined $disk and $disk) {$disk} else {1};
  1436. }
  1437.  
  1438. sub Connect {
  1439.     Map(undef,@_);
  1440. }
  1441.  
  1442. sub Disconnect {
  1443.  undef $Win32::FileOp::Error;
  1444.  croak 'Ussage: Win32::FileOp::Map([$drive,]$share[,\%options])',"\n"
  1445.   unless @_;
  1446.  my $disk = shift() . "\0";$disk =~ s/^(\w)\0$/$1:\0/;
  1447.  my $opt = shift() || {};
  1448.  croak 'Ussage: Win32::FileOp::Map([$drive,]$share[,\%options])',"\n"
  1449.   unless (UNIVERSAL::isa($opt, "HASH"));
  1450.  my $options = $opt->{persistent} ? 1 : 0;
  1451.  my $force   = $opt->{force} ? 1 : 0;
  1452.  
  1453.  $Win32::FileOp::WNetCancelConnection2->Call($disk,$options,$force)
  1454.   and return;
  1455.  1;
  1456. }
  1457.  
  1458. sub Unmap {
  1459.     undef $Win32::FileOp::Error;
  1460.     if (UNIVERSAL::isa($_[1], "HASH")) {
  1461.         $_[1]->{persistent} = 1 unless exists $_[1]->{persistent};
  1462.     } else {
  1463.         $_[1] = {persistent => 1}
  1464.     }
  1465.     goto &Disconnect;
  1466. }
  1467.  
  1468. sub Mapped {
  1469.  undef $Win32::FileOp::Error;
  1470.  goto &_MappedAll unless (@_);
  1471.  my $disk = shift();
  1472.  if ($disk =~ m#^[\\/][\\/]#) {
  1473.     $disk =~ tr#/#\\#;
  1474.     $disk = uc $disk;
  1475.     my %drives = _MappedAll();
  1476.     my ($drive,$share);
  1477.     while (($drive,$share) = each %drives) {
  1478.         return uc($drive).':' if (uc($share) eq $disk);
  1479.     }
  1480.     return;
  1481.  } else {
  1482.   $disk =~ s/^(\w)$/$1:/;$disk.="\0";
  1483.   my $size = 1024;
  1484.   my $share = "\0" x $size;
  1485.  
  1486.   $size = pack('L',$size);
  1487.   $Win32::FileOp::WNetGetConnection->Call($disk,$share,$size)
  1488.    and return;
  1489.   $share =~ s/\0.*$//;
  1490.   return $share;
  1491.  }
  1492. }
  1493.  
  1494. sub _MappedAll {
  1495.     my %hash;
  1496.     my $share;
  1497.     foreach (('A'..'Z')) {
  1498.         $share = Mapped $_
  1499.         and
  1500.         $hash{$_}=$share;
  1501.     }
  1502.     return %hash;
  1503. }
  1504.  
  1505. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1506.  
  1507. sub Subst {
  1508.  my $drive = shift;
  1509.  return unless $drive =~ s/^(\w):?$/$1:\0/;
  1510.  my $path = shift();
  1511.  return unless -e $path;
  1512.  $path.="\0";
  1513.  $Win32::FileOp::DefineDosDevice->Call(0,$drive,$path);
  1514. }
  1515.  
  1516. sub SubstDev {
  1517.  my $drive = shift;
  1518.  return unless $drive =~ s/^(\w):?$/$1:\0/;
  1519.  my $path = shift();
  1520. # return unless -e $path;
  1521.  $path = "\\Device\\$path" unless $path =~ /\\Device\\/i;
  1522.  $path.="\0";
  1523.  $Win32::FileOp::DefineDosDevice->Call(&DDD_RAW_TARGET_PATH,$drive,$path);
  1524. }
  1525.  
  1526. sub Unsubst {
  1527.  my $drive = shift;
  1528.  return unless $drive =~ s/^(\w):?$/$1:\0/;
  1529.  $Win32::FileOp::DefineDosDevice->Call(&DDD_REMOVE_DEFINITION,$drive,0);
  1530. }
  1531.  
  1532. sub Substed {
  1533.  my $drive = shift;
  1534.  if (defined $drive) {
  1535.   return unless $drive =~ s/^(\w):?$/$1:\0/;
  1536.   my $path = "\0" x 1024;
  1537.   my $device;
  1538.   $Win32::FileOp::QueryDosDevice->Call($drive,$path,1024)
  1539.    or return;
  1540.  
  1541.   $path =~ s/\0.*$//;
  1542.  
  1543.   $path =~ s/^\\\?\?\\UNC/\\/ and $device = 'UNC'
  1544.   or
  1545.   $path =~ s/\\Device\\(.*?)\\\w:/\\/ and $device = $1
  1546.   or
  1547.   $path =~ s/\\Device\\(.*)$// and $device = $1;
  1548.  
  1549.   return wantarray ? ($path,$device) : $path;
  1550.  } else {
  1551.   my ($drive,$path,%data);
  1552.   foreach $drive (('A'..'Z')) {
  1553.     $drive.=':';
  1554.     $path = Substed($drive);
  1555.     $data{$drive} = $path if defined $path;
  1556.   }
  1557.   return wantarray() ? %data : \%data;
  1558.  }
  1559. }
  1560.  
  1561.  
  1562. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1563.  
  1564. package Win32::FileOp::Error;
  1565. require Tie::Hash;
  1566. @Win32::FileOp::Error::ISA=qw(Tie::Hash);
  1567.  
  1568. sub TIEHASH {
  1569.     my $pkg = shift;
  1570.     my %hash = @_;
  1571.     my $self = \%hash;
  1572.     bless $self, $pkg;
  1573. }
  1574.  
  1575. sub FETCH { $_[0]->{$_[1]} || Win32::FormatMessage($_[1]) || "Unknown error ($_[1])" };
  1576.  
  1577. package Win32::FileOp;
  1578.  
  1579. tie %Win32::FileOp::ERRORS, 'Win32::FileOp::Error', (
  1580.  12291 => 'The buffer was too small!'
  1581. );
  1582.  
  1583. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1584.  
  1585. 1;
  1586.  
  1587. __END__
  1588.  
  1589. =head1 NAME
  1590.  
  1591. Win32::FileOp - 0.14.1
  1592.  
  1593. =head1 DESCRIPTION
  1594.  
  1595. Module for file operations with fancy dialog boxes, for moving files
  1596. to recycle bin, reading and updating INI files and file operations in general.
  1597.  
  1598. Unless mentioned otherwise all functions work under WinXP, Win2k, WinNT, WinME and Win9x.
  1599. Let me know if not.
  1600.  
  1601. Version 0.14.1
  1602.  
  1603. =head2 Functions
  1604.  
  1605. C<GetDesktopHandle> C<GetWindowHandle>
  1606.  
  1607. C<Copy> C<CopyConfirm> C<CopyConfirmEach> C<CopyEx>
  1608.  
  1609. C<Move> C<MoveConfirm> C<MoveConfirmEach> C<MoveEx>
  1610.  
  1611. C<MoveFile> C<MoveFileEx> C<CopyFile> C<MoveAtReboot>
  1612.  
  1613. C<Recycle> C<RecycleConfirm> C<RecycleConfirmEach> C<RecycleEx>
  1614.  
  1615. C<Delete> C<DeleteConfirm> C<DeleteConfirmEach> C<DeleteEx> C<DeleteAtReboot>
  1616.  
  1617. C<UpdateDir> C<FillInDir>
  1618.  
  1619. C<Compress> C<Uncompress> C<Compressed> C<SetCompression> C<GetCompression>
  1620. C<CompressDir> C<UncompressDir>
  1621.  
  1622. C<GetLargeFileSize> C<GetDiskFreeSpace>
  1623.  
  1624. C<AddToRecentDocs> C<EmptyRecentDocs>
  1625.  
  1626. C<WriteToINI> C<WriteToWININI> C<ReadINI> C<ReadWININI>
  1627.  
  1628. C<DeleteFromINI> C<DeleteFromWININI>
  1629.  
  1630. C<OpenDialog> C<SaveAsDialog> C<BrowseForFolder>
  1631.  
  1632. C<Map> C<Unmap> C<Disconnect> C<Mapped>
  1633.  
  1634. C<Subst> C<Unsubst> C<Substed>
  1635.  
  1636. C<ShellExecute>
  1637.  
  1638. To get the error message from most of these functions, you should not use $!, but
  1639. $^E or Win32::FormatMessage(Win32::GetLastError())!
  1640.  
  1641. =over 2
  1642.  
  1643. =item GetDesktopHandle
  1644.  
  1645.  use Win32::FileOp
  1646.  $handle = GetDesktopHandle()
  1647.  
  1648. Same as: $handle = $Win32::FileOp::DesktopHandle
  1649.  
  1650. Used to get desktop window handle when confirmation is used.
  1651. The value of the handle can be gotten from $Win32::FileOp::DesktopHandle.
  1652.  
  1653. Returns the Desktop Window handle.
  1654.  
  1655. =item GetWindowHandle
  1656.  
  1657.  use Win32::FileOp
  1658.  $handle = GetWindowHandle()
  1659.  
  1660. Same as: $handle = $Win32::FileOp::WindowHandle
  1661.  
  1662. Used to get the console window handle when confirmation is used.
  1663. The value of the handle can be gotten from $Win32::FileOp::WindowHandle.
  1664.  
  1665. Returns the Console Window handle.
  1666.  
  1667. =item Copy
  1668.  
  1669.  Copy ($FileName => $FileOrDirectoryName [, ...])
  1670.  Copy (\@FileNames => $DirectoryName [, ...] )
  1671.  Copy (\@FileNames => \@FileOrDirectoryNames [, ...])
  1672.  
  1673. Copies the specified files. Doesn't show any confirmation nor progress dialogs.
  1674.  
  1675. It may show an error message dialog, because I had to omit FOF_NOERRORUI
  1676. from its call to allow for autocreating directories.
  1677.  
  1678. You should end the directory names by backslash so that they are
  1679. not mistaken for filenames. It is not necessary if
  1680. the directory already exists or if you use Copy \@filenames => $dirname.
  1681.  
  1682. Returns true if successful.
  1683.  
  1684. Rem: Together with Delete, Move, DeleteConfirm, CopyConfirm,
  1685. MoveConfirm, CopyEx, MoveEx, DeleteEx and Recycle based on Win32 API function
  1686. SHFileOperation().
  1687.  
  1688. =item CopyConfirm
  1689.  
  1690.  CopyConfirm ($FileName => $FileOrDirectoryName [, ...])
  1691.  CopyConfirm (\@FileNames => $DirectoryName [, ...] )
  1692.  CopyConfirm (\@FileNames => \@FileOrDirectoryNames [, ...])
  1693.  
  1694. Copies the specified files. In case of a collision, shows a confirmation dialog.
  1695. Shows progress dialogs.
  1696.  
  1697. Returns true if successful.
  1698.  
  1699. =item CopyConfirmEach
  1700.  
  1701. The same as CopyConfirm.
  1702.  
  1703. =item CopyEx
  1704.  
  1705.  CopyEx ($FileName => $FileOrDirectoryName, [...], $options)
  1706.  CopyEx (\@FileNames => $DirectoryName, [...], $options)
  1707.  CopyEx (\@FileNames => \@FileOrDirectoryNames, [...], $options)
  1708.  
  1709. Copies the specified files. See below for the available options (C<FOF_> constants).
  1710.  
  1711. Returns true if successful.
  1712.  
  1713. =item Move
  1714.  
  1715. Moves the specified files. Parameters as C<Copy>
  1716.  
  1717. It may show an error message dialog, because I had to omit FOF_NOERRORUI
  1718. from its call to allow for autocreating directories.
  1719.  
  1720. =item MoveConfirm
  1721.  
  1722. Moves the specified files. Parameters as C<CopyConfirm>
  1723.  
  1724. =item MoveConfirmEach
  1725.  
  1726. The same as MoveConfirm
  1727.  
  1728. =item MoveEx
  1729.  
  1730. Moves the specified files. Parameters as C<CopyEx>
  1731.  
  1732. =item MoveAtReboot
  1733.  
  1734.  MoveAtReboot ($FileName => $DestFileName, [...])
  1735.  
  1736. This function moves the file during the next start of the system.
  1737.  
  1738. =item MoveFile
  1739.  
  1740.  MoveFile ($FileName => $DestFileName [, ...])
  1741.  
  1742. Move files. This function uses API function MoveFileEx as well
  1743. as MoveAtReboot. It may be a little quicker than C<Move>, but
  1744. it doesn't understand wildcards and the $DestFileName may not be a directory.
  1745.  
  1746. REM: Based on Win32 API function MoveFileEx().
  1747.  
  1748. =item MoveFileEx
  1749.  
  1750.  MoveFileEx ($FileName => $DestFileName [, ...], $options)
  1751.  
  1752. This is a simple wrapper around the API function MoveFileEx, it calls the function
  1753. for every pair of files with the $options you specify.
  1754. See below for the available options (C<FOF_>... constants).
  1755.  
  1756. REM: Based on Win32 API function MoveFileEx().
  1757.  
  1758. =item CopyFile
  1759.  
  1760.  CopyFile ($FileName => $DestFileName [, $FileName2 => $DestFileName2 [, ...]])
  1761.  
  1762. Copy a file somewhere. This function is not able to copy directories!
  1763.  
  1764. REM: Based on Win32 API function CopyFile().
  1765.  
  1766. =item Recycle
  1767.  
  1768.  Recycle @filenames
  1769.  
  1770. Send the files into the recycle bin. You will not get any confirmation dialogs.
  1771.  
  1772. Returns true if successful.
  1773.  
  1774. =item RecycleConfirm
  1775.  
  1776.  RecycleConfirm @filenames
  1777.  
  1778. Send the files into the recycle bin. You will get a confirmation dialog if you
  1779. have "Display delete confirmation dialog" turned on in your recycle bin. You
  1780. will confirm the deletion of all the files at once.
  1781.  
  1782. Returns true if successful. Please remember that this function is successful
  1783. even if the user chose [No] on the confirmation dialog!
  1784.  
  1785. =item RecycleConfirmEach
  1786.  
  1787.  RecycleConfirmEach @filenames
  1788.  
  1789. Send the files into the recycle bin. You will get a separate confirmation
  1790. dialog for each file if you have "Display delete confirmation dialog" turned
  1791. on in your recycle bin. You will confirm the deletion of all the files at once.
  1792.  
  1793. Returns the number of files that were successfully deleted.
  1794.  
  1795. =item RecycleEx
  1796.  
  1797.  RecycleEx @filenames, $options
  1798.  
  1799. Send the files into the recycle bin. You may specify the options for deleting,
  1800. see below.  You may get a confirmation dialog if you have "Display delete
  1801. confirmation dialog" turned on in your recycle bin, if so, you will confirm the
  1802. deletion of all the files at once.
  1803.  
  1804. Returns true if successful. Please remember that this function is successful
  1805. even if the user chose [No] on the confirmation dialog!
  1806.  
  1807. The $options may be constructed from C<FOF_>... constants.
  1808.  
  1809. =item Delete
  1810.  
  1811.  Delete @filenames
  1812.  
  1813. Deletes the files. You will not get any confirmation dialogs.
  1814.  
  1815. Returns true if successful.
  1816.  
  1817. =item DeleteConfirm
  1818.  
  1819.  DeleteConfirm @filenames
  1820.  
  1821. Deletes the the files. You will get a confirmation dialog to confirm
  1822. the deletion of all the files at once.
  1823.  
  1824. Returns true if successful. Please remember that this function is successful
  1825. even if the user selected [No] on the confirmation dialog!
  1826.  
  1827. =item DeleteConfirmEach
  1828.  
  1829.  DeleteConfirmEach @filenames
  1830.  
  1831. Deletes the files. You will get a separate confirmation dialog for each file.
  1832.  
  1833. Returns the number of files that were successfully deleted.
  1834.  
  1835. =item DeleteEx
  1836.  
  1837.  DeleteEx @filenames, $options
  1838.  
  1839. Deletes the files. You may specify the options for deleting,
  1840. see below.  You may get a confirmation dialog if you have "Display delete
  1841. confirmation dialog" turned on in your recycle bin.
  1842.  
  1843. Returns true if successful. Please remember that this function is successful
  1844. even if the user selected [No] on the confirmation dialog!
  1845.  
  1846. =item DeleteAtReboot
  1847.  
  1848.  DeleteAtReboot @files
  1849.  
  1850. This function moves the file during the next start of the system.
  1851.  
  1852. =item UpdateDir
  1853.  
  1854.  UpdateDir $SourceDirectory, $DestDirectory [, \&callback]
  1855.  
  1856. Copy the newer or updated files from $SourceDir to $DestDir. Processes subdirectories!
  1857. The &callback function is called for each file to be copied.
  1858. The parameters it gets are exactly the same as the callback function
  1859. in File::Find. That is $_, $File::Find::dir and $File::Find::name.
  1860.  
  1861. If this function returns a false value, the file is skipped.
  1862.  
  1863.  Ex.
  1864.  
  1865.   UpdateDir 'c:\dir' => 'e:\dir', sub {print '.'};
  1866.   UpdateDir 'c:\dir' => 'e:\dir', sub {if (/^s/i) {print '.'}};
  1867.  
  1868. =item FillInDir
  1869.  
  1870.  FillInDir $SourceDirectory, $DestDirectory [, \&callback]
  1871.  
  1872. Copy the files from $SourceDir not present in $DestDir. Processes subdirectories!
  1873. The &callback works the same as in UpdateDir.
  1874.  
  1875. =item Compress
  1876.  
  1877.  Compress $filename [, ...]
  1878.  
  1879. Compresses the file(s) or directories using the transparent WinNT compression
  1880. (The same as checking the "Compressed" checkbox in Explorer properties
  1881. fo the file).
  1882.  
  1883. It doesn't compress all files and subdirectories in a directory you
  1884. specify. Use ComressDir for that. Compress($directory) only sets the compression flag for
  1885. the directory so that the new files are compressed by default.
  1886.  
  1887. WinNT only!
  1888.  
  1889. REM: Together with other compression related functions based
  1890. on DeviceIoControl() Win32 API function.
  1891.  
  1892. =item Uncompress
  1893.  
  1894.  Uncompress $filename [, ...]
  1895.  
  1896. Uncompresses the file(s) using the transparent WinNT compression
  1897. (The same as unchecking the "Compressed" checkbox in Explorer properties
  1898. fo the file).
  1899.  
  1900. WinNT only!
  1901.  
  1902. =item Compressed
  1903.  
  1904.  Compressed $filename
  1905.  
  1906. Checks the compression status for a file.
  1907.  
  1908. =item SetCompression
  1909.  
  1910.  SetCompression $filename [, $filename], $value
  1911.  
  1912. Sets the compression status for file(s). The $value should be
  1913. either 1 or 0.
  1914.  
  1915. =item GetCompression
  1916.  
  1917.  GetCompression $filename
  1918.  
  1919. Checks the compression status for a file.
  1920.  
  1921. =item CompressDir
  1922.  
  1923.  CompressDir $directory, ... [, \&callback]
  1924.  
  1925. Recursively descends the directory(ies) specified and compresses all files
  1926. and directories within. If you specify the \&callback, the specified function
  1927. gets executed for each of the files and directories. If the callback returns false,
  1928. no compression is done on the file/directory.
  1929.  
  1930. The parameters the callback gets are exactly the same as the callback function
  1931. in File::Find. That is $_, $File::Find::dir and $File::Find::name.
  1932.  
  1933. =item UncompressDir
  1934.  
  1935.  UncompressDir $directory, ... [, \&callback]
  1936.  
  1937. The counterpart of CompressDir.
  1938.  
  1939. =item GetLargeFileSize
  1940.  
  1941.     ($lo_word, $hi_word) = GetLargeFileSize( $path );
  1942.     # or
  1943.     $file_size = GetLargeFileSize( $path );
  1944.  
  1945. This gives you the file size for too big files (over 4GB).
  1946. If called in list context returns the two 32 bit words, in scalar context
  1947. returns the file size as one number ... if the size is too big to fit in
  1948. an Integer it'll be returned as a Float. This means that if it's above
  1949. cca. 10E15 it may get slightly rounded.
  1950.  
  1951. =item GetDiskFreeSpace
  1952.  
  1953.     $freeSpaceForUser = GetDiskFreeSpace $path;
  1954.     # or
  1955.     ($freeSpaceForUser, $totalSize, $totalFreeSpace) = GetDiskFreeSpace $path;
  1956.  
  1957. In scalar context returns the amount of free space available to current user
  1958. (respecting quotas), in list context returns the free space for current user, the total size
  1959. of disk and the total amount of free space on the disk.
  1960.  
  1961. Works OK with huge disks.
  1962.  
  1963. Requires at least Windows 95 OSR2 or WinNT 4.0.
  1964.  
  1965. =item AddToRecentDocs
  1966.  
  1967.  AddToRecentDocs $filename [, ...]
  1968.  
  1969. Add a shortcut(s) to the file(s) into the Recent Documents folder.
  1970. The shortcuts will appear in the Documents submenu of Start Menu.
  1971.  
  1972. The paths may be relative.
  1973.  
  1974. REM: Based on Win32 API function SHAddToRecentDocs().
  1975.  
  1976. =item EmptyRecentDocs
  1977.  
  1978.  EmptyRecentDocs;
  1979.  
  1980. Deletes all shortcuts from the Recent Documents folder.
  1981.  
  1982. REM: Based on Win32 API function SHAddToRecentDocs(). Strange huh?
  1983.  
  1984. =item WriteToINI
  1985.  
  1986.  WriteToINI $INIfile, $section, $name1 => $value [, $name2 => $value2 [, ...]]
  1987.  
  1988. Copies a string into the specified section of the specified initialization file.
  1989. You may pass several name/value pairs at once.
  1990.  
  1991. Returns 1 if successful, undef otherwise. See Win32::GetLastError &
  1992. Win32::FormatMessage(Win32::GetLastError) if failed for the error code and message.
  1993.  
  1994. REM: Based on Win32 API function WritePrivateProfileString().
  1995.  
  1996. =item WriteToWININI
  1997.  
  1998.  WriteToWININI $section, $name1 => $value1 [, $name2 => $value2 [, ...]]
  1999.  
  2000. Copies a string into the specified section of WIN.INI.
  2001. You may pass several name/value pairs at once.
  2002.  
  2003. Please note that some values or sections of WIN.INI and some other INI
  2004. files are mapped to registry so they do not show up
  2005. in the INI file even if they were successfully written!
  2006.  
  2007. REM: Based on Win32 API function WriteProfileString().
  2008.  
  2009. =item ReadINI
  2010.  
  2011.     $value = ReadINI $INIfile, $section, $name [, $defaultvalue]
  2012.  
  2013. Reads a value from an INI file. If you do not specify the default
  2014. and the value is not found you'll get undef.
  2015.  
  2016. REM: Based on Win32 API function GetPrivateProfileString().
  2017.  
  2018. =item ReadWININI
  2019.  
  2020.     $value = ReadWININI $section, $name [, $defaultvalue]
  2021.  
  2022. Reads a value from WIN.INI file. If you do not specify the default
  2023. and the value is not found you'll get undef.
  2024.  
  2025. Please note that some values or sections of WIN.INI and some other INI
  2026. files are mapped to registry so even that they do not show up
  2027. in the INI file this function will find and read them!
  2028.  
  2029. REM: Based on Win32 API function GetProfileString().
  2030.  
  2031. =item DeleteFromINI
  2032.  
  2033.  DeleteFromINI $INIfile, $section, @names_to_delete
  2034.  
  2035. Delete a value from an INI file.
  2036.  
  2037. REM: Based on Win32 API function WritePrivateProfileString().
  2038.  
  2039. =item DeleteFromWININI
  2040.  
  2041.  DeleteFromWININI $section, @names_to_delete
  2042.  
  2043. Delete a value from WIN.INI.
  2044.  
  2045. REM: Based on Win32 API function WriteProfileString().
  2046.  
  2047. =item ReadINISections
  2048.  
  2049.  @sections = ReadINISections($inifile);
  2050.  \@sections = ReadINISections($inifile);
  2051.  ReadINISections($inifile,\@sections);
  2052.  
  2053. Enumerate the sections in a INI file. If you do not specify the INI file,
  2054. it enumerates the contents of win.ini.
  2055.  
  2056. REM: Based on Win32 API function GetPrivateProfileString().
  2057.  
  2058. =item ReadINISectionKeys
  2059.  
  2060.  @sections = ReadINISectionKeys($inifile, $section);
  2061.  \@sections = ReadINISectionKeys($inifile, $section);
  2062.  ReadINISectionKeys($inifile, $section, \@sections);
  2063.  
  2064. Enumerate the keys in a section of a INI file. If you do not specify the
  2065. INI file, it enumerates the contents of win.ini.
  2066.  
  2067. REM: Based on Win32 API function GetPrivateProfileString().
  2068.  
  2069. =item OpenDialog
  2070.  
  2071.  $filename = OpenDialog \%parameters [, $defaultfilename]
  2072.  @filenames = OpenDialog \%parameters [, $defaultfilename]
  2073.  
  2074.  $filename = OpenDialog %parameters [, $defaultfilename]
  2075.  @filenames = OpenDialog %parameters [, $defaultfilename]
  2076.  
  2077. Creates the standard Open dialog allowing you to select some files.
  2078.  
  2079. Returns a list of selected files or undef if the user pressed [Escape].
  2080. It also sets two global variables :
  2081.  
  2082.  $Win32::FileOp::ReadOnly = the user requested a readonly access.
  2083.  $Win32::FileOp::SelectedFilter = the id of filter selected in the dialogbox
  2084.  
  2085.  %parameters
  2086.   title => the title for the dialog, default is 'Open'
  2087.         'Open file'
  2088.   filters => definition of file filters
  2089.         { 'Filter 1' => '*.txt;*.doc', 'Filter 2' => '*.pl;*.pm'}
  2090.         [ 'Filter 1' => '*.txt;*.doc', 'Filter 2' => '*.pl;*.pm']
  2091.         [ 'Filter 1' => '*.txt;*.doc', 'Filter 2' => '*.pl;*.pm' , $default]
  2092.         "Filter 1\0*.txt;*.doc\0Filter 2\0*.pl;*.pm"
  2093.   defaultfilter => the number of the default filter counting from 1.
  2094.                    Please keep in mind that hashes do not preserve
  2095.                    ordering!
  2096.   dir => the initial directory for the dialog, default is the current directory
  2097.   filename => the default filename to be showed in the dialog
  2098.   handle => the handle to the window which will own this dialog
  2099.             Default is the console of the perl script.
  2100.             If you do not want to tie the dialog to any window use
  2101.             handle => 0
  2102.   options => options for the dialog, see bellow OFN_... constants
  2103.  
  2104. There is a little problem with the underlying function. You have to
  2105. preallocate a buffer for the selected filenames and if the buffer is too
  2106. smallyou will not get any results. I've consulted this with the guys on
  2107. Perl-Win32-Users and there is not any nice solution. The default size of
  2108. buffer is 256B if the options do not include OFN_ALLOWMULTISELECT and
  2109. 64KB if they do. You may change the later via variable
  2110. $Win32::FileOp::BufferSize.
  2111.  
  2112. NOTE: I have been notified about a strange behaviour under Win98.
  2113. If you use UNCs you should always use backslashes in the paths.
  2114. \\server/share doesn't work at all under Win98 and //server/share works
  2115. only BEFORE calling the Win32::FileOp::OpenDialog(). I have no idea what
  2116. is the cause of this behaviour.
  2117.  
  2118. REM: Based on Win32 API function GetOpenFileName().
  2119.  
  2120. =item SaveAsDialog
  2121.  
  2122. Creates the Save As dialog box, parameters are the same as for OpenDialog.
  2123.  
  2124. REM: Based on Win32 API function GetSaveFileName().
  2125.  
  2126. =item BrowseForFolder
  2127.  
  2128.  BrowseForFolder [$title [, $rootFolder [, $options]]]
  2129.  
  2130. Creates the standard "Browse For Folder" dialog.
  2131. The $title specifies the text to be displayed below the title of the dialog.
  2132. The $rootFolder may be one of the C<CSIDL_>... constants.
  2133. For $options you should use the C<BIF_>... constants. Description
  2134. of the constants is bellow.
  2135.  
  2136. REM: Based on Win32 API function SHBrowseForFolder().
  2137.  
  2138. =item Map
  2139.  
  2140.  Map $drive => $share;
  2141.  $drive = Map $share;
  2142.  Map $drive => $share, \%options;
  2143.  $drive = Map $share, \%options;
  2144.  
  2145. Map a drive letter or LTPx to a network resource. If successfull returns the drive letter/LPTx.
  2146.  
  2147. If you do not specify the drive letter, the function uses the last free
  2148. letter, if you specify undef or empty string as the drive then the share is connected,
  2149. but not assigned a letter.
  2150.  
  2151. Since the function doesn't require the ':' in the drive name you
  2152. may use the function like this:
  2153.  
  2154.  Map H => '\\\\server\share';
  2155.  as well as
  2156.  Map 'H:' => '\\\\server\share';
  2157.  
  2158.  Options:
  2159.   persistent => 0/1
  2160.       should the connection be restored on next logon?
  2161.  
  2162.   user => $username
  2163.       username to be used to connect the device
  2164.   passwd => $password
  2165.       password to be used to connect the device
  2166.   overwrite => 0/1
  2167.       should the drive be remapped if it was already connected?
  2168.   force_overwrite => 0/1
  2169.       should the drive be forcefully disconnected and
  2170.       remapped if it was already connected?
  2171.   interactive = 0 / 'yes' / $WindowHandle
  2172.       if necessary displays a dialog box asking the user
  2173.       for the username and password.
  2174.   prompt = 0/1
  2175.       if used with interactive=> the user is ALWAYS asked for the username
  2176.       and password, even if you supplied them in the call. If you did not specify
  2177.       interactive=> then prompt=> is ignored.
  2178.   redirect = 0/1
  2179.       forces the redirection of a local device when making the connection
  2180.  
  2181.  Example:
  2182.   Map I => '\\\\servername\share', {persistent=>1,overwrite=>1};
  2183.  
  2184. Notes: 1) If you use the C<interactive> option the user may Cancel that dialog. In that case
  2185. the Map() fails, returns undef and Win32::GetLastError() returns 1223
  2186. and $^E is equals to 1223 in numerical context and to "The operation was canceled by the user."
  2187. in string context.
  2188.  
  2189. 2) You should only check the Win32::GetLastError() or $^E if the function failed.
  2190. If you do check it even if it succeeded you may get error 997 "Overlapped I/O operation is in progress.".
  2191. This means that it worked all right and you should not care about this bug!
  2192.  
  2193. REM: Based on Win32 API function WNetAddConnection3().
  2194.  
  2195. =item Connect
  2196.  
  2197.     Connect $share
  2198.     Connect $share, \%options
  2199.  
  2200. Connects a share without assigning a drive letter to it.
  2201.  
  2202. REM: Based on Win32 API function WNetAddConnection3().
  2203.  
  2204. =item Disconnect
  2205.  
  2206.  Disconnect $drive_or_share;
  2207.  Disconnect $drive_or_share, \%options;
  2208.  
  2209. Breaks an existing network connection. It can also be used to remove
  2210. remembered network connections that are not currently connected.
  2211.  
  2212. $drive_or_share specifies the name of either the redirected local device
  2213. or the remote network resource to disconnect from. If this parameter
  2214. specifies a redirected local resource, only the specified redirection is
  2215. broken; otherwise, all connections to the remote network resource are
  2216. broken.
  2217.  
  2218.  Options:
  2219.   persistent = 0/1, if you do not use persistent=>1, the connection will be closed, but
  2220.                the drive letter will still be mapped to the device
  2221.   force      = 0/1, disconnect even if there are some open files
  2222.  
  2223.  See also: Unmap
  2224.  
  2225. REM: Based on Win32 API function WNetCancelConnection2().
  2226.  
  2227. =item Unmap
  2228.  
  2229.  Unmap $drive_or_share;
  2230.  Unmap $drive_or_share, \%options;
  2231.  
  2232. The only difference from Disconnect is that persistent=>1 is the default.
  2233.  
  2234. REM: Based on Win32 API function WNetCancelConnection2().
  2235.  
  2236. =item Mapped
  2237.  
  2238.  %drives = Mapped;
  2239.  $share = Mapped $drive;
  2240.  $drive = Mapped $share; # currently not implemented !!!
  2241.  
  2242. This function retrieves the name of the network resource associated with a local device.
  2243. Or vice versa.
  2244.  
  2245. If you do not specify any parameter, you get a hash of drives and shares.
  2246.  
  2247. To get the error message from most of these functions, you should not use $!, but
  2248. Win32::FormatMessage(Win32::GetLastError()) or $^E !
  2249.  
  2250. REM: Based on Win32 API function WNetGetConnection().
  2251.  
  2252.  
  2253. =item Subst
  2254.  
  2255.  Subst Z => 'c:\temp';
  2256.  Subst 'Z:' => '\\\\servername\share\subdir';
  2257.  
  2258. This function substitutes a drive letter for a directory, both local and UNC.
  2259.  
  2260. Be very carefull with this, cause it'll allow you to change the
  2261. substitution even for C:. ! Which will most likely be lethal !
  2262.  
  2263. Works only on WinNT.
  2264.  
  2265. REM: Based on DefineDosDevice()
  2266.  
  2267.  =item SubstDev
  2268.  
  2269.  SubstDev F => 'Floppy0';
  2270.  SubstDev G => 'Harddisk0\Partition1';
  2271.  
  2272. Allows you to make a substitution to devices. For example if you want to
  2273. make an alias for A: ...
  2274.  
  2275. To get the device mapped to a drive letter use Substed() in list context.
  2276.  
  2277. Works only on WinNT.
  2278.  
  2279. REM: Based on DefineDosDevice()
  2280.  
  2281. =item Unsubst
  2282.  
  2283.  Unsubst 'X';
  2284.  
  2285. Deletes the substitution for a drive letter. Again, be very carefull with this!
  2286.  
  2287. Works only on WinNT.
  2288.  
  2289. REM: Based on DefineDosDevice()
  2290.  
  2291. =item Substed
  2292.  
  2293.  %drives = Substed;
  2294.  $substitution = Substed $drive;
  2295.  ($substitution, $device) = Substed $drive;
  2296.  
  2297. This function retrieves the name of the resource(s) associated with a drive letter(s).
  2298.  
  2299. If used with a parameter :
  2300.  
  2301. In scalar context you get the substitution. If the drive is the root of
  2302. a local device you'll get an empty string, if it's not mapped to
  2303. anything you'll get undef.
  2304.  
  2305. In list context you'll get both the substitution and the device/type of device :
  2306.  
  2307.  Substed 'A:' => ('','Floppy0')
  2308.  Substed 'B:' => undef
  2309.  Substed 'C:' => ('','Harddisk0\Partition1')
  2310.  Substed 'H:' => ('\\\\servername\homes\username','UNC')
  2311.   # set by subst H: \\servername\homes\username
  2312.  Substed 'S:' => ('\\\\servername\servis','LanmanRedirector')
  2313.   # set by net use S: \\servername\servis
  2314.  Substed 'X:' => ()
  2315.   # not mapped to anything
  2316.  
  2317. If used without a parameter gives you a hash of drives and their
  2318. corresponding sunstitutions.
  2319.  
  2320. Works only on WinNT.
  2321.  
  2322. REM: Based on Win32 API function QueryDosDevice().
  2323.  
  2324. =item ShellExecute
  2325.  
  2326.     ShellExecute $filename;
  2327.     ShellExecute $operation => $filename;
  2328.     ShellExecute $operation => $filename, $params, $dir, $showOptions, $handle;
  2329.     ShellExecute $filename,
  2330.         {params => $params, dir => $dir, show => $showOptions, handle => $handle};
  2331.     ShellExecute $operation => $filename,
  2332.         {params => $params, dir => $dir, show => $showOptions, handle => $handle};
  2333.  
  2334. This function instructs the system to execute whatever application is assigned to the file
  2335. type as the specified action in the registry.
  2336.  
  2337.     ShellExecute 'open' => $filename;
  2338.  or
  2339.     ShellExecute $filename;
  2340.  
  2341. is equivalent to doubleclicking the file in the Explorer,
  2342.  
  2343.     ShellExecute 'edit' => $filename;
  2344.  
  2345. is equivalent to rightclicking it and selecting the Edit action.
  2346.  
  2347. Parameters:
  2348.  
  2349. $operation : specifies the action to perform. The set of available operations depends on the file type.
  2350. Generally, the actions available from an object's shortcut menu are available verbs.
  2351.  
  2352. $filename : The file to execute the action for.
  2353.  
  2354. $params : If the $filename parameter specifies an executable file, $params is a string that specifies
  2355. the parameters to be passed to the application. The format of this string is determined by
  2356. the $operation that is to be invoked. If $filename specifies a document file, $params should be undef.
  2357.  
  2358. $dir : the default directory for the invoked program.
  2359.  
  2360. $showOptions : one of the SW_... constants that specifies how the application is to be displayed
  2361. when it is opened.
  2362.  
  2363. $handle : The handle of the window that gets any message boxes that may be invoked by this.
  2364. Be default the handle of the console that this script runs in.
  2365.  
  2366. REM: Based on Win32 API function ShellExecute
  2367.  
  2368. =back
  2369.  
  2370. =head2 Options
  2371.  
  2372. =over 2
  2373.  
  2374. =item FOF_
  2375.  
  2376.  FOF_SILENT = do not show the progress dialog
  2377.  FOF_RENAMEONCOLLISION = rename the file in case of collision
  2378.             ('file.txt' -> 'Copy of file.txt')
  2379.  FOF_NOCONFIRMATION = do not show the confirmation dialog
  2380.  FOF_ALLOWUNDO = send file(s) to RecycleBin instead of deleting
  2381.  FOF_FILESONLY = skip directories
  2382.  FOF_SIMPLEPROGRESS = do not show the filenames in the process dialog
  2383.  FOF_NOCONFIRMMKDIR = do not confirm creating directories
  2384.  FOF_NOERRORUI = do not report errors
  2385.  FOF_NOCOPYSECURITYATTRIBS = do not copy security attributes
  2386.  
  2387. =item OFN_
  2388.  
  2389.  OFN_ALLOWMULTISELECT
  2390.  
  2391. Specifies that the File Name list box allows multiple selections. If you
  2392. also set the OFN_EXPLORER flag, the dialog box uses the Explorer-style
  2393. user interface; otherwise, it uses the old-style user interface.
  2394.  
  2395.  OFN_CREATEPROMPT
  2396.  
  2397. If the user specifies a file that does not exist, this flag causes the
  2398. dialog box to prompt the user for permission to create the file. If the
  2399. user chooses to create the file, the dialog box closes and the function
  2400. returns the specified name; otherwise, the dialog box remains open.
  2401.  
  2402.  OFN_EXPLORER
  2403.  
  2404. Since I cannot implement hook procedures through Win32::API (AFAIK),
  2405. this option in not necessary.
  2406.  
  2407.  OFN_FILEMUSTEXIST
  2408.  
  2409. Specifies that the user can type only names of existing files in the
  2410. File Name entry field. If this flag is specified and the user enters an
  2411. invalid name, the dialog box procedure displays a warning in a message
  2412. box. If this flag is specified, the OFN_PATHMUSTEXIST flag is also used.
  2413.  
  2414.  OFN_HIDEREADONLY
  2415.  
  2416. Hides the Read Only check box.
  2417.  
  2418.  OFN_LONGNAMES
  2419.  
  2420. For old-style dialog boxes, this flag causes the dialog box to use long
  2421. filenames. If this flag is not specified, or if the OFN_ALLOWMULTISELECT
  2422. flag is also set, old-style dialog boxes use short filenames (8.3
  2423. format) for filenames with spaces. Explorer-style dialog boxes ignore
  2424. this flag and always display long filenames.
  2425.  
  2426.  OFN_NOCHANGEDIR
  2427.  
  2428. Restores the current directory to its original value if the user changed
  2429. the directory while searching for files.
  2430.  
  2431.  OFN_NODEREFERENCELINKS
  2432.  
  2433. Directs the dialog box to return the path and filename of the selected
  2434. shortcut (.LNK) file. If this value is not given, the dialog box returns
  2435. the path and filename of the file referenced by the shortcut
  2436.  
  2437.  OFN_NOLONGNAMES
  2438.  
  2439. For old-style dialog boxes, this flag causes the dialog box to use short
  2440. filenames (8.3 format). Explorer-style dialog boxes ignore this flag and
  2441. always display long filenames.
  2442.  
  2443.  OFN_NONETWORKBUTTON
  2444.  
  2445. Hides and disables the Network button.
  2446.  
  2447.  OFN_NOREADONLYRETURN
  2448.  
  2449. Specifies that the returned file does not have the Read Only check box
  2450. checked and is not in a write-protected directory.
  2451.  
  2452.  OFN_NOTESTFILECREATE
  2453.  
  2454. Specifies that the file is not created before the dialog box is closed.
  2455. This flag should be specified if the application saves the file on a
  2456. create-nonmodify network sharepoint. When an application specifies this
  2457. flag, the library does not check for write protection, a full disk, an
  2458. open drive door, or network protection. Applications using this flag
  2459. must perform file operations carefully, because a file cannot be
  2460. reopened once it is closed.
  2461.  
  2462.  OFN_NOVALIDATE
  2463.  
  2464. Specifies that the dialog boxes allow invalid characters in the returned
  2465. filename.
  2466.  
  2467.  OFN_OVERWRITEPROMPT
  2468.  
  2469. Causes the Save As dialog box to generate a message box if the selected
  2470. file already exists. The user must confirm whether to overwrite the
  2471. file.
  2472.  
  2473.  OFN_PATHMUSTEXIST
  2474.  
  2475. Specifies that the user can type only valid paths and filenames. If this
  2476. flag is used and the user types an invalid path and filename in the File
  2477. Name entry field, the dialog box function displays a warning in a
  2478. message box.
  2479.  
  2480.  OFN_READONLY
  2481.  
  2482. Causes the Read Only check box to be checked initially when the dialog
  2483. box is created. If the check box is checked when the dialog box is closed
  2484. $Win32::FileOp::ReadOnly is set to true.
  2485.  
  2486.  OFN_SHAREAWARE
  2487.  
  2488. Specifies that if a call to the OpenFile function fails because of a
  2489. network sharing violation, the error is ignored and the dialog box
  2490. returns the selected filename.
  2491.  
  2492.  OFN_SHOWHELP
  2493.  
  2494. Causes the dialog box to display the Help button. The hwndOwner member
  2495. must specify the window to receive the HELPMSGSTRING registered messages
  2496. that the dialog box sends when the user clicks the Help button.
  2497.  
  2498. =item BIF_
  2499.  
  2500.  BIF_DONTGOBELOWDOMAIN
  2501.  
  2502. Does not include network folders below the domain level in the tree view
  2503. control.
  2504.  
  2505.  BIF_RETURNONLYFSDIRS
  2506.  
  2507. Only returns file system directories. If the user selects folders that
  2508. are not part of the file system, the OK button is grayed.
  2509.  
  2510.  BIF_RETURNFSANCESTORS
  2511.  
  2512. Only returns file system ancestors. If the user selects anything other
  2513. than a file system ancestor, the OK button is grayed.
  2514.  
  2515. This option is strange, cause it seems to allow you to select only computers.
  2516. I don't know the definition of a filesystem ancestor, but I didn't think
  2517. it would be a computer. ?-|
  2518.  
  2519.  BIF_BROWSEFORCOMPUTER
  2520.  
  2521. Only returns computers. If the user selects anything other than a
  2522. computer, the OK button is grayed.
  2523.  
  2524.  BIF_BROWSEFORPRINTER
  2525.  
  2526. Only returns printers. If the user selects anything other than a
  2527. printer, the OK button is grayed.
  2528.  
  2529.  BIF_STATUSTEXT
  2530.  
  2531. Since it is currently impossible to define callbacks, this options is
  2532. useless.
  2533.  
  2534.  
  2535. =item CSIDL_
  2536.  
  2537. This is a list of available options for BrowseForFolder().
  2538.  
  2539. CSIDL_BITBUCKET
  2540.  
  2541. Recycle bin --- file system directory containing file objects in the
  2542. user's recycle bin. The location of this directory is not in the
  2543. registry; it is marked with the hidden and system attributes to prevent
  2544. the user from moving or deleting it.
  2545.  
  2546. CSIDL_CONTROLS
  2547.  
  2548. Control Panel --- virtual folder containing icons for the control panel
  2549. applications.
  2550.  
  2551. CSIDL_DESKTOP
  2552.  
  2553. Windows desktop --- virtual folder at the root of the name space.
  2554.  
  2555. CSIDL_DESKTOPDIRECTORY
  2556.  
  2557. File system directory used to physically store file objects on the
  2558. desktop (not to be confused with the desktop folder itself).
  2559.  
  2560. CSIDL_DRIVES
  2561.  
  2562. My Computer --- virtual folder containing everything on the local
  2563. computer: storage devices, printers, and Control Panel. The folder may
  2564. also contain mapped network drives.
  2565.  
  2566. CSIDL_FONTS
  2567.  
  2568. Virtual folder containing fonts.
  2569.  
  2570. CSIDL_NETHOOD
  2571.  
  2572. File system directory containing objects that appear in the network
  2573. neighborhood.
  2574.  
  2575. CSIDL_NETWORK
  2576.  
  2577. Network Neighborhood --- virtual folder representing the top level of the
  2578. network hierarchy.
  2579.  
  2580. CSIDL_PERSONAL
  2581.  
  2582. File system directory that serves as a common repository for documents.
  2583.  
  2584. CSIDL_PRINTERS
  2585.  
  2586. Printers folder --- virtual folder containing installed printers.
  2587.  
  2588. CSIDL_PROGRAMS
  2589.  
  2590. File system directory that contains the user's program groups (which are
  2591. also file system directories).
  2592.  
  2593. CSIDL_RECENT
  2594.  
  2595. File system directory that contains the user's most recently used
  2596. documents.
  2597.  
  2598. CSIDL_SENDTO
  2599.  
  2600. File system directory that contains Send To menu items.
  2601.  
  2602. CSIDL_STARTMENU
  2603.  
  2604. File system directory containing Start menu items.
  2605.  
  2606. CSIDL_STARTUP
  2607.  
  2608. File system directory that corresponds to the user's Startup program
  2609. group.
  2610.  
  2611. CSIDL_TEMPLATES
  2612.  
  2613. File system directory that serves as a common repository for document
  2614. templates.
  2615.  
  2616. Not all options make sense in all functions!
  2617.  
  2618. =item SW_
  2619.  
  2620. SW_HIDE
  2621.  
  2622. Hides the window and activates another window.
  2623.  
  2624. SW_MAXIMIZE
  2625.  
  2626. Maximizes the specified window.
  2627.  
  2628. SW_MINIMIZE
  2629.  
  2630. Minimizes the specified window and activates the next top-level window in the z-order.
  2631.  
  2632. SW_RESTORE
  2633.  
  2634. Activates and displays the window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when restoring a minimized window.
  2635.  
  2636. SW_SHOW
  2637.  
  2638. Activates the window and displays it in its current size and position.
  2639.  
  2640. SW_SHOWDEFAULT
  2641.  
  2642. Sets the show state based on the SW_ flag specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application. An application should call ShowWindow with this flag to set the initial show state of its main window.
  2643.  
  2644. SW_SHOWMAXIMIZED
  2645.  
  2646. Activates the window and displays it as a maximized window.
  2647.  
  2648. SW_SHOWMINIMIZED
  2649.  
  2650. Activates the window and displays it as a minimized window.
  2651.  
  2652. SW_SHOWMINNOACTIVE
  2653.  
  2654. Displays the window as a minimized window. The active window remains active.
  2655.  
  2656. SW_SHOWNA
  2657.  
  2658. Displays the window in its current state. The active window remains active.
  2659.  
  2660. SW_SHOWNOACTIVATE
  2661.  
  2662. Displays a window in its most recent size and position. The active window remains active.
  2663.  
  2664. SW_SHOWNORMAL
  2665.  
  2666. Activates and displays a window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when displaying the window for the first time.
  2667.  
  2668. =back
  2669.  
  2670. =head2 Variables
  2671.  
  2672.  $Win32::FileOp::ProgressTitle
  2673.  
  2674. This variable (if defined) contains the text to be displayed on
  2675. the progress dialog if using FOF_SIMPLEPROGRESS. This allows you
  2676. to present the user with your own message about what is happening
  2677. to his computer.
  2678.  
  2679. If the options for the call do not contain FOF_SIMPLEPROGRESS, this
  2680. variable is ignored.
  2681.  
  2682. =head2 Examples
  2683.  
  2684.     use Win32::FileOp;
  2685.  
  2686.     CopyConfirm ('c:\temp\kinter.pl' => 'c:\temp\copy\\',
  2687.                  ['\temp\kinter1.pl', 'temp\kinter2.pl']
  2688.                  => ['c:\temp\copy1.pl', 'c:\temp\copy2.pl']);
  2689.  
  2690.     $Win32::FileOp::ProgressTitle = "Moving the temporary files ...";
  2691.     MoveEx 'c:\temp\file.txt' => 'd:\temp\\',
  2692.            ['c:\temp\file1.txt','c:\temp\file2.txt'] => 'd:\temp',
  2693.            FOF_RENAMEONCOLLISION | FOF_SIMPLEPROGRESS;
  2694.     undef $Win32::FileOp::ProgressTitle;
  2695.  
  2696.     Recycle 'c:\temp\kinter.pl';
  2697.  
  2698. =head2 Handles
  2699.  
  2700. All the functions keep Win32::API handles between calls. If you want to free the handles
  2701. you may undefine them, but NEVER EVER set them to anything else than undef !!!
  2702. Even  "$handlename = $handlename;" would destroy the handle without repair!
  2703. See docs for Data::Lazy.pm for explanation.
  2704.  
  2705. List of handles and functions that use them:
  2706.  
  2707.  $Win32::FileOp::fileop : Copy, CopyEx, CopyConfirm, Move, MoveEx, MoveConfirm
  2708.   Delete, DeleteEx, DeleteConfirm, Recycle, RecycleEx, RecycleConfirm
  2709.  $Win32::FileOp::movefileex : MoveFileEx MoveFile MoveAtReboot
  2710.  $Win32::FileOp::movefileexDel : DeleteAtReboot
  2711.  $Win32::FileOp::copyfile : CopyFile
  2712.  $Win32::FileOp::writeINI : WriteToINI MoveAtReboot DeleteAtReboot
  2713.  $Win32::FileOp::writeWININI : WriteToWININI
  2714.  $Win32::FileOp::deleteINI : DeleteFromINI
  2715.  $Win32::FileOp::deleteWININI : DeleteFromWININI
  2716.  $Win32::FileOp::readINI : ReadINI
  2717.  $Win32::FileOp::readWININI : ReadWININI
  2718.  $Win32::FileOp::GetOpenFileName : OpenDialog
  2719.  $Win32::FileOp::GetSaveFileName : SaveAsDialog
  2720.  $Win32::FileOp::SHAddToRecentDocs : AddToRecentDocs EmptyRecentDocs
  2721.  $Win32::FileOp::DesktopHandle
  2722.  $Win32::FileOp::WindowHandle : OpenDialog SaveDialog
  2723.  $Win32::FileOp::WNetAddConnection3 : Map
  2724.  $Win32::FileOp::WNetGetConnection : Mapped
  2725.  $Win32::FileOp::WNetCancelConnection2 : Unmap Disconnect Map
  2726.  $Win32::FileOp::GetLogicalDrives : FreeDriveLetters Map
  2727.  
  2728. =head1 Notes
  2729.  
  2730. By default all functions are exported! If you do not want to polute your
  2731. namespace too much import only the functions you need.
  2732. You may import either single functions or whole groups.
  2733.  
  2734. The available groups are :
  2735.  
  2736.  BASIC = Move..., Copy..., Recycle... and Delete... functions plus constants
  2737.  _BASIC = FOF_... constants only
  2738.  HANDLES = DesktopHandle GetDesktopHandle WindowHandle GetWindowHandle
  2739.  INI = WriteToINI WriteToWININI ReadINI ReadWININI ReadINISectionKeys
  2740.        DeleteFromINI DeleteFromWININI
  2741.  DIALOGS = OpenDialog, SaveAsDialog and BrowseForFolder plus OFN_...,
  2742.            BIF_... and CSIDL_... constants
  2743.  _DIALOGS = only OFN_..., BIF_... and CSIDL_... constants
  2744.  RECENT = AddToRecentDocs, EmptyRecentDocs
  2745.  DIRECTORY = UpdateDir, FillInDir
  2746.  COMPRESS => Compress Uncompress Compressed SetCompression GetCompression
  2747.              CompressedSize CompressDir UncompressDir
  2748.  MAP => Map Unmap Disconnect Mapped
  2749.  SUBST => Subst Unsubst Substed SubstDev
  2750.  
  2751. Examples:
  2752.  
  2753.  use Win32::FileOp qw(:BASIC GetDesktopHandle);
  2754.  use Win32::FileOp qw(:_BASIC MoveEx CopyEx);
  2755.  use Win32::FileOp qw(:INI :_DIALOGS SaveAsDialog);
  2756.  
  2757. This module contains all methods from Win32::RecycleBin. The only change
  2758. you have to do is to use this module instead of the old Win32::RecycleBin.
  2759. Win32:RecycleBin is not supported anymore!
  2760.  
  2761. =head1 TO-DO
  2762.  
  2763. WNetConnectionDialog, WNetDisconnectDialog
  2764.  
  2765. =head1 AUTHORS
  2766.  
  2767.  Module built by :
  2768.   Jan Krynicky <Jenda@Krynicky.cz>
  2769.   $Bill Luebkert <dbe@wgn.net>
  2770.   Mike Blazer <blazer@peterlink.ru>
  2771.   Aldo Calpini <a.calpini@romagiubileo.it>
  2772.   Michael Yamada <myamada@gj.com>
  2773.  
  2774. =cut
  2775.  
  2776.  
  2777.  
  2778.