U盘插入时复制

U盘插入时复制

以前写过的一篇文章,写作水平差了点~~

版权说明:欢迎转载,但转载时请注明作者及出处!
这个程序的作用就是当USB可移动设备插入电脑的时候,USB_COPY会提示是否拷贝所有文件到指定目录。
这个程序的主要思路就是当USB设备插入时,系统会发送WM_DEVICECHANGE消息,只要对这个消息进行处理,添加拷贝函数就完成了框架。其他的地方还得细化,下面就来分析这个程序的核心部分。
分析的过程中本程序没有使用的结构体或者函数一笔带过,如果要想了解更多,请参见MSDN--Windows开发最权威的宝典^_^
1、对WM_DEVICECHANGE消息的处理。
WM_DEVICECHANGE消息的wParam参数存储的是设备改变的事件,lParam参数存储的是指向相应的结构体指针。
wParam参数取值如下:
DBT_CONFIGCHANGECANCELED--A request to change the current configuration (dock or undock) has been canceled.
DBT_CONFIGCHANGED--The current configuration has changed, due to a dock or undock.
DBT_CUSTOMEVENT--A custom event has occurred.Windows NT 4.0 and Windows 95:  This value is not supported.
DBT_DEVICEARRIVAL--A device or piece of media has been inserted and is now available.
DBT_DEVICEQUERYREMOVE--Permission is requested to remove a device or piece of media. Any application can deny this request and cancel the removal.
DBT_DEVICEQUERYREMOVEFAILED--A request to remove a device or piece of media has been canceled.
DBT_DEVICEREMOVECOMPLETE--A device or piece of media has been removed.
DBT_DEVICEREMOVEPENDING--A device or piece of media is about to be removed. Cannot be denied.
DBT_DEVICETYPESPECIFIC--A device-specific event has occurred.
DBT_DEVNODES_CHANGED--A device has been added to or removed from the system.
Windows NT 4.0 and Windows Me/98/95:  This value is not supported.
DBT_QUERYCHANGECONFIG--Permission is requested to change the current configuration (dock or undock).
DBT_USERDEFINED--The meaning of this message is user-defined.
我们需要考虑的就是DBT_DEVICEARRIVAL--系统设备(或者光盘)插入并且变为有效。
lParam参数的取值为指向wParam参数事件的结构体。本程序所用到的为指向DBT_DEVICEARRIVAL事件结构体DEV_BROADCAST_HDR的指针,其他的请参考MSDN。
DEV_BROADCAST_HDR定义如下:
typedef struct _DEV_BROADCAST_HDR {
  DWORD dbch_size;//Size of this structure, in bytes.
  DWORD dbch_devicetype;//Device type, which determines the event-specific information that follows the first three members.
  DWORD dbch_reserved;//Reserved; do not use.
} DEV_BROADCAST_HDR, *PDEV_BROADCAST_HDR;
我们主要使用的就是dbch_devicetype结构成员,取值如下:
DBT_DEVTYP_DEVICEINTERFACE--Class of devices. This structure is a DEV_BROADCAST_DEVICEINTERFACE structure.Windows XP/2000 and Windows Me/98:  This value is not supported.
DBT_DEVTYP_HANDLE--File system handle. This structure is a DEV_BROADCAST_HANDLE structure.Windows XP/2000 and Windows Me/98:  This value is not supported.
DBT_DEVTYP_OEM--OEM- or IHV-defined device type. This structure is a DEV_BROADCAST_OEM structure.
DBT_DEVTYP_PORT--Port device (serial or parallel). This structure is a DEV_BROADCAST_PORT structure.
DBT_DEVTYP_VOLUME--Logical volume. This structure is a DEV_BROADCAST_VOLUME structure.
我们用到的是DBT_DEVTYP_VOLUME成员,这个成员说明插入的是逻辑卷,也就是磁盘(光盘)。
好了,介绍了这么些关于WM_DEVICECHANGE消息的结构体,下面来看具体实现代码:
/* 系统设备改变事件处理函数 OnDeviceChange
 参数:
  wParam: 设备改变的事件
  lParam: 指向相应的结构体指针
*/
LRESULT CUSBCopyDlg::OnDeviceChange(WPARAM wParam, LPARAM lParam)
{
 CString strMobileDriver;
 switch (wParam)
 {
 case DBT_DEVICEARRIVAL://系统设备插入并且变为有效
  DEV_BROADCAST_HDR *stHDR;
  stHDR = (DEV_BROADCAST_HDR *)lParam;
  switch(stHDR->dbch_devicetype)//判断设备类型
  {
  case DBT_DEVTYP_VOLUME://逻辑卷标
   strMobileDriver = GetMobileDrive();//取得可移动磁盘盘符存储在strMobileDriver成员函数中
   if (strMobileDriver  )
    strSourcePath = strMobileDriver + "\\*.*";
   else
    break;
   break;
  }
 default :  //别的事件
  break;
 }
 return 0;
}
2、CopyFile和GetMobileDrive函数--注
2.1 CopyFile函数
这个函数中使用了SHFILEOPSTRUCT结构体,这个结构体定义如下:
typedef struct _SHFILEOPSTRUCT {
    HWND hwnd;//要显示文件复制状态的Windows对话框句柄
    UINT wFunc;//指示文件操作方式(复制、删除、移动、重命名)
    LPCTSTR pFrom;//源文件地址(支持通配符)
    LPCTSTR pTo;//目的地址(支持通配符)
    FILEOP_FLAGS fFlags;//控制文件操作的标志
    BOOL fAnyOperationsAborted;//是否接受用户中断文件操作
    LPVOID hNameMappings;//名字映射
    LPCTSTR lpszProgressTitle;//文件操作进度对话框题头
} SHFILEOPSTRUCT, *LPSHFILEOPSTRUCT;
在这个本程序中,只需设置wFunc为FO_COPY(文件复制),pFrom,pTo,fAnyOperationsAborted为FALSE(既不允许用户中断文件操作),fFlags根据参数设置为FOF_SILENT(不现实进度对话框)或者为NULL;
填写好SHFILEOPSTRUCT结构体之后,就调用SHFileOperation函数进行文件操作,该函数定义如下:
int SHFileOperation(
    LPSHFILEOPSTRUCT lpFileOp //指向SHFILEOPSTRUCT结构体的指针
);
具体代码:
/* 文件拷贝函数CopyFile
 参数:
  Hint:  文件复制结束是否提示
  CopyEnable: 是否允许复制文件
  SourcePath: 文件源地址
  DestinationPath:文件目的地址
 返回值:
  true:  复制成功
  false:  复制失败
*/
bool CUSBCopyDlg::CopyFile(bool Hint, bool CopyEnable, CString SourcePath, CString DestinationPath)
{
 if (CopyEnable)
 {
  
  CString DirName = GetDirectoryName(); //取得复制到的目录名称
  CreateDirectory(DestinationPath + '\\' + DirName , NULL);//创建目录

  SHFILEOPSTRUCT FileOP;   //声明文件操作结构体

  FileOP.hwnd = m_hWnd;   //句柄
  if (bProgress)
   FileOP.fFlags = NULL;
  else
   FileOP.fFlags = FOF_SILENT ; //操作标志位
  FileOP.wFunc = FO_COPY;   //操方式
  FileOP.pFrom = SourcePath;  //源地址
  FileOP.pTo = DestinationPath + '\\' + DirName;  //目的地址
  FileOP.fAnyOperationsAborted = false; //是否允许中断操作
  FileOP.hNameMappings = NULL;
  FileOP.lpszProgressTitle = NULL;

  int MSG = SHFileOperation(&FileOP); //执行复制操作
  if (MSG == 0)    //复制成功
  {
   CopyEnable = true;
   bResult = true;
   if(Hint)
    MessageBox("复制成功!" , "提示" , MB_OK | MB_ICONINFORMATION);
  }
  else     //复制失败
  {
   bResult = false;
   if (Hint)
    MessageBox("复制失败!" , "提示" , MB_OK | MB_ICONERROR);
  }

 }
 return bResult;
}
2.2GetMoblieDriver函数
这个函数使用了GetLogicalDrives函数取得系统所有盘符:
DWORD GetLogicalDrives(void);
函数的返回值是当前系统所有有效磁盘驱动器的位掩码(如00000011111)。
位掩码中位置为0的位如果为1,那么代表驱动器A存在,位置为1的位如果为1,那么代表驱动器B存在,位置为2的位如果为1,那么代表驱动器C存在,以此类推。
然后调用GetDriveType函数来寻找是否存在可移动磁盘:
UINT GetDriveType(
  LPCTSTR lpRootPathName //盘符(X:),一定要有冒号!
);
GetDriveType函数的返回值为:
DRIVE_UNKNOWN--The drive type cannot be determined.
DRIVE_NO_ROOT_DIR--The root path is invalid. For example, no volume is mounted at the path.
DRIVE_REMOVABLE--The disk can be removed from the drive.
DRIVE_FIXED--The disk cannot be removed from the drive.
DRIVE_REMOTE--The drive is a remote (network) drive.
DRIVE_CDROM--The drive is a CD-ROM drive.
DRIVE_RAMDISK--The drive is a RAM disk.
USB移动存储器是DRIVE_REMOVABLE,我们只要判断GetDriverType返回的那个盘符的类型是不是DRIVE_REMOVABLE类型就可以了。
具体代码:
/* 取得可移动磁盘盘符函数GetMobileDrive(void)
 参数:
  无
 返回值:
  盘符的字符串(如C:、D:等)

*/
CString CUSBCopyDlg::GetMobileDrive(void)
{
 CString strDriver;
 DWORD id = GetLogicalDrives();
 for (int i = 1; i < 26; i++)
 {
  if ((id & (1 << i)) != 0)
  {
   CString strDrv = CString(char('A' + i)) + ":";
   if (GetDriveType(strDrv) == DRIVE_REMOVABLE)
    strDriver = strDrv;
  }
 }
 return strDriver;

}
3、显示目录浏览对话框
这个函数使用了BROWSEINFO结构体:
typedef struct _browseinfo {
    HWND hwndOwner;//所属Windows窗体句柄
    LPCITEMIDLIST pidlRoot;//默认选择的文件夹
    LPTSTR pszDisplayName;//接受用户选择目录路径的字符串
    LPCTSTR lpszTitle;//对话框标题
    UINT ulFlags;//对话框选项标记
    BFFCALLBACK lpfn;//回调函数
    LPARAM lParam;//回调函数的参数
    int iImage;//接受关联到选择的文件夹的图像变量(为索引值)
} BROWSEINFO, *PBROWSEINFO, *LPBROWSEINFO;
然后调用SHBrowseForFolder函数:
LPITEMIDLIST SHBrowseForFolder(
          LPBROWSEINFO lpbi //指向BROWSEINFO结构体指针
);
返回指向选项的标示符表,这个标示符表存储了所选择的文件夹的路径
调用SHGetPathFromIDList函数提取存储在LPITEMIDLIST中的文件夹路径
BOOL SHGetPathFromIDList(
    LPCITEMIDLIST pidl, //LPITEMIDLIST地址
    LPTSTR pszPath //接受路径的地址指针
);
成功返回TRUE。
具体代码:
void CConfigDlg::OnBnClickedBrower()
{
 char buf[MAX_PATH];
 char Value[MAX_PATH];
 BROWSEINFO bi;  //选择目录对话框结构体
 bi.hwndOwner = m_hWnd; //所属窗口
 bi.iImage = 0;
 bi.lParam = 0;  //回调函数参数
 bi.lpfn = NULL;  //回调函数
 bi.lpszTitle = "请选择保存目录";
 bi.pidlRoot = NULL;
 bi.pszDisplayName = buf;
 bi.ulFlags = BIF_RETURNONLYFSDIRS;   //标记位

 LPITEMIDLIST pItemIDList = SHBrowseForFolder(&bi); //显示对话框
 if ( pItemIDList ) //点击确定
 {
  SHGetPathFromIDList(pItemIDList, buf);
  m_CtrlDirPath = buf;
 }
 else   //关闭对话框或者点击取消
  MessageBox("您没有选择保存目录,将使用默认路径" , "提示" , MB_OK | MB_ICONINFORMATION); 
 UpdateData(false);
}
不足:插入多个U盘可能出现错误,原因在于获取盘符时只获得第一个。
后记:
    我正在考虑把它改写成课件拷贝软件(基本原理、核心不变)。在学校老师的课件都拷贝到电脑一个盘上,下课同学们都去拷课件,插上U盘后到硬盘里找课件,然后复制,粘贴到U盘里。我想把这个小程序改写一下,把老师的课件存放情况弄成一个列表,然后当同学的U盘插上后,自动弹出课件信息列表的对话框,同学选择一个或多个老师的课件然后按确定,就自动拷贝到U盘了。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值