winapi - 我正在尝试使用 DeviceIoControl IOCTL_STORAGE_EJECT_MEDIA 弹出我的 CD ROM 驱动器,但出现错误访问冲突写入位置
问题描述
我试图通过单击按钮弹出我的 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;
}
}
}
有没有人遇到过这个错误并知道如何解决它?
解决方案
因为MessageBox
一直处于阻塞状态,CloseHandle
是不会调用的。当您第二次按下该按钮时,CreateFile
将再次打开光驱手柄,之前的手柄尚未关闭,访问被拒绝。
您可以简单地删除此行:
MessageBox(NULL, L"Please insert a CD ROM in the CD tray.", L"CD ROM Drive", 0);
但正确的方法是添加确保所有消息都得到处理的DefWindowProcA函数。
调用默认窗口过程为应用程序未处理的任何窗口消息提供默认处理。此功能可确保处理每条消息。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;
}
推荐阅读
- xcode - XCode 在克隆的 git repo 中看不到项目中的文件
- wpf - WPF TreeView 仅扩展根
- python - 我试图在这个 python 程序中使用递归,但它显示 NameError。我应该怎么办?
- linux - 如何使用 printk()?
- python - 如何在 Python 3 中将 --prefer-binary 与 pip 一起使用?
- php - PHP正则表达式问题符号
- sql - 基于 MSSQL 或 LINQ 中的单列选择不常见的行
- javascript - 如何在 React 中绘制堆叠的时间序列?
- atomic - OpenACC:ATOMIC 指令的问题
- php - AWS Elastic Beanstalk + Laravel, Nginx Configuration