长春做网站qianceyun,武昌专业的网络推广团队,温州网红打卡地,免费微信商城系统VC位移操作和以及逻辑驱动器插拔产生的掩码dbv.dbcv_unitmask进行分析的相关代码 一、VC位移操作符和1、右位移操作符 #xff1a;2、左位移操作符 #xff1a; 二、逻辑驱动器插拔产生的掩码 dbv.dbcv_unitmask 进行分析的… VC位移操作和以及逻辑驱动器插拔产生的掩码dbv.dbcv_unitmask进行分析的相关代码 一、VC位移操作符和1、右位移操作符 2、左位移操作符 二、逻辑驱动器插拔产生的掩码 dbv.dbcv_unitmask 进行分析的相关代码1、设备发生改变的消息 WM_DEVICECHANGEA、微软官方 VC 代码B、驱动器号与设备掩码 dbcv_unitmask 的关系 2、设备状态发生改变 WM_DEVICECHANGE 的改进 C# 代码 一、VC位移操作符和
1、右位移操作符
右移运算符是将一个数的二进制位全部右移若干位低位移出(舍弃)。高位的空位补符号位即正数补零负数补1。
语法格式 需要移位的数字 移位的次数
例如 11 2等于2是将数字11的二进制右移2位即00001011------00000010(2) 2 1相当于2/2 99 1: 相当于 99/2 向下取整为49 99 2相当于 99/pow(2,2)向下取整为24 999 i相当于999/pow(2,i) 整数 i相当于将这个整数化为二进制整数并去掉这个数的末尾的 i 位数字
cout (2 1) endl;//输出为 1
cout (99 1) endl;//输出为 49
cout (99 2) endl;// 24
cout (999 3) endl;// 124
cout (1000 4) endl;// 622、左位移操作符
左移运算符是将一个数的二进制位全部左移若干位低位右补0高位左移后溢出舍弃。
语法格式 需要移位的数字 移位的次数
例如 将a的二进制数左移2位右补0。 若a15即二进制数00001111左移2位得00111100即十进制数60。
3 2则是将数字3左移2位。即00000011-----00001100(12); 2 1相当于22。 99 1: 相当于 992 。 99 2相当于 99*pow(2,2)。 999 i相当于999 * pow(2,i)。 整数 i相当于将这个整数化为二进制整数并在这个数的末尾加上 i 个0。
cout (2 1) endl; //输出为 4
cout (99 1) endl; //输出为 198
cout (99 2) endl; // 396
cout (999 3) endl; // 7992
cout (1000 4) endl; // 16000数字1 左移 1 i pow(2,i) 2 i pow(2,i) * 2 3 i pow(2,i) * 3 x i pow(2,i) * x
cout (1 0) endl; // 1
cout (1 1) endl; // 2
cout (1 2) endl; // 4
cout (1 3) endl; // 8
cout (1 4) endl; // 16二、逻辑驱动器插拔产生的掩码 dbv.dbcv_unitmask 进行分析的相关代码
1、设备发生改变的消息 WM_DEVICECHANGE
Windows 在设备发生的情况下如可插拔设备 U盘、移动硬盘、USB串口的插入和弹出光盘插入和弹出会有相应的响应在这里对于编程的识别进行探讨
Windows 定义了一些控制代码和指令当添加新设备或介质如 CD 或 DVD以及删除现有设备或介质时Windows 会给所有顶级窗口发送一组默认设备改变的消息 WM_DEVICECHANGE 在微软官方文档中有具体描述
检测介质插入或删除
每个 WM_DEVICECHANGE 消息都有描述更改的关联事件以及提供有关更改的详细信息的结构。 该结构包含与事件无关的标头 DEV_BROADCAST_HDR后跟与事件相关的成员。 与事件相关的成员描述应用事件的设备。 若要使用此结构应用程序必须首先确定事件类型和设备类型。 然后它们可以使用正确的结构执行适当的操作。
当用户将新的 CD 或 DVD 插入驱动器时应用程序会收到 WM_DEVICECHANGE 消息和 DBT_DEVICEARRIVAL 事件。 应用程序必须检查事件以确保到达的设备的类型是卷dbch_devicetype 成员是 DBT_DEVTYP_VOLUME并且更换会影响介质dbcv_flags 成员是 DBTF_MEDIA。
当用户从驱动器中删除 CD 或 DVD 时应用程序会收到 WM_DEVICECHANGE 消息和 DBT_DEVICEREMOVECOMPLETE 事件。 同样应用程序必须检查事件以确保要删除的设备是卷并且更换会影响介质。
A、微软官方 VC 代码
//C
#include windows.h
#include dbt.h
#include strsafe.h
#pragma comment(lib, user32.lib )void Main_OnDeviceChange( HWND hwnd, WPARAM wParam, LPARAM lParam );
char FirstDriveFromMask( ULONG unitmask ); //prototype/*------------------------------------------------------------------Main_OnDeviceChange( hwnd, wParam, lParam )描述处理发送到应用程序顶级窗口的 WM_DEVICECHANGE 消息。
--------------------------------------------------------------------*/void Main_OnDeviceChange( HWND hwnd, WPARAM wParam, LPARAM lParam ){PDEV_BROADCAST_HDR lpdb (PDEV_BROADCAST_HDR)lParam;TCHAR szMsg[80];switch(wParam ){case DBT_DEVICEARRIVAL:// 检查驱动器中是否插入了CD或DVD。if (lpdb - dbch_devicetype DBT_DEVTYP_VOLUME)//驱动类型为逻辑卷{PDEV_BROADCAST_VOLUME lpdbv (PDEV_BROADCAST_VOLUME)lpdb;if (lpdbv - dbcv_flags DBTF_MEDIA){StringCchPrintf( szMsg, sizeof(szMsg)/sizeof(szMsg[0]), TEXT(驱动器 %c :介质已插入。\n), FirstDriveFromMask(lpdbv -dbcv_unitmask) );MessageBox( hwnd, szMsg, TEXT(WM_DEVICECHANGE), MB_OK );}}break;case DBT_DEVICEREMOVECOMPLETE:// 检查是否已从驱动器中弹出CD或DVD。if (lpdb - dbch_devicetype DBT_DEVTYP_VOLUME)//驱动类型为逻辑卷{PDEV_BROADCAST_VOLUME lpdbv (PDEV_BROADCAST_VOLUME)lpdb;if (lpdbv - dbcv_flags DBTF_MEDIA){StringCchPrintf( szMsg, sizeof(szMsg)/sizeof(szMsg[0]), TEXT(驱动器 %c: 介质已弹出。\n ),FirstDriveFromMask(lpdbv -dbcv_unitmask) );MessageBox( hwnd, szMsg, TEXT(WM_DEVICECHANGE ), MB_OK );}}break;default:/*由于其他设备或原因处理其他 WM_DEVICECHANGE 通知。*/ ;}
}/*------------------------------------------------------------------FirstDriveFromMask( unitmask )
描述
从驱动器号掩码中查找第一个有效的驱动器号。
掩码的格式必须为 bit 0A、bit 1B、bit 2C依此类推。
当相应的位设置为1时将定义有效的驱动器号。
返回找到的第一个驱动器号。
--------------------------------------------------------------------*/char FirstDriveFromMask( ULONG unitmask ){char i;for (i 0; i 26; i){if (unitmask 0x1)break;unitmask unitmask 1;}return( i A );
}B、驱动器号与设备掩码 dbcv_unitmask 的关系
从上面C代码上可以看到对于位操作的右移指令 从中可以看到驱动器掩码与驱动器号的对应关系
驱动器号字母值unitmaskunitmaskunitmask卷号字母10进制数16进制数10进制数二进制数A65112^010^00 0000000000000001B66222^110^01 0000000000000010C67442^210^02 0000000000000100D68882^310^03 0000000000001000E6910162^410^04 0000000000010000F7020322^510^05 0000000000100000G7140642^610^06 0000000001000000H72801282^710^07 0000000010000000I731002562^810^08 0000000100000000J742005122^910^09 0000001000000000K7540010242^1010^10 000001000000000L7680020482^1110^11 000010000000000M77100040962^1210^12 000100000000000N78200080962^1310^13 001000000000000O794000163842^1410^14 010000000000000P808000327682^1510^15 100000000000000Q以此类推
从上表对应关系可以看出对于驱动器号 A 盘的 unitmask 值不能再执行右位移操作。
在对移动U盘和移动硬盘编写的识别程序中参照应用微软以上 C 代码迁移到 C# 中可以发现只有一个分区的移动U盘和移动硬盘完全没有问题。但对于移动U盘和移动硬盘有多个分区时程序就无法完整识别Windows 11unitmask 值会随着设备插入出现 2 个值第一个值对应多分区的第一个盘符值第二个值就无法用微软提供的程序算法解释了。通过对多分区移动盘的识别发现如果移动盘符是 H、I、J、K 四个盘系统给出了 2 个 unitmask 值第一个值对应的第一个 H 盘第二个值比对应的最后一个盘符 K 大取整后就是 K 盘。
当设备被插入/拔出的时候WINDOWS会向每个窗体发送WM_DEVICECHANGE 消息当消息的wParam 值等于 DBT_DEVICEARRIVAL 时表示Media设备被插入并且已经可用如果wParam值等于DBT_DEVICEREMOVECOMPLETE表示Media设备已经被移出。
它们的lParam都指向一个 DEV_BROADCAST_HDR结构体其原形如下
//C
typedef struct _DEV_BROADCAST_HDR
{DWORD dbch_size;DWORD dbch_devicetype;DWORD dbch_reserved;
} DEV_BROADCAST_HDR, *PDEV_BROADCAST_HDR;这个结构体仅仅是一个“头”HDR其后还有附加数据dbch_size表示结构体实例的字节数当其中的dbch_devicetype字段值等于DBT_DEVTYP_VOLUME时表示当前设备是逻辑驱动器且lParam实际上指向的应该是DEV_BROADCAST_VOLUME 结构体实例DEV_BROADCAST_VOLUME 结构体原形如下
//C
typedef struct _DEV_BROADCAST_VOLUME
{DWORD dbcv_size;DWORD dbcv_devicetype;DWORD dbcv_reserved;DWORD dbcv_unitmask;WORD dbcv_flags;
} DEV_BROADCAST_VOLUME, *PDEV_BROADCAST_VOLUME;其中dbcv_unitmask 字段表示当前改变的驱动器掩码第一位表示驱动器号A第二位表示驱动器号B第三位表示驱动器号C以此类推…… dbcv_flags 表示驱动器的类别如果等于1则是光盘驱动器如果是2则是网络驱动器如果是硬盘、U盘则都等于0
所以我只需要在程序中捕捉WM_DEVICECHANGE 消息然后根据具体情况去处理即可。
2、设备状态发生改变 WM_DEVICECHANGE 的改进 C# 代码
//C# 响应消息声明
public const int WM_DEVICECHANGE 0x219;//U盘插入后OS的底层会自动检测到然后向应用程序发送“硬件设备状态改变“的消息
public const int DBT_DEVICEARRIVAL 0x8000; //就是用来表示U盘可用的。一个设备或媒体已被插入一块现在可用。
public const int DBT_DEVICEQUERYREMOVE 0x8001; //审批要求删除一个设备或媒体作品。任何应用程序也不能否认这一要求并取消删除。
public const int DBT_DEVICEQUERYREMOVEFAILED 0x8002; //请求删除一个设备或媒体片已被取消。
public const int DBT_DEVICEREMOVECOMPLETE 0x8004; //一个设备或媒体片已被删除。
public const int DBT_DEVICEREMOVEPENDING 0x8003; //一个设备或媒体一块即将被删除。不能否认的。//C#
public static Listchar Volumes new Listchar();protected override void DefWndProc(ref Message m){if (m.Msg WM_DEVICECHANGE)//设备发生改变{int wp m.WParam.ToInt32();//存储设备插/拔/弹if (wp DBT_DEVICEARRIVAL || wp DBT_DEVICEQUERYREMOVE || wp DBT_DEVICEREMOVECOMPLETE || wp DBT_DEVICEREMOVEPENDING) {DEV_BROADCAST_HDR dbhdr (DEV_BROADCAST_HDR)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_HDR));if (dbhdr.dbch_devicetype 2)//驱动类型为DBT_DEVTYP_VOLUME 逻辑卷{DEV_BROADCAST_VOLUME dbv (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_VOLUME));if (dbv.dbcv_flags 0)//驱动器标识硬盘和U盘{char[] volums GetVolumes(dbv.dbcv_unitmask);int len volums.Length;int start (int)volums[0];int end (int)volums[len - 1];for (int i start; i end; i){string disk ((char)i).ToString() :;if(wp DBT_DEVICEARRIVAL) //存储设备插入{//插入设备后的操作}else if (wp DBT_DEVICEREMOVECOMPLETE) //存储设备拔/弹出{//拔出设备后的操作}} }} else if (dbhdr.dbch_devicetype 3)//DBT_DEVTYP_PORT0x00000003 设备 (串行或并行) {//响应串口并口设备操作} } } base.DefWndProc(ref m); } /// summary根据驱动器掩码返回驱动器号数组/summary/// param nameMask驱动器掩码/param/// returns返回驱动器号数组/returnspublic static char[] GetVolumes(UInt32 Mask){for (int i 0; i 32; i){//uint p (uint)Math.Pow(2, i);//原参考代码uint p (uint)Math.Floor(Math.Log(Mask, 2));//算出驱动器掩码 dbcv_unitmask 以2为底的指数再取整加A的数值就是盘符。//if ((p | Mask) p)//原参考代码if (i p){Volumes.Add((char)(A i));}}return Volumes.ToArray();}移动 U盘的驱动类型是 Removable Media 移动硬盘的驱动类型是 External hard disk media 本地硬盘的驱动类型是 Fixed hard disk media。
在对以下 C# 代码进行测试插入后的多分区移动磁盘可以识别盘符是对系统所有磁盘进行判断不能对插入、拔出进行响应。
//C#/// summary获取U盘和可移动硬盘盘符名称/summary/// returns/returnspublic static Liststring GetDVN(){Liststring lstdisk new Liststring();ManagementClass mgtcls new ManagementClass(Win32_DiskDrive);var disks mgtcls.GetInstances();foreach (ManagementObject mo in disks){if (mo.Properties[mediatype].Value null || mo.Properties[mediatype].Value.ToString() External hard disk media || mo.Properties[mediatype].Value.ToString() Removable Media){foreach (ManagementObject diskpartition in mo.GetRelated(win32_diskpartition)){foreach (ManagementObject disk in diskpartition.GetRelated(win32_logicaldisk)){lstdisk.Add(disk.Properties[name].Value.ToString());}}// continue;}}return lstdisk;}综合上述代码总结可以对设备发生变化时进行的相应的程序操作。