Winapi 我正试图使用DeviceIoControl IOCTL\u STORAGE\u eject\u介质弹出我的CD Rom驱动器,但获取错误访问冲突写入位置

Winapi 我正试图使用DeviceIoControl IOCTL\u STORAGE\u eject\u介质弹出我的CD Rom驱动器,但获取错误访问冲突写入位置,winapi,visual-c++,createfile,cd-rom,Winapi,Visual C++,Createfile,Cd Rom,我试图通过单击按钮弹出cd-Rom驱动器。当按下按钮时,CD-Rom驱动器以前正确弹出,但现在它给了我一个错误:“0xC0000005:访问冲突写入位置0x00000000”。我不确定为什么会出现此错误。我的代码如下所示,其中我的CD-Rom驱动器是D驱动器: #include <windows.h> #include <tchar.h> #include <stdio.h> #define BUTTON 3456 LRES

我试图通过单击按钮弹出cd-Rom驱动器。当按下按钮时,CD-Rom驱动器以前正确弹出,但现在它给了我一个错误:“0xC0000005:访问冲突写入位置0x00000000”。我不确定为什么会出现此错误。我的代码如下所示,其中我的CD-Rom驱动器是D驱动器:

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

#define BUTTON                  3456
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
DWORD dwBytes;
HANDLE hCdRom;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
    {
        HWND hwndButton = CreateWindow(
            L"BUTTON",  // Predefined class; Unicode assumed 
            L"EJECT",   // Button text 
            WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles 
            180,         // x position 
            200,        // y position 
            100,        // Button width
            100,        // Button height
            hWnd,     // Parent window
            (HMENU)BUTTON,       // No menu.
            (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
            NULL);      // Pointer not needed.
    }
    
    case WM_COMMAND:
    {
        switch (LOWORD(wParam))
        {
        case BUTTON:
            hCdRom = CreateFile(L"\\\\.\\D:",
                GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

            if (hCdRom == INVALID_HANDLE_VALUE)
            {
                wsprintf(NULL, L"Error: %d", GetLastError());    //Getting error: Exception thrown at 0x746FFA6F (user32.dll) in Project.exe: 0xC0000005: Access violation writing location 0x00000000.
                return 1;
            }

            DeviceIoControl(hCdRom, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwBytes, NULL);

            if (hCdRom == 0)
            {
                wsprintfW(NULL, L"Error: %d", GetLastError());
                return 1;
            }
            MessageBox(NULL, L"Please insert a CD ROM in the CD tray.", L"CD ROM Drive", 0);

            CloseHandle(hCdRom);
    
            break;
        }
    }
}
#包括
#包括
#包括
#定义按钮3456
LRESULT回调WndProc(HWND、UINT、WPARAM、LPARAM);
双字双字节;
处理hCdRom;
LRESULT回调WndProc(HWND HWND,UINT消息,WPARAM WPARAM,LPARAM LPARAM)
{
开关(信息)
{
案例WM_创建:
{
HWND hwndButton=创建窗口(
L“BUTTON”,//预定义类;假定为Unicode
L“弹出”,//按钮文本
WS|TABSTOP | WS|u VISIBLE | WS|u CHILD | BS|u def按钮,//样式
180,//x位置
200,//y位置
100,//按钮宽度
100,//按钮高度
hWnd,//父窗口
(HMENU)按钮,//无菜单。
(HINSTANCE)GetWindowLongPtr(hWnd,GWLP_HINSTANCE),
NULL);//不需要指针。
}
case WM_命令:
{
开关(LOWORD(wParam))
{
案例按钮:
hCdRom=CreateFile(L“\\.\\D:”,
泛型|读|泛型|写,0,空,打开|存在,0,空);
if(hCdRom==无效的句柄值)
{
wsprintf(NULL,L“错误:%d”,GetLastError());//获取错误:在Project.exe中的0x746FFA6F(user32.dll)处引发异常:0xC0000005:访问冲突写入位置0x00000000。
返回1;
}
设备控制(hCdRom、IOCTL存储、弹出介质、NULL、0、NULL、0和dwBytes、NULL);
如果(hCdRom==0)
{
wsprintfW(NULL,L“错误:%d”,GetLastError());
返回1;
}
MessageBox(空,L“请在CD托盘中插入CD-ROM”,L“CD-ROM驱动器”,0);
闭合手柄(hCdRom);
打破
}
}
}

是否有人遇到此错误并知道如何修复它?

因为
MessageBox
一直处于阻止状态,所以不会调用
CloseHandle
。当您第二次按下按钮时,
CreateFile
将再次打开CD-Rom驱动器句柄,之前的句柄尚未关闭,访问被拒绝

您只需删除此行:

MessageBox(空,L“请在CD托盘中插入CD-ROM”,L“CD-ROM驱动器”,0);

但正确的方法是添加确保处理所有消息的函数

调用默认窗口过程以为提供默认处理 应用程序未处理的任何窗口消息。此 函数可确保处理每条消息。DefWindowProc 使用窗口过程接收到的相同参数调用

这样修改,

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
    {
        HWND hwndButton = CreateWindow(
            L"BUTTON",  // Predefined class; Unicode assumed 
            L"EJECT",   // Button text 
            WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles 
            180,         // x position 
            200,        // y position 
            100,        // Button width
            100,        // Button height
            hWnd,     // Parent window
            (HMENU)BUTTON,       // No menu.
            (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
            NULL);      // Pointer not needed.
    }

    case WM_COMMAND:
    {
        switch (LOWORD(wParam))
        {
        case BUTTON:
            hCdRom = CreateFile(L"\\\\.\\D:",
                GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

            if (hCdRom == INVALID_HANDLE_VALUE)
            {
                wsprintf(NULL, L"Error: %d", GetLastError());    //Getting error: Exception thrown at 0x746FFA6F (user32.dll) in Project.exe: 0xC0000005: Access violation writing location 0x00000000.
                return 1;
            }

            DeviceIoControl(hCdRom, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwBytes, NULL);

            if (hCdRom == 0)
            {
                wsprintfW(NULL, L"Error: %d", GetLastError());
                return 1;
            }
            MessageBox(NULL, L"Please insert a CD ROM in the CD tray.", L"CD ROM Drive", 0);

            CloseHandle(hCdRom);

            break;
        }
    }
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
更新:

#include <tchar.h>
#include <windows.h>
#include <mmsystem.h> // for MCI functions

// Link to winmm.lib (usually included in project settings)
#pragma comment(lib, "winmm")

void ControlCdTray(TCHAR drive, DWORD command)
{
    // Not used here, only for debug
    MCIERROR mciError = 0;

    // Flags for MCI command
    DWORD mciFlags = MCI_WAIT | MCI_OPEN_SHAREABLE | 
        MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT;

    // Open drive device and get device ID
    TCHAR elementName[] = { drive };
    MCI_OPEN_PARMS mciOpenParms = { 0 };
    mciOpenParms.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO;
    mciOpenParms.lpstrElementName = elementName;    
    mciError = mciSendCommand(0, 
        MCI_OPEN, mciFlags, (DWORD_PTR)&mciOpenParms);

    // Eject or close tray using device ID
    MCI_SET_PARMS mciSetParms = { 0 };
    mciFlags = MCI_WAIT | command; // command is sent by caller
    mciError = mciSendCommand(mciOpenParms.wDeviceID, 
        MCI_SET, mciFlags, (DWORD_PTR)&mciSetParms);
    
    // Close device ID
    mciFlags = MCI_WAIT;
    MCI_GENERIC_PARMS mciGenericParms = { 0 };
    mciError = mciSendCommand(mciOpenParms.wDeviceID, 
        MCI_CLOSE, mciFlags, (DWORD_PTR)&mciGenericParms);
}

// Eject drive tray
void EjectCdTray(TCHAR drive)
{
    ControlCdTray(drive, MCI_SET_DOOR_OPEN);
}

// Retract drive tray
void CloseCdTray(TCHAR drive)
{
    ControlCdTray(drive, MCI_SET_DOOR_CLOSED);
}

int _tmain(int argc, _TCHAR* argv[])
{
    EjectCdTray(TEXT('D')); // drive letter hardcoded
    //CloseCdTray(TEXT('D'));

    return 0;
}
#包括
#包括
#包含//用于MCI函数
//链接到winmm.lib(通常包含在项目设置中)
#pragma注释(lib,“winmm”)
无效控制CD托盘(TCHAR驱动器,DWORD命令)
{
//此处不使用,仅用于调试
MCIERROR-MCIERROR=0;
//MCI命令的标志
DWORD mciFlags=MCI_等待| MCI_开放|可共享|
MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_OPEN_元素;
//打开驱动器设备并获取设备ID
TCHAR elementName[]={drive};
MCI_OPEN_PARMS mciOpenParms={0};
mciOpenParms.lpstrDeviceType=(LPCTSTR)MCI_DEVTYPE_CD_AUDIO;
mciOpenParms.lpstrElementName=elementName;
mciError=mciSendCommand(0,
MCI_公开赛、mciFlags(DWORD_PTR)和mciOpenParms);
//使用设备ID弹出或关闭托盘
MCI_SET_PARMS mciSetParms={0};
mciFlags=MCI_WAIT | command;//该命令由调用方发送
mciError=mciSendCommand(mciOpenParms.wDeviceID,
MCI_集、mciFlags(DWORD_PTR)和mciSetParms);
//关闭设备ID
mciFlags=MCI_WAIT;
MCI_GENERIC_PARMS mciGenericParms={0};
mciError=mciSendCommand(mciOpenParms.wDeviceID,
MCI_CLOSE、mciFlags(DWORD_PTR)和mciGenericParms);
}
//弹出驱动器托盘
无效弹出CD托盘(TCHAR驱动器)
{
控制托盘(驱动器、MCI设置、门打开);
}
//收回驱动器托盘
无效关闭CD托盘(TCHAR驱动器)
{
控制托盘(驱动器、MCI设置、门关闭);
}
int _tmain(int argc,_TCHAR*argv[]
{
弹出CD托盘(文本('D');//硬编码的驱动器号
//关闭CD托盘(文本('D'));
返回0;
}

我的代码中有“default:return DefWindowProc(hWnd,message,wParam,lParam);”我没有在线包含它。我按照您的建议删除了“MessageBox(NULL,L“请在CD托盘中插入CD-ROM.”,L“CD-ROM驱动器”,0);,但它仍然没有弹出。@Alyssa还需要修改:
CreateFile(L“\\\\\\\。\\D:”,
…我也有,在线键入时忘记了引号。@Alyssa第一次按下按钮时CD-ROM会弹出吗?我将函数放在开头,这对我很有效。非常感谢!