0

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?

Alyssa
  • 5
  • 3

1 Answers1

1

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;
}
Strive Sun
  • 5,988
  • 1
  • 9
  • 26
  • I have the 'default: return DefWindowProc(hWnd, message, wParam, lParam);' in my code, I didn't include it online. I deleted the 'MessageBox(NULL, L"Please insert a CD ROM in the CD tray.", L"CD ROM Drive", 0);' like you suggested but it is still not ejecting. – Alyssa Jan 14 '21 at 05:48
  • @Alyssa Here is also needed to modify: `CreateFile(L"\\\\.\\D:",` ... – Strive Sun Jan 14 '21 at 05:51
  • I have that also, forgot the quotes when typing it online. – Alyssa Jan 14 '21 at 05:52
  • @Alyssa Will the CD ROM eject the first time the button is pressed? – Strive Sun Jan 14 '21 at 05:55
  • When I hover over 'HANDLE hCdRom', it says it is 0xffffffff. Does that mean it is full and is not closing properly? How do ensure that 'CloseHandle(hCdRom);' works correctly? – Alyssa Jan 14 '21 at 06:01
  • No, it is not ejecting at all but it was before and then for some reason it stopped, which is making me wonder if maybe the hCdRom HANDLE is full. I'm not sure how to clear it. I thought 'CloseHandle(hCdRom);' was clearing it but maybe that is not working. – Alyssa Jan 14 '21 at 06:03
  • @Alyssa It seems that the CD ROM handle has been occupied by a certain process, so your program cannot get the CD ROM handle. – Strive Sun Jan 14 '21 at 06:06
  • I'm not sure I understand what that means. Is there a way I can undo that? – Alyssa Jan 14 '21 at 06:11
  • @Alyssa Two questions, can the CD be ejected manually? Is this still the case after the computer restarts? – Strive Sun Jan 14 '21 at 06:15
  • Yes, the CD Rom drives opens manually when I click on the button on the tray, and also if I open up Windows Explorer, right-click on the CD-ROM folder and press "Eject". – Alyssa Jan 14 '21 at 06:23
  • @Alyssa Try another function, use `mciSendCommand` to send a command message to the CD Rom. See my updated. – Strive Sun Jan 14 '21 at 06:30
  • I placed the 'void ControlCdTray(TCHAR drive, DWORD command)', 'void EjectCdTray(TCHAR drive)', and 'void CloseCdTray(TCHAR drive)' at the very end of my code and 'EjectCdTray(TEXT('D'));' inside the button that I press to eject the tray, but I'm getting the error: "EjectCdTray': identifier not found. – Alyssa Jan 14 '21 at 06:36
  • 1
    I placed the functions at the beginning and this worked for me. Thank you so much! – Alyssa Jan 14 '21 at 06:39
  • If I have the drive letter saved in a TCHAR and pull it in so that the computer can search for the drive and then open it, can I do that? I'm trying to pull in a TCHAR variable but it says 'argument of "TCHAR*" is incompatible with parameter of type "TCHAR". – Alyssa Jan 14 '21 at 07:00
  • For instance, what if the CD Rom drive is something other than the D-Drive and you find what drive it is, and then save it in a TCHAR variable? This is not letting me place a variable in the 'EjectCdTray()' function. – Alyssa Jan 14 '21 at 07:42
  • @Alyssa Do you mean `TCHAR driver_letter = 'D'; EjectCdTray(driver_letter); `? – Strive Sun Jan 14 '21 at 07:44
  • Yes, exactly like that. It is not working for me. – Alyssa Jan 14 '21 at 07:53
  • Actually looks like it's a TCHAR*. – Alyssa Jan 14 '21 at 07:54
  • @Alyssa For Unicode platforms, TCHAR is defined as synonymous with the WCHAR type. For ANSI and DBCS platforms, TCHAR is defined as CHAR. You don't need to use TCHAR*, use TCHAR instead. And pass its pointer to new function, like: new_function(&driver_letter ). – Strive Sun Jan 14 '21 at 07:59
  • It is saying that driver_letter is a TCHAR but it gives me the error 'argument of "TCHAR*" is incompatible with parameter of type "TCHAR"'. I tried doing EjectCdTray(&driver_letter) also but that is not working. – Alyssa Jan 14 '21 at 08:05
  • @Alyssa Please add your question code or post a new question to ask. – Strive Sun Jan 14 '21 at 08:07
  • I'm not sure I understand what you mean by "pass its pointer to new function". Why does 'EjectCdTray(driver_letter)' not work? – Alyssa Jan 14 '21 at 08:07
  • I have posted it here: https://stackoverflow.com/questions/65715553/ejecting-cdrom-drive-without-hardcoding-drive-letter-using-win32-visual-c Any help would be greatly appreciated. – Alyssa Jan 14 '21 at 08:21