I am trying to eject my cd Rom drive by clicking a button. When the button is pressed, the CD Rom drive was ejecting correctly before but now it is giving me an error: "0xC0000005: Access violation writing location 0x00000000." I'm not sure why I am getting this error. My code is shown below, where my CD Rom drive is the D-drive:
#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;
}
}
}
Has anyone come across this error and know how to fix it?
Because MessageBox
has been in a blocking state, CloseHandle
is not called. When you press the button for the second time, CreateFile
will open the CD Rom drive handle again, the previous handle has not been closed, and access is denied.
You can simply delete this line:
MessageBox(NULL, L"Please insert a CD ROM in the CD tray.", L"CD ROM Drive", 0);
But the correct way is to add the DefWindowProcA function which ensures that all messages are processed.
Calls the default window procedure to provide default processing for any window messages that an application does not process. This function ensures that every message is processed. DefWindowProc is called with the same parameters received by the window procedure.
Modify like this,
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;
}
Updated:
#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;
}