VirtualBox WinXP 蓝屏问题

在 VirtualBox 中安装了一个 Windows XP,结果遇到每次进入桌面就重启动的问题。能够进入“安全模式”。于是用 WinDBG 分析Dump File,结果如下

virbsod

是 “IntelPPM.sys” 导致的。

在网上搜索 VirtualBox IntelPPM.sys 发现很多人遇到这样的问题。有人建议直接删除这个SYS文件,我试验过并不好用,最后是从安全模式进入,启动注册表

在下面的键值中,将 Start 修改为 4

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Intelppm

再次重启就OK了。

参考:

1.“Problems with Intelppm.sys and processr.sys under Virtual PC / Virtual Server”
http://blogs.msdn.com/b/virtual_pc_guy/archive/2005/10/24/484461.aspx

测试文件生成器

测试文件生成器

这个工具可以生成指定大小的随机内容文件以供测试。生成的内容是完全没有规律的随机数,压缩软件甚至无法对其进行压缩,是用来测试拷贝等等有力的工具。

使用方法:

fg /s /n /r

/s 指定生成文件的大小,单位是KB

/n 指定生成文件的数量

/r 完全随机内容(每次生成随机内容不同)

例如,fg /s4096 /n10 将会生成10个大小为 4096KB 的文件。

因为是内存直接写入文件的,因此目前的限制大约只能生成最大2G的内容。

fg

===============================================================

2023年10月 在 Windows 下可以直接通过fsutil命令完成相同的工作

fsutil file createnew 文件名 大小

例如:fsutil file createnew test.txt 1024 将会生成一个内容为全 00 的 1024字节的 test.txt文件。

又一种枚举当前系统中硬盘的方法(2)

这次使用 SetupDiGetClassDevs 和 SetupDiEnumDeviceInterfaces 函数直接查询系统中的硬盘信息。具体的解释,请参考

http://cutebunny.blog.51cto.com/301216/625577 《windows的磁盘操作之七——获取当前所有的物理磁盘号》 这是非常好的文章。

枚举的结果并非 \\.\PhysicalDriveX 而是类似 \\?\usbstor#disk&ven_adata&prod_usb_flash_drive&rev_1.00#000000000000000922&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b} 这样的字符串。(天杀同学指出:这种符号连接,是链接到atapi生成的设备,比如\device\ide\idedeviceP0TTolo-3这种设备上的,这个设备上面会附加\Device\Harddisk0\DR0,应用程序打开\\?\ide#xxxx这个,就和打开\\.\PhysicalDrive0一样了,因为请求在驱动里面都是从上层往下层传递的. )同样可以直接给CreateFile作为参数使用。

另外,这个程序如果直接运行,会出现打印出来上述字符串,然后又显示 “CreateFile() Error: 5”的问题。这个错误表示 “Access denied”.

它是由于在程序中使用CreateFile而没有相应的权限导致的。

程序中使用了很多C语言的变长数组,这在我看起来无比诡异…….

编译中需要加入 lib,具体方式请参考下图

setting

运行结果如下图,可以看到,最后还给出了硬盘号。

phy2

这样的方法更精确一些,在很多硬盘的情况下会节省查询的时间,但是和1中的方法相比,复杂度提高了很多倍。

代码如下

// phylist1.cpp : Defines the entry point for the console application.
//

#include   "stdafx.h"
#include   <windows.h>
#include   <stdio.h>   
#include   <conio.h> 
#include   <winioctl.h>
#include   <setupapi.h>

#define MAX_DEVICE  10
#define INTERFACE_DETAIL_SIZE    (1024)
DEFINE_GUID(GUID_DEVINTERFACE_DISK,   0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);

/******************************************************************************
* Function: get device path from GUID
* input: lpGuid, GUID pointer
* output: pszDevicePath, device paths
* return: Succeed, the amount of found device paths
*         Fail, -1
******************************************************************************/
DWORD GetDevicePath(LPGUID lpGuid, WCHAR **pszDevicePath)
{
    HDEVINFO hDevInfoSet;
    SP_DEVICE_INTERFACE_DATA ifdata;
    PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail;
    DWORD nCount;
    BOOL result;
 
    //get a handle to a device information set
    hDevInfoSet = SetupDiGetClassDevs(
                    lpGuid,      // class GUID
                    NULL,        // Enumerator
                    NULL,        // hwndParent
                    DIGCF_PRESENT | DIGCF_DEVICEINTERFACE    // present devices
                    );
 
    //fail...
    if (hDevInfoSet == INVALID_HANDLE_VALUE)
    {
        fprintf(stderr, "IOCTL_STORAGE_GET_DEVICE_NUMBER Error: %ld\n", GetLastError());
        return (DWORD)-1;
    }
 
    pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(INTERFACE_DETAIL_SIZE);
    if (pDetail == NULL)
    {
        return (DWORD)-1;
    }
    pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
 
    nCount = 0;
    result = TRUE;
 
    // device index = 0, 1, 2... test the device interface one by one
    while (result)
    {
        ifdata.cbSize = sizeof(ifdata);
 
        //enumerates the device interfaces that are contained in a device information set
        result = SetupDiEnumDeviceInterfaces(
                    hDevInfoSet,     // DeviceInfoSet
                    NULL,            // DeviceInfoData
                    lpGuid,          // GUID
                    nCount,   // MemberIndex
                    &ifdata        // DeviceInterfaceData
                    );
        if (result)
        {
            // get details about a device interface
            result = SetupDiGetDeviceInterfaceDetail(
                        hDevInfoSet,    // DeviceInfoSet
                        &ifdata,        // DeviceInterfaceData
                        pDetail,        // DeviceInterfaceDetailData
                        INTERFACE_DETAIL_SIZE,    // DeviceInterfaceDetailDataSize
                        NULL,           // RequiredSize
                        NULL          // DeviceInfoData
                        );
            if (result)
            {
                // copy the path to output buffer
                wcscpy(pszDevicePath[nCount], pDetail->DevicePath);
                printf("%ws\n", pDetail->DevicePath);
                nCount++;
            }
        }
    }
 
    free(pDetail);
    (void)SetupDiDestroyDeviceInfoList(hDevInfoSet);
 
    return nCount;
}

/******************************************************************************
* Function: get all present disks' physical number
* input: N/A
* output: ppDisks, array of disks' physical number
* return: Succeed, the amount of present disks
*         Fail, -1
******************************************************************************/
DWORD GetAllPresentDisks(DWORD **ppDisks)
{
    WCHAR *szDevicePath[MAX_DEVICE];        // device path
    DWORD nDevice;
    HANDLE hDevice;
    STORAGE_DEVICE_NUMBER number;
    BOOL result;
    DWORD readed;
    WORD i, j;
 
    for (i = 0; i < MAX_DEVICE; i++)
    {
        szDevicePath[i] = (WCHAR *)malloc(INTERFACE_DETAIL_SIZE);
        if (NULL == szDevicePath[i])
        {
            for (j = 0; j < i; j++)
            {
                free(szDevicePath[i]);
            }
            return (DWORD)-1;
        }
    }
 
    // get the device paths
    nDevice = GetDevicePath(const_cast<LPGUID>(&GUID_DEVINTERFACE_DISK), szDevicePath);
    if ((DWORD)-1 == nDevice)
    {
        for (i = 0; i < MAX_DEVICE; i++)
        {
            free(szDevicePath[i]);
        }
        return (DWORD)-1;
    }
 
    *ppDisks = (DWORD *)malloc(sizeof(DWORD) * nDevice);

    // get the disk's physical number one by one
    for (i = 0; i < nDevice; i++)
    {
        hDevice = CreateFile(
                    szDevicePath[i], // drive to open
                    GENERIC_READ | GENERIC_WRITE,     // access to the drive
                    FILE_SHARE_READ | FILE_SHARE_WRITE, //share mode
                    NULL,             // default security attributes
                    OPEN_EXISTING,    // disposition
                    0,                // file attributes
                    NULL            // do not copy file attribute
                    );
        if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
        {
            for (j = 0; j < MAX_DEVICE; j++)
            {
                free(szDevicePath[j]);
            }
            free(*ppDisks);
            fprintf(stderr, "CreateFile() Error: %ld\n", GetLastError());
            return DWORD(-1);
        }
        result = DeviceIoControl(
                    hDevice,                // handle to device
                    IOCTL_STORAGE_GET_DEVICE_NUMBER, // dwIoControlCode
                    NULL,                            // lpInBuffer
                    0,                               // nInBufferSize
                    &number,           // output buffer
                    sizeof(number),         // size of output buffer
                    &readed,       // number of bytes returned
                    NULL      // OVERLAPPED structure
                    );
        if (!result) // fail
        {
            fprintf(stderr, "IOCTL_STORAGE_GET_DEVICE_NUMBER Error: %ld\n", GetLastError());
            for (j = 0; j < MAX_DEVICE; j++)
            {
                free(szDevicePath[j]);
            }
            free(*ppDisks);
            (void)CloseHandle(hDevice);
            return (DWORD)-1;
        }
        *(*ppDisks + i) = number.DeviceNumber;
		// printf("%d\n",number.DeviceNumber);
        (void)CloseHandle(hDevice);
    }
 
    for (i = 0; i < MAX_DEVICE; i++)
    {
        free(szDevicePath[i]);
    }
    return nDevice;
}

int _tmain(int argc, _TCHAR* argv[])
{
	DWORD *pDisk;
	int t,j;
	t=GetAllPresentDisks(&pDisk);
	for (j=0; j<t;j++)
	{
      printf("%d \n", *pDisk++);
	}

	_getch(); 
	return 0;
}

 

完整代码下载

Phylist2

枚举当前系统中硬盘的方法(1)

枚举的结果是 “\\.\PhysicalDriveX”这样的形式。

需要注意的是:程序必须在 Administrator 权限下运行。即运行时,要求 “Run as Administrator”。同样在VS2008中编译时,由于权限不够,可能无法看到运行结果。本程序使用的是最传统的方法,使用CreateFile尝试不同的 PhysicalDirve+Number如果能够打开就是存在的。

#include "stdafx.h"
#include   <windows.h>   
#include   <stdio.h>   
#include   <conio.h> 

int _tmain(int argc, _TCHAR* argv[])
{
	int    i;
	TCHAR  Device[0x20];
	HANDLE hDevice;

	for (i=0;i<10;i++)

	{
		wsprintf(Device,TEXT("\\\\.\\PhysicalDrive%d"), i);
		
		hDevice = CreateFile(Device, 
						GENERIC_READ,
						FILE_SHARE_READ, 
						NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);

		if (hDevice!=INVALID_HANDLE_VALUE) {printf("%ws \n",Device); }
		CloseHandle( hDevice );   
	}



	_getch(); 
	return 0;
}

 

phylist1

获得当前系统增加/移除USB设备名称的方法 VC (2)

上面一篇文章给出了 Delphi 版本获得当前系统增加/移除USB设备名称的方法。这篇给出一个VC 的版本。编译器为 VS2008 Express,代码如下

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
#include <dbt.h>
#include <Shellapi.h>
// This GUID is for all USB 
/* A5DCBF10-6530-11D2-901F-00C04FB951ED */
GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED };
// For informational messages and window titles
PWSTR g_pszAppName;
// Forward declarations
void OutputMessage(HWND hOutWnd, WPARAM wParam, LPARAM lParam);
void ErrorHandler(LPTSTR lpszFunction);
//
// DoRegisterDeviceInterfaceToHwnd
//
BOOL DoRegisterDeviceInterfaceToHwnd( 
    IN GUID InterfaceClassGuid, 
    IN HWND hWnd,
    OUT HDEVNOTIFY *hDeviceNotify 
)
// Routine Description:
//     Registers an HWND for notification of changes in the device interfaces
//     for the specified interface class GUID.
// Parameters:
//     InterfaceClassGuid - The interface class GUID for the device 
//         interfaces.
//     hWnd - Window handle to receive notifications.
//     hDeviceNotify - Receives the device notification handle. On failure, 
//         this value is NULL.
// Return Value:
//     If the function succeeds, the return value is TRUE.
//     If the function fails, the return value is FALSE.
// Note:
//     RegisterDeviceNotification also allows a service handle be used,
//     so a similar wrapper function to this one supporting that scenario
//     could be made from this template.
{
    DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
    ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );
    NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    NotificationFilter.dbcc_classguid = InterfaceClassGuid;
    *hDeviceNotify = RegisterDeviceNotification( 
        hWnd,                       // events recipient
        &NotificationFilter,        // type of device
        DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle
        );
    if ( NULL == *hDeviceNotify ) 
    {
        ErrorHandler(TEXT("RegisterDeviceNotification"));
        return FALSE;
    }
    return TRUE;
}
//
// MessagePump
//
void MessagePump(
    HWND hWnd
)
// Routine Description:
//     Simple main thread message pump.
//
// Parameters:
//     hWnd - handle to the window whose messages are being dispatched
// Return Value:
//     None.
{
    MSG msg; 
    int retVal;
    // Get all messages for any window that belongs to this thread,
    // without any filtering. Potential optimization could be
    // obtained via use of filter values if desired.
    while( (retVal = GetMessage(&msg, NULL, 0, 0)) != 0 ) 
    { 
        if ( retVal == -1 )
        {
            ErrorHandler(TEXT("GetMessage"));
            break;
        }
        else
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    } 
}
//
// WinProcCallback
//
INT_PTR WINAPI WinProcCallback(
                              HWND hWnd,
                              UINT message,
                              WPARAM wParam,
                              LPARAM lParam
                              )
// Routine Description:
//     Simple Windows callback for handling messages.
//     This is where all the work is done because the example
//     is using a window to process messages. This logic would be handled 
//     differently if registering a service instead of a window.
// Parameters:
//     hWnd - the window handle being registered for events.
//     message - the message being interpreted.
//     wParam and lParam - extended information provided to this
//          callback by the message sender.
//     For more information regarding these parameters and return value,
//     see the documentation for WNDCLASSEX and CreateWindowEx.
{
    LRESULT lRet = 1;
    static HDEVNOTIFY hDeviceNotify;
    static HWND hEditWnd;
    static ULONGLONG msgCount = 0;
	
	switch (message)
    {
    case WM_CREATE:
        //
        // This is the actual registration., In this example, registration 
        // should happen only once, at application startup when the window
        // is created.
        //
        // If you were using a service, you would put this in your main code 
        // path as part of your service initialization.
        //
        if ( ! DoRegisterDeviceInterfaceToHwnd(
                        GUID_DEVINTERFACE_USB_DEVICE, 
                        hWnd,
                        &hDeviceNotify) )
        {
            // Terminate on failure.
            ErrorHandler(TEXT("DoRegisterDeviceInterfaceToHwnd"));
            ExitProcess(1);
        }

        //
        // Make the child window for output.
        //
        hEditWnd = CreateWindow(TEXT("EDIT"),// predefined class 
                                NULL,        // no window title 
                                WS_CHILD | WS_VISIBLE | WS_VSCROLL | 
                                ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, 
                                0, 0, 0, 0,  // set size in WM_SIZE message 
                                hWnd,        // parent window 
                                (HMENU)1,    // edit control ID 
                                (HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE), 
                                NULL);       // pointer not needed
        if ( hEditWnd == NULL )
        {
            // Terminate on failure.
            ErrorHandler(TEXT("CreateWindow: Edit Control"));
            ExitProcess(1);
        }
        // Add text to the window. 
        SendMessage(hEditWnd, WM_SETTEXT, 0, 
            (LPARAM)TEXT("Registered for USB device notification...\n"));
        break;
    case WM_SETFOCUS: 
        SetFocus(hEditWnd);
        break;
    case WM_SIZE: 
        // Make the edit control the size of the window's client area. 
        MoveWindow(hEditWnd, 
                   0, 0,                  // starting x- and y-coordinates 
                   LOWORD(lParam),        // width of client area 
                   HIWORD(lParam),        // height of client area 
                   TRUE);                 // repaint window
        break;
    case WM_DEVICECHANGE :
    {
        //
        // This is the actual message from the interface via Windows messaging.
        // This code includes some additional decoding for this particular device type
        // and some common validation checks.
        //
        // Note that not all devices utilize these optional parameters in the same
        // way. Refer to the extended information for your particular device type 
        // specified by your GUID.
        //
        PDEV_BROADCAST_DEVICEINTERFACE b = (PDEV_BROADCAST_DEVICEINTERFACE) lParam;
        TCHAR strBuff[256];
        // Output some messages to the window.
        switch (wParam)
        {
        case DBT_DEVICEARRIVAL:
            msgCount++;
            StringCchPrintf(
                strBuff, 256, 
                TEXT("Message %d: DBT_DEVICEARRIVAL\n"), msgCount);
        OutputMessage(hEditWnd, wParam, (LPARAM)strBuff);
            StringCchPrintf(
                strBuff, 256, 
				TEXT("USB Device information: \n"));
        OutputMessage(hEditWnd, wParam, (LPARAM)strBuff);
		//MultiByteToWideChar(CP_ACP, 0, strBuff,256,b->dbcc_name,sizeof(b->dbcc_name));
        OutputMessage(hEditWnd, wParam, (LPARAM)b->dbcc_name);
            break;
        case DBT_DEVICEREMOVECOMPLETE:
            msgCount++;
            StringCchPrintf(
                strBuff, 256, 
                TEXT("Message %d: DBT_DEVICEREMOVECOMPLETE\n"), msgCount);
            break;
        case DBT_DEVNODES_CHANGED:
            msgCount++;
            StringCchPrintf(
                strBuff, 256, 
                TEXT("Message %d: DBT_DEVNODES_CHANGED\n"), msgCount);
            break;
        default:
            msgCount++;
            StringCchPrintf(
                strBuff, 256, 
                TEXT("Message %d: WM_DEVICECHANGE message received, value %d unhandled.\n"), 
                msgCount, wParam);
            break;
        }
        OutputMessage(hEditWnd, wParam, (LPARAM)strBuff);
    }
            break;
    case WM_CLOSE:
        if ( ! UnregisterDeviceNotification(hDeviceNotify) )
        {
           ErrorHandler(TEXT("UnregisterDeviceNotification")); 
        }
        DestroyWindow(hWnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        // Send all other messages on to the default windows handler.
        lRet = DefWindowProc(hWnd, message, wParam, lParam);
        break;
    }
    return lRet;
}
#define WND_CLASS_NAME TEXT("SampleAppWindowClass")
//
// InitWindowClass
//
BOOL InitWindowClass()
// Routine Description:
//      Simple wrapper to initialize and register a window class.
// Parameters:
//     None
// Return Value:
//     TRUE on success, FALSE on failure.
// Note: 
//     wndClass.lpfnWndProc and wndClass.lpszClassName are the
//     important unique values used with CreateWindowEx and the
//     Windows message pump.
{
    WNDCLASSEX wndClass;
    wndClass.cbSize = sizeof(WNDCLASSEX);
    wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
    wndClass.hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(0));
    wndClass.lpfnWndProc = reinterpret_cast<WNDPROC>(WinProcCallback);
    wndClass.cbClsExtra = 0;
    wndClass.cbWndExtra = 0;
    wndClass.hIcon = LoadIcon(0,IDI_APPLICATION);
    wndClass.hbrBackground = CreateSolidBrush(RGB(192,192,192));
    wndClass.hCursor = LoadCursor(0, IDC_ARROW);
    wndClass.lpszClassName = WND_CLASS_NAME;
    wndClass.lpszMenuName = NULL;
    wndClass.hIconSm = wndClass.hIcon;

    if ( ! RegisterClassEx(&wndClass) )
    {
        ErrorHandler(TEXT("RegisterClassEx"));
        return FALSE;
    }
    return TRUE;
}
//
// main
//
int __stdcall _tWinMain(
                      HINSTANCE hInstanceExe, 
                      HINSTANCE, // should not reference this parameter
                      PTSTR lpstrCmdLine, 
                      int nCmdShow
                      )
{
//
// To enable a console project to compile this code, set
// Project->Properties->Linker->System->Subsystem: Windows.
//
    int nArgC = 0;
    PWSTR* ppArgV = CommandLineToArgvW(lpstrCmdLine, &nArgC);
    g_pszAppName = ppArgV[0];
    if ( ! InitWindowClass() )
    {
        // InitWindowClass displays any errors
        return -1;
    }
    // Main app window
    HWND hWnd = CreateWindowEx(
                    WS_EX_CLIENTEDGE | WS_EX_APPWINDOW,
                    WND_CLASS_NAME,
                    g_pszAppName,
                    WS_OVERLAPPEDWINDOW, // style
                    CW_USEDEFAULT, 0, 
                    640, 480,
                    NULL, NULL, 
                    hInstanceExe, 
                    NULL);
    
    if ( hWnd == NULL )
    {
        ErrorHandler(TEXT("CreateWindowEx: main appwindow hWnd"));
        return -1;
    }
    // Actually draw the window.
    ShowWindow(hWnd, SW_SHOWNORMAL);
    UpdateWindow(hWnd);
    // The message pump loops until the window is destroyed.
    MessagePump(hWnd);
    return 1;
}
//
// OutputMessage
//
void OutputMessage(
    HWND hOutWnd, 
    WPARAM wParam, 
    LPARAM lParam
)
// Routine Description:
//     Support routine.
//     Send text to the output window, scrolling if necessary.
// Parameters:
//     hOutWnd - Handle to the output window.
//     wParam  - Standard windows message code, not used.
//     lParam  - String message to send to the window.
// Return Value:
//     None
// Note:
//     This routine assumes the output window is an edit control
//     with vertical scrolling enabled.
//     This routine has no error checking.
{
    LRESULT   lResult;
    LONG      bufferLen;
    LONG      numLines;
    LONG      firstVis;
  
    // Make writable and turn off redraw.
    lResult = SendMessage(hOutWnd, EM_SETREADONLY, FALSE, 0L);
    lResult = SendMessage(hOutWnd, WM_SETREDRAW, FALSE, 0L);
    // Obtain current text length in the window.
    bufferLen = SendMessage (hOutWnd, WM_GETTEXTLENGTH, 0, 0L);
    numLines = SendMessage (hOutWnd, EM_GETLINECOUNT, 0, 0L);
    firstVis = SendMessage (hOutWnd, EM_GETFIRSTVISIBLELINE, 0, 0L);
    lResult = SendMessage (hOutWnd, EM_SETSEL, bufferLen, bufferLen);
    // Write the new text.
    lResult = SendMessage (hOutWnd, EM_REPLACESEL, 0, lParam);
    // See whether scrolling is necessary.
    if (numLines > (firstVis + 1))
    {
        int        lineLen = 0;
        int        lineCount = 0;
        int        charPos;
        // Find the last nonblank line.
        numLines--;
        while(!lineLen)
        {
            charPos = SendMessage(
                hOutWnd, EM_LINEINDEX, (WPARAM)numLines, 0L);
            lineLen = SendMessage(
                hOutWnd, EM_LINELENGTH, charPos, 0L);
            if(!lineLen)
                numLines--;
        }
        // Prevent negative value finding min.
        lineCount = numLines - firstVis;
        lineCount = (lineCount >= 0) ? lineCount : 0;
        
        // Scroll the window.
        lResult = SendMessage(
            hOutWnd, EM_LINESCROLL, 0, (LPARAM)lineCount);
    }
    // Done, make read-only and allow redraw.
    lResult = SendMessage(hOutWnd, WM_SETREDRAW, TRUE, 0L);
    lResult = SendMessage(hOutWnd, EM_SETREADONLY, TRUE, 0L);
} 
//
// ErrorHandler
//
void ErrorHandler(
   LPTSTR lpszFunction
) 
// Routine Description:
//     Support routine.
//     Retrieve the system error message for the last-error code
//     and pop a modal alert box with usable info.
// Parameters:
//     lpszFunction - String containing the function name where 
//     the error occurred plus any other relevant data you'd 
//     like to appear in the output.
// Return Value:
//     None
// Note:
//     This routine is independent of the other windowing routines
//     in this application and can be used in a regular console
//     application without modification.
{
    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError();
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );
    // Display the error message and exit the process.
    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
        (lstrlen((LPCTSTR)lpMsgBuf)
                  + lstrlen((LPCTSTR)lpszFunction)+40)
                  * sizeof(TCHAR)); 
    StringCchPrintf((LPTSTR)lpDisplayBuf, 
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("%s failed with error %d: %s"), 
        lpszFunction, dw, lpMsgBuf); 
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, g_pszAppName, MB_OK);
    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
}

 

上面的代码改编自 MSDN :http://msdn.microsoft.com/en-us/library/windows/desktop/aa363432(v=vs.85).aspx

运行结果

usbevent

此外,本文还参考了如下文章

http://blog.csdn.net/daoxwj/article/details/8819784
http://www.codeproject.com/Articles/14500/Detecting-Hardware-Insertion-and-or-Removal

下载
vcusb

获得当前系统增加/移除USB设备名称的方法 Delphi (1)

根据 http://delphi.cjcsoft.net/viewthread.php?tid=48860 文章内容,将类似 \\?\USB#Vid_4146&Pid_d2b5#0005050400044#{a5dcbf10-6530-11d2-901f-00c04fb951ed} 转化为更易读的类型,例如

USB Inserted
Device Type = USB Mass Storage Device
Driver Name = Disk drive
Friendly Name = I0MEGA UMni1GB*IOM2J4 USB Device

之前《关于监视插入U盘的问题(1)》中给出了接收 WM_DEVICECHANGE 消息的方法。从资料中可以看出,直接处理这个消息能够获得当前系统发生变化的盘符,但是无法处理未产生盘符变化(未分区或者其他USB设备)。对于这样的问题,可以使用RegisterDeviceNotification来向系统注册一个回调函数,并且设置好只通知USB设备变化,通过这样的方法能够取得发生变化的USB设备的信息,之后再通过查询注册表对照出更易读的信息。

文章还指出这样的转换是通过读取注册表来完成的。

我编写了如下例子,实践证明这个程序工作很好。除了普通的U盘,我还地尝试了一个 USB2UART 的 Cable,可以看出工作正常。

测试环境为 Win7+Delphi10,不需要管理员权限运行程序即可。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,MahUSB;

type
  TForm1 = class(TForm)
    procedure FormShow(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
     { Private declarations }
     FUsb : TUsbClass;
     procedure UsbIN(ASender : TObject; const ADevType,ADriverName,
                     AFriendlyName : string);
     procedure UsbOUT(ASender : TObject; const ADevType,ADriverName,
                     AFriendlyName : string);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
   FreeAndNil(FUsb);
end;

procedure TForm1.FormShow(Sender: TObject);
begin
   FUsb := TUsbClass.Create;
   FUsb.OnUsbInsertion := UsbIN;
   FUsb.OnUsbRemoval := UsbOUT;
end;

procedure TForm1.UsbIN(ASender : TObject; const ADevType,ADriverName,
                       AFriendlyName : string);
begin
  showmessage('USB Inserted - Device Type = ' + ADevType + #13#10 +
              'Driver Name = ' + ADriverName + #13+#10 +
              'Friendly Name = ' + AFriendlyName);
end;

procedure TForm1.UsbOUT(ASender : TObject; const ADevType,ADriverName,
                         AFriendlyName : string);
begin
  showmessage('USB Removed - Device Type = ' + ADevType + #13#10 +
               'Driver Name = ' + ADriverName + #13+#10 +
               'Friendly Name = ' + AFriendlyName);
end;

end.

============================================================================================

unit MahUSB;
interface
uses Windows, Messages, SysUtils, Classes, Registry, Masks;

type
  { Event Types }
  TOnUsbChangeEvent = procedure(AObject : TObject;
                                const ADevType,ADriverName,
                                      AFriendlyName : string) of object;

  { USB Class }
  TUsbClass = class(TObject)
  private
    FHandle : HWND;
    FOnUsbRemoval,
    FOnUsbInsertion : TOnUsbChangeEvent;
    procedure GetUsbInfo(const ADeviceString : string;
                         out ADevType,ADriverDesc,
                            AFriendlyName : string);
    procedure WinMethod(var AMessage : TMessage);
    procedure RegisterUsbHandler;
    procedure WMDeviceChange(var AMessage : TMessage);
  public
    constructor Create;
    destructor Destroy; override;
    property OnUsbInsertion : TOnUsbChangeEvent read FOnUsbInsertion
                                           write FOnUsbInsertion;
    property OnUsbRemoval : TOnUsbChangeEvent read FOnUsbRemoval
                                         write FOnUsbRemoval;
  end;

// -----------------------------------------------------------------------------
implementation

type
  // Win API Definitions
  PDevBroadcastDeviceInterface  = ^DEV_BROADCAST_DEVICEINTERFACE;
  DEV_BROADCAST_DEVICEINTERFACE = record
    dbcc_size : DWORD;
    dbcc_devicetype : DWORD;
    dbcc_reserved : DWORD;
    dbcc_classguid : TGUID;
    dbcc_name : char;
  end;

const
  // Miscellaneous
  GUID_DEVINTF_USB_DEVICE : TGUID = '{A5DCBF10-6530-11D2-901F-00C04FB951ED}';
  USB_INTERFACE                = $00000005; // Device interface class
  USB_INSERTION                = $8000;     // System detected a new device
  USB_REMOVAL                  = $8004;     // Device is gone

  // Registry Keys
  USBKEY  = 'SYSTEM\CurrentControlSet\Enum\USB\%s\%s';
  USBSTORKEY = 'SYSTEM\CurrentControlSet\Enum\USBSTOR';
  SUBKEY1  = USBSTORKEY + '\%s';
  SUBKEY2  = SUBKEY1 + '\%s';

constructor TUsbClass.Create;
begin
  inherited Create;
  FHandle := AllocateHWnd(WinMethod);
  RegisterUsbHandler;
end;

destructor TUsbClass.Destroy;
begin
  DeallocateHWnd(FHandle);
  inherited Destroy;
end;

procedure TUsbClass.GetUsbInfo(const ADeviceString : string;
                               out ADevType,ADriverDesc,
                                   AFriendlyName : string);
var sWork,sKey1,sKey2 : string;
    oKeys,oSubKeys : TStringList;
    oReg : TRegistry;
    i,ii : integer;
    bFound : boolean;
begin
  ADevType := '';
  ADriverDesc := '';
  AFriendlyName := '';

  if ADeviceString<>'' then begin
    bFound := false;
    oReg := TRegistry.Create;
    oReg.RootKey := HKEY_LOCAL_MACHINE;

    // Extract the portions of the string we need for registry. eg.
    // \\?\USB#Vid_4146&Pid_d2b5#0005050400044#{a5dcbf10- ..... -54334fb951ed}
    // We need sKey1='Vid_4146&Pid_d2b5' and sKey2='0005050400044'
    sWork := copy(ADeviceString,pos('#',ADeviceString) + 1,1026);
    sKey1 := copy(sWork,1,pos('#',sWork) - 1);
    sWork := copy(sWork,pos('#',sWork) + 1,1026);
    sKey2 := copy(sWork,1,pos('#',sWork) - 1);

    // Get the Device type description from \USB key
    if oReg.OpenKeyReadOnly(Format(USBKEY,[skey1,sKey2])) then begin
      ADevType := oReg.ReadString('DeviceDesc');
      oReg.CloseKey;
      oKeys := TStringList.Create;
      oSubKeys := TStringList.Create;

      // Get list of keys in \USBSTOR and enumerate each key
      // for a key that matches our sKey2='0005050400044'
      // NOTE : The entry we are looking for normally has '&0'
      // appended to it eg. '0005050400044&0'
      if oReg.OpenKeyReadOnly(USBSTORKEY) then begin
        oReg.GetKeyNames(oKeys);
        oReg.CloseKey;

        // Iterate through list to find our sKey2
        for i := 0 to oKeys.Count - 1 do begin
          if oReg.OpenKeyReadOnly(Format(SUBKEY1,[oKeys[i]])) then begin
            oReg.GetKeyNames(oSubKeys);
            oReg.CloseKey;

            for ii := 0 to oSubKeys.Count - 1 do begin
              if MatchesMask(oSubKeys[ii],sKey2 + '*') then begin
                // Got a match?, get the actual desc and friendly name
                if oReg.OpenKeyReadOnly(Format(SUBKEY2,[oKeys[i],
                                        oSubKeys[ii]])) then begin
                  ADriverDesc := oReg.ReadString('DeviceDesc');
                  AFriendlyName := oReg.ReadString('FriendlyName');
                  oReg.CloseKey;
                end;

                bFound := true;
              end;
            end;
          end;

          if bFound then break;
        end;
      end;

      FreeAndNil(oKeys);
      FreeAndNil(oSubKeys);
    end;

    FreeAndNil(oReg);
  end;
end;

procedure TUsbClass.WMDeviceChange(var AMessage : TMessage);
var iDevType : integer;
    sDevString,sDevType,
    sDriverName,sFriendlyName : string;
    pData : PDevBroadcastDeviceInterface;
begin
  if (AMessage.wParam = USB_INSERTION) or
     (AMessage.wParam = USB_REMOVAL) then begin
    pData := PDevBroadcastDeviceInterface(AMessage.LParam);
    iDevType := pData^.dbcc_devicetype;

    // Is it a USB Interface Device ?
    if iDevType = USB_INTERFACE then begin
      sDevString := PChar(@pData^.dbcc_name);
      GetUsbInfo(sDevString,sDevType,sDriverName,sFriendlyName);

      // Trigger Events if assigned
      if (AMessage.wParam = USB_INSERTION) and
        Assigned(FOnUsbInsertion) then
          FOnUsbInsertion(self,sDevType,sDriverName,sFriendlyName);
      if (AMessage.wParam = USB_REMOVAL) and
        Assigned(FOnUsbRemoval) then
          FOnUsbRemoval(self,sDevType,sDriverName,sFriendlyName);
    end;
  end;
end;

procedure TUsbClass.WinMethod(var AMessage : TMessage);
begin
  if (AMessage.Msg = WM_DEVICECHANGE) then
    WMDeviceChange(AMessage)
  else
    AMessage.Result := DefWindowProc(FHandle,AMessage.Msg,
                                     AMessage.wParam,AMessage.lParam);
end;

procedure TUsbClass.RegisterUsbHandler;
var rDbi : DEV_BROADCAST_DEVICEINTERFACE;
    iSize : integer;
begin
  iSize := SizeOf(DEV_BROADCAST_DEVICEINTERFACE);
  ZeroMemory(@rDbi,iSize);
  rDbi.dbcc_size := iSize;
  rDbi.dbcc_devicetype := USB_INTERFACE;
  rDbi.dbcc_reserved := 0;
  rDbi.dbcc_classguid  := GUID_DEVINTF_USB_DEVICE;
  rDbi.dbcc_name := #0;
  RegisterDeviceNotification(FHandle,@rDbi,DEVICE_NOTIFY_WINDOW_HANDLE);
end;

end.

detecusb

DetectUSB1

在Console中使用Timer (2)

之前的一篇文章展示了如何在Console中使用Timer,他使用的是CallBack方式进行回调的。这里演示直接处理 WM_TIMER 的方法,代码如下

#include “stdafx.h”
#include
#include
#include

int count =0;

VOID ShowTimer()
{
count++;
printf(“WM_TIMER in work thread count=%d\n”,count);
}

DWORD CALLBACK Thread(PVOID pvoid)
{
MSG msg;

UINT timerid=SetTimer(NULL,111,3000,NULL);
BOOL bRet;

PeekMessage(&msg,NULL,WM_USER,WM_USER,PM_NOREMOVE);
while((bRet = GetMessage(&msg,NULL,0,0))!= 0)
{
if(bRet==-1)
{
// handle the error and possibly exit
}
else
{
if (msg.message == WM_TIMER) { ShowTimer(); }
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
KillTimer(NULL,timerid);
printf(“thread end here\n”);
return 0;
}

int main()
{
DWORD dwThreadId;
printf(“Use timer in workthread of console application\n”);
HANDLE hThread = CreateThread(NULL,0,Thread,0,0,&dwThreadId);
_getch();
return 0;
}

运行结果和之前的相同。

代码和EXE在这里下载

contimer2

另外,还有如下的一个例子,来自 http://read.pudn.com/downloads121/sourcecode/windows/console/512780/1ms/1ms.cpp__.htm

//************************************************************************************
//本程序使用了两种实现定时的方法,都是基于API的,而不是MFC
//
// 1. 是使用线程定时休眠的方法,启动线程ThreadProc,在线程中输出,然后Sleep 1000ms
//
// 2. 使用定时器方法,设置一个1000ms的定时器(SetTimer),然后捕捉该消息,然后调用回调函数
// TimerProc,在该函数中输出DEF,注意,SetTimer可以直接写回调函数地址,不必捕捉消息。
// 3. 本例子已经很详细了。
// 4. 祝你好运。
//
//************************************************************************************

#include “stdafx.h”
#include

DWORD WINAPI ThreadProc( LPVOID lpParameter )//方法1
{
static DWORD tick=0;
DWORD tmp = GetTickCount();
while(1)
{
tick = GetTickCount()-tmp;//获得系统从启动开始到现在的ms数
tmp = GetTickCount();
printf(“THREAD_PROC: abc %d, tickcount: %d\n”,tick,tmp);//打印abc和上次打印到这次打印之间的毫秒间隔。
Sleep(1000);//每隔1000ms打印abc
}
}
VOID TimerProc()//方法2
{
static DWORD tick=0;
static DWORD tmp = GetTickCount();

tick = GetTickCount()-tmp;
tmp = GetTickCount();
printf(” TimerProc________________def %d\n”,tick);

}

int main()
{
DWORD dwthread;
::CreateThread(NULL,0,ThreadProc,(LPVOID)0,1024,&dwthread);//生成一个线程,在该线程里每1000ms输出一个”abc”,然后SLEEP
SetTimer(0,0,1000,0);//设置一个定时器,定时器的回调函数为0,仅产生定时器消息,在main函数里捕捉该消息
MSG msg;
bool flag;

while(1)//该循环捕捉定时器消息,并且防止main函数退出
{
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
while( (flag = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (flag == -1)
{
// handle the error and possibly exit
}
else if(msg.message==WM_TIMER)
{
TimerProc();//如果是定时器消息,调用timerproc

}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}

}

关于监视插入U盘的问题(1)

本文是参考 http://bbs.csdn.net/topics/390293365?page=1#post-393016986 完成的。

修改了其中的Demo,使得程序能够在 VS2008 Express 下编译成功。

修改后的代码如下,删除了读取识别出来盘符上指定文件的代码

//编程识别u盘的插入,通过处理WM_DEVICECHANGE的消息,来达到识别的效果
//vc下编译通过,能够识别
#include “stdafx.h”
#include
#include
#include
#include

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
TCHAR FirstDriveFromMask (ULONG unitmask);

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPreInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
//windows窗口类的成员
TCHAR szClassName[] = TEXT(“MainWClass”);
WNDCLASSEX wndclass;
wndclass.cbSize = sizeof(wndclass);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = ::LoadIcon(NULL,IDI_APPLICATION);
wndclass.hCursor = ::LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szClassName;
wndclass.hIconSm = NULL;

::RegisterClassEx(&wndclass);

HWND hwnd = ::CreateWindowEx(
0,
szClassName,
TEXT(“mc”),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
UINT Cret = GetLastError();
//printf(“%d\n”,GetLastError());
if (hwnd == NULL)
{
::MessageBox(NULL,TEXT(“Create Window error!”),TEXT(“error”),MB_OK);
return -1;
}
::ShowWindow(hwnd,nCmdShow);
::UpdateWindow(hwnd);
MSG msg;
while (::GetMessage(&msg,NULL,0,0))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}

return msg.wParam;
}
//回调函数处理消息
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:/*初始化*/
MessageBox(hwnd, TEXT(“go!”), TEXT(“405 Studio”), MB_OK);
break;
case WM_DEVICECHANGE:
if(wParam == DBT_DEVICEARRIVAL) //设备激活
{
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
TCHAR szMsg[80],Disk;
Disk = FirstDriveFromMask(lpdbv ->dbcv_unitmask);
wsprintf (szMsg,TEXT(“Drive %c: Media has arrived./n”),Disk);
MessageBox (hwnd, szMsg, TEXT(“WM_DEVICECHANGE”), MB_OK);
//Sleep(1000);
::PostQuitMessage(0);

}
break;
default:
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
return 0;
}
//提取u盘的盘符
TCHAR FirstDriveFromMask (ULONG unitmask)
{
char i;
for (i = 0; i < 26; ++i) { if (unitmask & 0x1) break; unitmask = unitmask >> 1;
}
return (i + ‘A’);
}

首先运行本程序,然后插入U盘,可以看出识别出来插入U盘的盘符,另外弹出来的是Windows自动播放的对话框。运行结果如下:

wusb

源程序和编译后的EXE可以从下面下载

watchusb