RonalBertogi 46 Junior Poster in Training

You can't do that in C++. Microsoft Office Applications do not use the ordinary menu we see in other windows-based program.

RonalBertogi 46 Junior Poster in Training

You declared you array wrong.

char array[5][2] = { "blueone", "greentwo", "redthree", "pinkfour", "yellowfive" };

This declaration says that there are 5 elements that themselves are arrays consisting 2 elements.

You can declare them like this:

char (asterisk character) array[] = { "blueone", "greentwo", "redthree", "pinkfour", "yellowfive" };

NOTE: I can't type a literal asterisk here. It is being interpreted as the italic formatting code.

RonalBertogi 46 Junior Poster in Training

Review the instructions to your assignment. Sometimes are error is not the coding itself but the failure to follow instructions.

Like this:

...data in the file. Your input and output file names will be supplied to your program on the command line, which you will access using argc and argv[]

...but in line 23 you asked the user to enter the input file.

Of course, there are still other errors in your code (like line 20(?)) but review--and understand well--your instruction and rewrite your code and try to compile and run it so that you yourself can see the problem. It is the compiler's task to inform us the errors (except of course logical errors) and it is our task to fix them. If your compiler tells about errors, try to understand them first and fix them yourself until you prove to yourself you need the others' help. That way, I suppose, you will learn programming systematically.

RonalBertogi 46 Junior Poster in Training
Dim rs As Recordset, nextId As Long
Set rs = con.Execute("SELECT Max(emp_id) As LastID FROM theTable")
nextId = 1
If rs.RecordCount <> 0 Then
    nextId = rs!LastID
End If
nextId = nextId + 1
RonalBertogi 46 Junior Poster in Training

i read somewhere that the string constats are available through the whole runtime of the application as they are embded in the executable itself and the compiler just calls the address location, thus not going out of scope, but maybe i didn't understand corectly.

Yes, that is, if you are certain that you will be supplying constant strings to those functions.

One more thing...

Msg_Len = strlen(_Message);
m_Msg = new char[Msg_Len];
strcpy(m_Msg, _Message);
To_Len = strlen(_To);
m_To = new char[To_Len];
strcpy(m_To, _To);
From_Len = strlen(_From);
m_From = new char[From_Len];
strcpy(m_From, _From);

...do you think that solves your problem of heap corruption? My answer is a NO. Why? Because your memory allocation was based on the return value of strlen which do not include the EOS marker. Value must be strlen() + 1.

RonalBertogi 46 Junior Poster in Training

First of all, I did not see any variable declared with an identifier To and From. But I suppose the main error in this class is your declaration if these variables: m_To, m_From and m_Msg. They are all pointers. And the fact that they are pointers, you should not call the delete operator on them unless you have initialized them with the new operator.

Let's look at the mutators of these variables. Since they are all in the same code pattern, we will just look particularly at the SetMessage function specifically on line 43.

On Line 43 you assigned the value of the actual parameter called value to m_Msg data of your class using the assignment operator--WITHOUT allocating an appropriate amount of memory for m_Msg to accomodate the length of the value. In some few (and rare) cases this can be ok. But the problem is if the memory pointed to in the formal parameter value is a non-static memory where it will automatically be freed when the function where the SetMessage was called from exits.

Example:

void InitializeChat(CMsgPacket * pMsgPacket)
{
    char msg[] = "A message"; // This is a temp variable that will be
                              // destroyed when the function exits.
    pMsgPacket.SetMessage(msg);
}

void main()
{
    CMsgPacket msg;
    InitializeChat(&msg);
}

pMsgPacket.SetMessage() was called with a temporary variable as its argument that will be assigned to the m_Msg data of the CMsgPacket class. When InitializeChat exits, the value assigned to the m_Msg will no longer be valid.

I …

mike_2000_17 commented: Nice! +14
RonalBertogi 46 Junior Poster in Training

You are correct, @BitBlt. I just answered the problem posted.

About checking if a particular file exists, the usual trick is to attempt to open a file for sequential input (in C/C++/VB) and in C: check for the file number returned if it indicates a valid file number or an error code; in C++/Win32 File IO: check if the returned handle is valid; and, in VB, use its structured error handling mechanism (On Error goto...) that uses the IErrorInfo interface. This method will not just allow you to check for a file's existence but also IO privileges or file read/write access.

BTW, the fastest way to check if a file exists is to use the master file allocation table and that's another story.

RonalBertogi 46 Junior Poster in Training

If your goal is to read the file line by line without the carriage return and line feed (CRLF), you can do so without allocating large amount of memory. And, I still opt the method you choose than using another object for that purpose.

Dim strBuffer As String

Close #1 ' To make sure that 1 is available

Open "C:\TEST\28-06-2013.TXT" For Input As #1

While Not Eof(1)
    Line Input #1, strBuffer
    Debug.Print strBuffer
Wend

Close #1
RonalBertogi 46 Junior Poster in Training

Typing ULONG instead of ulong might help. BTW, DWORD is the same as ULONG.

RonalBertogi 46 Junior Poster in Training

First, have a cleanup of your code. You may (must) replace your code from line 40 up to line 62 with the code below. That way, it could be cleaner to read (and debug) your code and it might help us—including yourself—solve your problem.

if (reply == 'y')
{
    switch (guestAdult)
    {
        case 0:
            if (guestChild == 1)
                totalFee = (((trainNum * TRAINFEE) + (birdNum * BIRDFEE))/2);
            else if (guestChild == 2)
                totalFee = (((trainNum * TRAINFEE) + (birdNum * BIRDFEE))/2);
            else if (guestChild > 2)
                totalFee = ((guestChild - 2) * CHILDFEE) + (((trainNum * TRAINFEE) + (birdNum * BIRDFEE))/2);
            break;
        case 1:
            if (guestChild == 0)
                totalFee = (((trainNum * TRAINFEE) + (birdNum * BIRDFEE))/2);
            else if (guestChild == 1)
                totalFee = (((trainNum * TRAINFEE) + (birdNum * BIRDFEE))/2);
            break;
        case 2:
            totalFee = (guestChild * CHILDFEE) + (((trainNum * TRAINFEE) + (birdNum * BIRDFEE))/2);
            break;
        default:
            if( guestAdult > 2)
                totalFee = ((guestAdult - 2) * ADULTFEE) + (guestChild * CHILDFEE) + (((trainNum * TRAINFEE) + (birdNum * BIRDFEE))/2);
    }
}
else
    totalFee = (adultNum * ADULTFEE) + (childNum * CHILDFEE) + (trainNum * TRAINFEE) + (birdNum * BIRDFEE);
RonalBertogi 46 Junior Poster in Training

Previous answers are correct but I just want to post something clearer. If you are planning to use more than one database simultaneously in your program, you have to make one connection per database.

But the most ideal solution here is to make links to the table of interests from your DB A inside your DB B. The advantage of this is that you only have to create a single connection to work on both databases. The disadvantage here is that, DB A must not be moved to another location in your computer or else the link would be broke. But you can work around this problem, that is, if you know. Me? Show your interest first and I'd be willing to help you.

RonalBertogi 46 Junior Poster in Training

Ugh! Got myself corrected by triumphost. I meant ITaskbarList. But I want to point two lines in your post that may cause an access violation error: These are on lines 16 and 26.

triumphost commented: Yeah forgot to put that in the if statement. Thanks :D +6
RonalBertogi 46 Junior Poster in Training

OK, for the sake of answering the question, when creating your main window (with CreateWindowEx API and not with CreateWindow macro), include in the extended window style the WS_EX_TOOLWINDOW. But you'll have title bar which is awkward for a main window. If you are using a dialog box as your main window, find in the dialog box's properties any property that corresponds to that extended style. In VC++ 6, it was a checkbox button in the extended window style page. In VC2010, it is a boolean property.

ITaskbarIcon interface give's you more control on what appears on the taskbar.

RonalBertogi 46 Junior Poster in Training

But using random numbers in createing bank account number, I suppose, is not a good idea. There are a lot of ways you can generate a unique bank account number. One of this is using the date and time a client registered.

RonalBertogi 46 Junior Poster in Training

First loop is actually 2x(2-2) which will result to 0. But why is your compiled program returning 3?

RonalBertogi 46 Junior Poster in Training

He he he. Actually, the OP's confusion is valid. After the state while( count++<=5), count's value will already be 2, thus cout<<count*(count-2)<<" "; will be 2(2-2)==>2(0)==>0. It's like the sum(A1:A5) function in excel returning different result compared to A1+A2+A3+A4+A5.

If you're very much sure there's nothing to check in your codes, then there might be something wrong with your compiler.

RonalBertogi 46 Junior Poster in Training

You just declared the structure of the class, its ctor and dtor and some data members. Does your project files include a source file that will define the class?

RonalBertogi 46 Junior Poster in Training

What do you want from the web site pointed to by the URL? The HTML document, objects contained in an element like src of the <img> element?

If you are going to do that in windows, you can run an instance of the internet explorer thru its dispatch interface, feed that url to the interface and create a handler on the documentready event and parse the contents of the document thru document dispatch interface when the event fires up.

RonalBertogi 46 Junior Poster in Training

That's one solution to the problem--one solution because there are a lot of ways you can avoid this warning.

RonalBertogi 46 Junior Poster in Training

What kind of post is this?

RonalBertogi 46 Junior Poster in Training

...and to make the life of the user of your program easier, consider him wanting to type lower case F, C and Y.

RonalBertogi 46 Junior Poster in Training

mc3330418's question was that you allocated (dynamically) a Student object but missed (or failed) to deallocate them when your program exits.

Basically when you dynamically allocate an array the compiler calls the constructor for each object you want to allocate.

Yes, that's true, IF, you allocated them using the new statement. And its destructor will also be called ONLY when you use the delete statement. But if you mean by that that the compiler itself will deallocate for you that memory object then you are wrong. The compiler will not know how you allocated a memory and thus can never know how to deallocate them. The link you had given clearly speaks for that.

RonalBertogi 46 Junior Poster in Training

...and for a cleaner coding you can cause the switch statement:

After lines #7 & #8 of Milton Neal's post:

switch( sign )
{
    case '+':
        statements;
        break;
    case '-':
        statements;
        break;
    case '*':
        statements;
        break;
    case '/':
        statements;
        break;
    default:
        cout<<"Invalid sign "<<"("<<sign<<") used.";
}

Replace statements with your actual statements.

ddanbe commented: The best solution +14
RonalBertogi 46 Junior Poster in Training

Calling registry functions does not cause GetLastError() to return any error codes. They are rather returned by the registry function you called.

Example:

DWORD Err;
HKEY key;
char * msg;
Err = RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\\hggjk"), &key);
if( Err!=ERROR_SUCCESS )
{
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM, NULL, 0, Err, (LPTSTR) &msg, 0, NULL);
    cout<<"System: "<<Err<<endl<<endl;
    printf("%S\n System<Message may contain irregular messeges or be shortened", msg);
    LocalFree(msg); // Always call this API to free the memory allocated by the call to FormatMessage
}
else
    RegCloseKey(key);

If RegOpenKey fails, the error code is returned in the Err variable.

Additionally, calling GetLastError() for the first time clears the system's internal error flag thus succeeding calls to GetLastError() will always return 0.

RonalBertogi 46 Junior Poster in Training

Why this program crashes not because of typedef but because of using an uninitialized variable. Look at your code at line #6: You declared static test *p and, without allocating it, used in your int main() function.

On your second post, static test p should work of course because variable p is automatically allocated from the stack.

If you want to use a pointer to your test struct like test *p, you must allocated some memory for it either by using the new operator (as suggested by nullptr) or by any appropriate method.

RonalBertogi 46 Junior Poster in Training

...and while I was waiting for someone to share any ideas, I discovered the culprit.

First, this one will not give you any problem:

struct SomeStruct
{
    int anIntMember;
    long aLongMember;
};

CArray<SomeStruct> some;

This one too will not give you any problem:

CArray<int> someInts;

But this one will:

struct AnotherStruct
{
    char firstMember;
    int secondMember;
    CArray<long> obviouslyAnArray;
}

Well, I just don't know if I am the only one who encountered this problem. I never had it using std::vector though.

RonalBertogi 46 Junior Poster in Training

Observe this code:

        TOOLBARINFO tbi = { 0 };
        BUTTONINFO bi, *xBI;
        tbi.pTOI = pTOI;
        int x = 0, xSearchBox = 0, s = 0;
        BYTE xType = btNone;
        BOOL bAdd;

        for( ;*pszInfo; )
        {
            bAdd = TRUE;
            memset(&bi, 0, sizeof bi);
            switch( *pszInfo )
            {
                case bfButton:
                    s++;
                    bi.L = x + 4;
                    if( xType==bfButton )
                        bi.L += 4;
                    bi.R = bi.L + 24;
                    bi.wFlags = xType = bfButton;

                    if( *(pszInfo+1) )
                    {
                        *++pszInfo;
                        for( ;*(pszInfo+1) && bfActive<=*(pszInfo+1) && *(pszInfo+1)<=bfDisabled;*pszInfo++ )
                            bi.wFlags |= *pszInfo;
                        if( *pszInfo && *pszInfo==':' )
                        {
                            *++pszInfo;
                            _rgTipText.Add(pszInfo);
                        }
                    }
                    break;
                case bfSeparator:
                    bi.L = x + 4;
                    bi.R = x + 6;
                    bi.wFlags = xType = bfSeparator;
                    break;
                case bfLabel:
                {
                    int cx = 0;
                    if( *++pszInfo=='*' )
                        cx = pTOI->DoToolbarOwnerAction(WM_MEASUREITEM, tbi.rgButtons.GetSize(), 0);
                    else
                        cx = _wtoi(pszInfo);
                    bi.wFlags = xType = bfLabel;
                    bi.L = x + 4;
                    bi.R = bi.L + cx;
                    break;
                }
                case bfDropdown:
                    ASSERT(xBI!=NULL);
                    xBI->wFlags |= bfDropdown;
                    bi.L = x;
                    bi.R = x + 5;
                    bi.wFlags = xType = bfDropdown;
                    break;
                case bfSearchBox:
                    bAdd = FALSE;
                    xSearchBox = tbi.rgButtons.GetSize();
                    xType = bfSearchBox;
                    x = -30000;
            }

            if( bAdd )
            {
                x = bi.R;
                if( xSearchBox )
                    tbi.cxRights += (bi.R - bi.L) + 4;
                tbi.rgButtons.Add(bi);
                if( xType==bfButton )
                    xBI = &tbi.rgButtons[tbi.rgButtons.GetSize()-1];
                else
                    xBI = NULL;
            }
            pszInfo += wcslen(pszInfo) + 1;
        }

        if( tbi.rgButtons.GetSize() )
        {
            tbi.xSearchBox = xSearchBox;
            if( pTOI->hbmIco==HBMDEFAULT )
                pTOI->hbmIco = _hbmStdToolbarIco;

            if( xSearchBox )
            {
                RECT rc;
                HWND hwnd = NULL;
                GetClientRect(m_hWnd, &rc);

                rc.left = tbi.rgButtons[xSearchBox-1].R …
RonalBertogi 46 Junior Poster in Training

You can combine info.wShowWindow = SW_HIDE with info.dwFlags = STARTF_USESHOWWINDOW. But the GUI app you are trying to run could always ignore the value of wShowWindow of STARTUPINFO structure (which is passed as int nCmdShow in the WinMain entry point) and show its own window the way it wants (the way the programmer of that particular app wanted). So, to achieve the purpose, I suggest you do the following steps:

  1. Run the app still specifying those values of the two STARTUPINFO struct members
  2. Use WaitForInputIdle on that process so you can get the ideal timing in calling the FindWindow API
  3. Call FindWindow
  4. If calling FindWindow yields the correct window handle, check if it is still visible via IsWindowVisible and...I think you already know what's the next appropriate action here.

Hope this helps. Good luck!

RonalBertogi 46 Junior Poster in Training

if you just want to check if your process is still alive or dead using the process id (pid) you have, calling the OpenProcess API would suffice.

RonalBertogi 46 Junior Poster in Training

But, in continuation to deceptikon's reply, if you just want to be able to call ShellExecute while enabling you to pass your sProgramName variable as an argument, you can use its ANSI version without much hassles, e. g. ShellExecuteA(NULL, NULL, &sProgramName[0], NULL, NULL, SW_SHOW);

CodeAngry commented: this is the solution for your problem +0
RonalBertogi 46 Junior Poster in Training

Using the right shift (>>) operator is the quicker, if not the quickest, method.

RonalBertogi 46 Junior Poster in Training

As your class declaration says, buildFromInputString is part of its structure. But when you defined the functions of your class, particularly buildFromInputString function, I think you simply missed to type something. Look at what you've typed in line 114:

template<typename T>
void buildFromInputString(const string input)
{
    istringstream iss(input);
    while(iss)
    {
        T temp_token;
        iss >> temp_token;
        insert(temp_token);
    }
}

...ain't that supposed to be like this:

template<typename T>
void BST<T>::buildFromInputString(const string input)
{
    istringstream iss(input);
    while(iss)
    {
        T temp_token;
        iss >> temp_token;
        insert(temp_token);
    }
}

You missed the 'BST<T>::'. Thus when this function started from being referenced somewhere else in your program, you will get this linker error since it would fail to find the definition of the said function.

RonalBertogi 46 Junior Poster in Training

Why is this threat not marked as solved yet?

RonalBertogi 46 Junior Poster in Training

He he he... Sorry, I didn't notice I was looking at page 1. My bad :D

RonalBertogi 46 Junior Poster in Training

Just successfully posted a reply to this thread today but I no longer see it when I reopen this thread. Was my post deleted for some reason?

RonalBertogi 46 Junior Poster in Training

I meant in example #2 "for( ;szHex;szHex++ )" which I did actually type. But I lost my asterisk symbols.

RonalBertogi 46 Junior Poster in Training

Well, I think there's no way to directly convert hex to octal because a hex value needs to be parsed first to get its value in real numbers (decimal). But the process is always the same: to convert decimal to another notation (hex, octal) you divide the number with your base (radix), putting the remainder right to left, until you get a zero quotient. Converting from other notation to decimal, start from 0, multiply it with 10 and parse and add the value of that notation starting from the left.

Here I'll show you some example: Note that numerical notations other than decimal can only be stored in strings (well, it's only my assumption and someone may correct me if I'm wrong).

  1. Converting decimal to dexadecimal

    const char * dectohex(long num)
    {
        static char szout[11];
        long c;
        int pos = 10;
        memset(szout, '0', 10);
        while( num )
        {
            c = num % 16;
            if( c<=9 )
                szout[pos--] = '0' + c;
            else
                szout[pos--] = 'A' + c;
            num /= 16;
        }
        szout[0] = '0';
        szout[1] = 'x';
        return szout;
    }
    
  2. Converting hex to decimal

    long hextodec(const char * szHex)
    {
        long ret = 0;
        char h;
        for( ;*szHex;*szHex++ )
        {
            h = tolower(*szHex);
            if( '0'<=h && h<='9' )
                ret = ret * 10 + (h - '0');
            else if( 'a'<=h && h<='f' )
                ret = ret * 10 + (10 + h - 'a');
            else
                break;
        }
        return ret;
    }
    
RonalBertogi 46 Junior Poster in Training

Hello echo,

I wrote here some notes I hope could help you decrypt your problem.

  1. If you want to create a subclassed button where you want to do the painting yourself through the new WNDPROC address you have given, you do not need to create an owner-drawn button.

  2. When responding to WM_PAINT message, it is always necessary to call the BeginPaint/EndPaint APIs to remove the message from the message queue but in your WM_PAINT label...

    case WM_PAINT:
    {
    if(IS_HOVERERING_X == FALSE) {
    xSetButtonState(ID_BUTTON_STATE_NORMAL);
    }
    break;
    }

... you only called your xSetButtonState which subsequently calls BeginPaint/EndPaint when IS_HOVERERING_X is FALSE. Meaning, when this condition is not satisfied, you are choking your message queue. Try to run Task Manager and run your program and you will see what I mean. However, if you pass this message to DefWindowProc nothing will be seen in your control since you did not completely specify the styles for this button. Hence, when responding to WM_PAINT message, always call BeginPaint/EndPaint and do the painting of your button--in all of its states--yourself.

  1. When DefWindowProc receives a WM_CLOSE message, it automatically destroys the window where the message is sent. You only handle WM_CLOSE if you want to really close your application in a particular condition or let it continue running otherwise.

  2. The way to generate bitmaps during the WM_PAINT message in your main window can cause lags to your application. I suggest you store it in some variables so won't be …

RonalBertogi 46 Junior Poster in Training
template<class _T>
const char * dec2bin(_T dec)
{
    static char szret[65];
    int ch = sizeof(dec) * 8;
    memset(szret, 0, ch+1);
    char * ptr = szret;
    for( int i=0;i<ch;i++ )
        ptr[ch-1-i] = '0' + (dec >> i & 1);
    return ptr;
}

I've tried before posting this. dec2bin function accepts any integer (BYTE, short, long, __int64). Hope this helps.

RonalBertogi 46 Junior Poster in Training

All posts above are sufficient answers. I just want to add a little additional info regarding the protected statement: Data/properties and methods of a class declared as protected is only accessible to the class and its inheritors.

RonalBertogi 46 Junior Poster in Training

You can use unsigned long long or you can create a class that can handle infinite numerical value (although may not be worth in some particular case).

RonalBertogi 46 Junior Poster in Training

If you are targetting Windows platform, using a mutex, as suggested by triumphost, is, as my personal experience, the best way to do this. I have here a little sample here:

UINT g_uSyncMsg;

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
    g_uSyncMsg = RegisterWindowMessage("any msg string you prefer");
    HANDLE hMutex = CreateMutex(NULL, TRUE, "unique mutex name you prefer");

    if( ERROR_ALREADY_EXISTS==GetLastError() )
    {
        PostMessage(HWND_BROADCAST, g_uSyncMsg, 0, 0);
        CloseHandle(hMutex);
        return 0;
    }
    ...
    ...
    ...
}

You can also do the same (with the necesary modification) in a console app.

Hope this can help you.

RonalBertogi 46 Junior Poster in Training

Let's examine the code in your binarySearchTree::insert() function line by line:

treeNode *temp;
treeNode *add;

here you allocated memory for you local add variable and set its item property
to the value of x

add = new treeNode;
add->item=x;
temp=root;
if(temp==NULL)

this line here will be executed the first time insert() is called since root is
initialized to NULL in this class' constructor.

    root=add;

root->item now is equal to 1598

else{

This code block here will then be executed in the succeeding calls to the function beccause root is no longer NULL, reiterating until temp becomes NULL. But no matter how many times will this block loop, this does actually nothing to insert the new value which is 160 in your second call.

    while(temp!=NULL){
        if(temp->item>=add->item)
            temp=temp->left;////////////It's here that I encounter the runtime error..why is this?
        else
            temp=temp->right;
    }

Even this line here would not affect your root member. Doing nothing significant.

    temp=add;
}

Hope this could help you.

RonalBertogi 46 Junior Poster in Training

Oh, Bile, I guess it's in Program Files\Microsoft Visual Studio\VB98\Template. In that folder there are different subfolders that for each respective type of template: forms, classes, etc. etc.

RonalBertogi 46 Junior Poster in Training

Create your form with all the menus you need, save it (with the name that will help you identify it's contents) and copy it to the forms templates folder of visual basic. About this folder, :( I can no longer remember where exactly it is. Haven't been using vb6 for quite a long time now.

RonalBertogi 46 Junior Poster in Training

Hello, meLiel! I'll give you an example how to check whether a record exists in database or not. This is best and easily done if your database records has a field that contains a unique key or id. On your sample code, I will just assume that txtEnterID.Text holds the value that is to be to a particular field of your table. Let's just name it here EnterID.

Here I assume that con is a global variable

Public Function RecordExists(ByVal pszId As String) As Boolean
    Dim rs As ADODB.Recordset
    Set rs = con.Execute("SELECT EnterID FROM MyTable WHERE EnterID='" & pszId & "'")
    RecordExists = rs.RecordCount<>0;
End Function

About those text boxes, you create a function that will check each control if they have a valid value. It's better if you store your control in an array...

That's all for now.

RonalBertogi 46 Junior Poster in Training

Looks like you have already done some sort of exercises. Perhaps all you need to do first is to review those exercises you underwent. E. g. what is a struct and how to declare a struct? How to declare variables and assign value to them? etc. etc.

Do them first and I bet it will help you "get the ball rolling".

RonalBertogi 46 Junior Poster in Training

include winmm.lib in your project imports or do the pragma: #pragma comment(lib, "winmm.lib")

BTW, here is my own version. Additional to this is you can lock/unlock the drive.

// dischander.h

#pragma once

struct DiscHandler
{
    // I assume these routines are self-explanatory
    static BOOL Eject(BYTE bDrive);
    static BOOL Load(BYTE bDrive);
    static BOOL IsReady(BYTE bDrive);
    static DWORD GetSerial(BYTE bDrive, wchar_t * pLabelBuf = 0, int chBuf = 0);
    static void Lock(BYTE bDrive, BOOL fLock);

private:
    struct DeviceHandle
    {
        DeviceHandle(BYTE bDrive);
        ~DeviceHandle();
        operator HANDLE();
        HANDLE m_handle;
    };
};

#define EjectDrive     DiscHandler::Eject
#define LoadDrive      DiscHandler::Load
#define IsDriveReady   DiscHandler::IsReady
#define GetDiscSerial  DiscHandler::GetSerial
#define LockDrive      DiscHandler::Lock

...and the definition

#include "dischandler.h"
#include <winioctl.h>

DiscHandler::DeviceHandle::DeviceHandle(BYTE bDrive)
{
    wchar_t szRoot[] = L"\\\\.\\?:";
    szRoot[4] = bDrive;
    m_handle = CreateFile(szRoot, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
        OPEN_EXISTING, 0, NULL);
    if( m_handle==INVALID_HANDLE_VALUE )
        m_handle = NULL;
}

DiscHandler::DeviceHandle::~DeviceHandle()
{
    if( m_handle )
        CloseHandle(m_handle);
}

DiscHandler::DeviceHandle::operator HANDLE()
{
    return m_handle;
}

BOOL DiscHandler::Eject(BYTE bDrive)
{
    DeviceHandle hDrive = bDrive;
    if( hDrive )
    {
        DWORD dwBytesReturned;
        return DeviceIoControl(hDrive, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
    }
    return FALSE;
}

BOOL DiscHandler::Load(BYTE bDrive)
{
    DeviceHandle hDrive = bDrive;
    if( hDrive )
    {
        DWORD dwBytesReturned;
        return DeviceIoControl(hDrive, IOCTL_STORAGE_LOAD_MEDIA, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
    }
    return 0;
}

BOOL DiscHandler::IsReady(BYTE bDrive)
{
    DeviceHandle hDrive = bDrive;
    if( hDrive )
    {
        DWORD dwBytesReturned;
        return DeviceIoControl(hDrive, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
    }
    return 0;
}

DWORD DiscHandler::GetSerial(BYTE bDrive, wchar_t * pLabelBuf, int chBuf)
{
    DWORD dwSerial = 0;
    wchar_t wsz[] = L"?:\\"; …
RonalBertogi 46 Junior Poster in Training

You can use these GDI API functions:

GetObject
GetDIBits

They are faster than GetPixel but entails more work than the latter.

RonalBertogi 46 Junior Poster in Training

What kind of error are you receiving, run-time or compile time? May I know the IDE you are using and its version?