winapivisual-c++createfilecd-rom

I am trying to eject my CD Rom drive using DeviceIoControl IOCTL_STORAGE_EJECT_MEDIA but getting error access violation writing location


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?


Solution

  • 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;
    }