#winapi #visual-c #createfile #cd-rom
#winapi #visual-c #создать файл #cd-rom
Вопрос:
Я пытаюсь извлечь свой дисковод cd Rom, нажав кнопку. При нажатии кнопки привод CD-Rom раньше извлекался правильно, но теперь он выдает ошибку: «0xC0000005: место записи 0x00000000 с нарушением доступа». Я не уверен, почему я получаю эту ошибку. Мой код показан ниже, где мой дисковод CD-Rom является общим дисководом:
#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, amp;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;
}
}
}
Кто-нибудь сталкивался с этой ошибкой и знает, как ее исправить?
Ответ №1:
Поскольку MessageBox
он находится в состоянии блокировки, CloseHandle
не вызывается. Когда вы нажмете кнопку во второй раз, CreateFile
снова откроется дескриптор привода CD Rom, предыдущий дескриптор не был закрыт, и доступ запрещен.
Вы можете просто удалить эту строку:
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, amp;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)amp;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)amp;mciSetParms);
// Close device ID
mciFlags = MCI_WAIT;
MCI_GENERIC_PARMS mciGenericParms = { 0 };
mciError = mciSendCommand(mciOpenParms.wDeviceID,
MCI_CLOSE, mciFlags, (DWORD_PTR)amp;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;
}
Комментарии:
1. У меня есть ‘default: return DefWindowProc (hWnd, message, wParam, lParam);’ в моем коде, я не включил его в онлайн. Я удалил ‘MessageBox (NULL, L»Пожалуйста, вставьте компакт-диск в лоток для компакт-дисков.», L»Привод компакт-дисков», 0);’ как вы и предлагали, но он все еще не извлекается.
2. @Alyssa Здесь также необходимо изменить:
CreateFile(L"\\.\D:",
…3. У меня это тоже есть, забыл кавычки при вводе его в Интернете.
4. @Alyssa будет ли компакт-диск извлечен при первом нажатии кнопки?
5. Я разместил функции в начале, и это сработало для меня. Большое вам спасибо!