0

I am creating a win32 C++ app in which pressing the "Eject" button opens the CD Rom Tray and pressing the "Close" button closes the CD Rom Tray. The "Eject" button works and the tray opens, however, pressing the "Close" button does not close the CD Rom Tray. I want it to find the CD Rom drive (whatever that might be from computer to computer) and close the tray. I am using "DeviceIoControl" and "IOCTL_STORAGE_LOAD_MEDIA". The "Eject" button part of my code is shown below (only the relevant parts of the code):

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#include <stdio.h>

#define IDC_BUTTON                  3456
#define BUF_SIZE                     512

WCHAR buf[BUF_SIZE];
LPWSTR pBuf = buf;
DWORD chrCopied = GetLogicalDriveStrings(BUF_SIZE - 1, buf);

TCHAR DRIVE[200];

DWORD dwBytes;
HANDLE hCdRom;


LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
    {
        while (chrCopied)
        {
            if (DRIVE_CDROM == GetDriveType(pBuf))
            {
                wsprintf(DRIVE, L"%c%c.%c%s", 0x5c, 0x5c, 0x5c, pBuf);  //  Displays drive name as: \\.\D:\ 
                size_t indexOfNull = _tcslen(DRIVE);
                DRIVE[indexOfNull - 1] = '\0';             // removes the last \ to make the file name \\.\D:
            }
            size_t len = _tcslen(buf);
            chrCopied -= len + 1;
            pBuf += len + 1;
        }

        HWND hwndButton = CreateWindow(
            L"BUTTON",  // Predefined class; Unicode assumed 
            L"EJECT",   // Button text 
            WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles 
            150,         // x position 
            200,        // y position 
            100,        // Button width
            100,        // Button height
            hWnd,     // Parent window
            (HMENU)IDC_BUTTON,       // No menu.
            (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
            NULL);      // Pointer not needed.

        HWND hwndButton_Close = CreateWindow(
                L"BUTTON",  // Predefined class; Unicode assumed 
                L"CLOSE",   // Button text 
                WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles 
                263,         // x position 
                200,        // y position 
                100,        // Button width
                100,        // Button height
                hWnd,     // Parent window
                (HMENU)IDC_BUTTON_CLOSE,       // No menu.
                (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
                NULL);      // Pointer not needed.

    }

    case WM_COMMAND:
    {
        switch (LOWORD(wParam))
        {
        case IDC_BUTTON:

            hCdRom = CreateFile(DRIVE,
                GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

            if (hCdRom == INVALID_HANDLE_VALUE)
            {
                _tprintf(_T("Error: %x"), GetLastError());
                return 1;
            }

            DeviceIoControl(hCdRom, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwBytes, NULL);
            if (hCdRom == 0)
            {
                _tprintf(_T("Error: %x"), GetLastError());
                return 1;
            }
            MessageBox(NULL, L"Please insert a CD ROM in the CD tray.", L"CD ROM Drive", 0);

            CloseHandle(hCdRom);

            break;

        case IDC_BUTTON_CLOSE:

            hCdRom = CreateFile(DRIVE,
                GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

            if (hCdRom == INVALID_HANDLE_VALUE)
            {
                _tprintf(_T("Error: %x"), GetLastError());
                return 1;
            }

            //Close CD Rom Tray
            DeviceIoControl(hCdRom, IOCTL_STORAGE_LOAD_MEDIA, NULL, 0, NULL, 0, &dwBytes_close, NULL);

            if (hCdRom == 0)
            {
                _tprintf(_T("Error: %x"), GetLastError());
                return 1;
            }

            CloseHandle(hCdRom);

            break;
        }
    }
}
Sophia
  • 57
  • 1
  • 9
  • "*The "Eject" button part of my code is shown below*" - you showed the code that tries to close the tray, not the code that ejects the tray. Where is that code? Your close code is manipulating the `chrCopied_close` and `pBuf_close` variables, does your eject code do the same thing? You are not resetting those variables at the beginning of the close code, so if you eject first then try to close, you may be passing a bad device path to `CreateFile()`, which you are not checking for. – Remy Lebeau Jan 05 '21 at 18:52
  • The "Eject" button part of the code does not use the chrCopied_close and pBuf_close variables. These are new variables that I created just for the "Close" button part of the code. – Sophia Jan 05 '21 at 18:54
  • 1
    Even if that is true, you still have the bug I mentioned, that you are not resetting the variables on each close, so you would only be able to close the tray 1 time at most, and then you would have to restart your app before you could close the tray again. Rather than compute the drive path on each eject/close operation, I would suggest computing the device path 1 time at program startup, and then use it as-is for each operation. In any case, your code is not doing any error handling. Are `CreateFile()` or `DeviceIoControl()` reporting any errors when the tray fails to close? – Remy Lebeau Jan 05 '21 at 18:58
  • @Remy Lebeau I've updated my code to compute the device path 1 time at program startup, as you suggested. I've also added error handing within the buttons. If the device path is being computed one time, the variables would be reset, wouldn't they? The CD Rom drive is still not closing for me though. – Sophia Jan 05 '21 at 20:16
  • "*I've updated my code to compute the device path 1 time at program startup*" - you don't need 2 separate variables for the same device path. Compute 1 path, and reuse it for BOTH operations. But you should have moved that compute into the `WM_CREATE` handler, or even into `WinMain()`. Doing it at the top of `WndProc` is not right. "*I've also added error handing*" - you did so only for `CreateFile()`, but not for `DeviceIoControl()`. "*If the device path is being computed one time, the variables would be reset, wouldn't they?*" - no. – Remy Lebeau Jan 05 '21 at 20:39
  • @RemyLebeau I've updated my code again - took out the 2 separate variables for the device path and reused 1 for both operations. I've also moved the device path compute to the WM_CREATE handler. Also added error handling for the DeviceIoControl() - I'm not sure if I did that part correctly. Also, how would I reset the variables on each close like you suggested? The CD Rom tray is still not closing. – Sophia Jan 05 '21 at 21:01
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/226895/discussion-between-remy-lebeau-and-sophia). – Remy Lebeau Jan 05 '21 at 21:02
  • Does your CD Rom Tray support auto close? As far as I know, many desktop computer's CD Rom Trays don't support this operation and can only eject automatically. – Strive Sun Jan 06 '21 at 12:41
  • @StriveSun-MSFT It is a portable external CD Rom Drive - is there a way I can check if it supports the close operation? – Sophia Jan 06 '21 at 18:24
  • There may not be a programming way to determine whether to support automatic close, maybe contacting the manufacturer is another quick way. – Strive Sun Jan 07 '21 at 06:10
  • @StriveSun-MSFT Okay, thank you! – Sophia Jan 07 '21 at 06:11
  • The CD tray will have its own eject/close button. Press it once and the tray will eject, and press it again to close the tray. If the tray will not be closed, the tray may not support automatic closing. – Strive Sun Jan 07 '21 at 06:18

0 Answers0