none
MSVCRTD.lib(crtexew.obj) : error LNK2019: unresolved external symbol _WinMain@16 referenced in function ___tmainCRTStartup

    Question

  • When trying to compile the code below I get this error 
    "MSVCRTD.lib(crtexew.obj) : error LNK2019: unresolved external symbol _WinMain@16 referenced in function ___tmainCRTStartup"
    Can someone please tell me how to fix this error? The code is from the following url :
    http://msdn.microsoft.com/en-us/library/ms646268%28v=VS.85%29.aspx?appId=Dev10IDEF1&l=EN-US&k=k%28%22WINUSER/
    DRAWTEXT%22%29;k%28DRAWTEXT%29;k%28DevLang-%22C++%22%29;k%28TargetOS-WINDOWS%29&rd=true
    Have tried console & windows subsystem, neither works and also tried changing the entry point still no luck.

    #define BUFSIZE 65535
    #define SHIFTED 0x8000

    LONG APIENTRY MainWndProc(HWND hwndMain, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    HDC hdc; // handle to device context
    TEXTMETRIC tm; // structure for text metrics
    static DWORD dwCharX; // average width of characters
    static DWORD dwCharY; // height of characters
    static DWORD dwClientX; // width of client area
    static DWORD dwClientY; // height of client area
    static DWORD dwLineLen; // line length
    static DWORD dwLines; // text lines in client area
    static int nCaretPosX = 0; // horizontal position of caret
    static int nCaretPosY = 0; // vertical position of caret
    static int nCharWidth = 0; // width of a character
    static int cch = 0; // characters in buffer
    static int nCurChar = 0; // index of current character
    static PTCHAR pchInputBuf; // input buffer
    int i, j; // loop counters
    int cCR = 0; // count of carriage returns
    int nCRIndex = 0; // index of last carriage return
    int nVirtKey; // virtual-key code
    TCHAR szBuf[128]; // temporary buffer
    TCHAR ch; // current character
    PAINTSTRUCT ps; // required by BeginPaint
    RECT rc; // output rectangle for DrawText
    SIZE sz; // string dimensions
    COLORREF crPrevText; // previous text color
    COLORREF crPrevBk; // previous background color
    size_t * pcch;
    HRESULT hResult;

    switch (uMsg)
    {
    case WM_CREATE:

    // Get the metrics of the current font.

    hdc = GetDC(hwndMain);
    GetTextMetrics(hdc, &tm);
    ReleaseDC(hwndMain, hdc);

    // Save the average character width and height.

    dwCharX = tm.tmAveCharWidth;
    dwCharY = tm.tmHeight;

    // Allocate a buffer to store keyboard input.

    pchInputBuf = (LPTSTR) GlobalAlloc(GPTR,
    BUFSIZE * sizeof(TCHAR));
    return 0;

    case WM_SIZE:

    // Save the new width and height of the client area.

    dwClientX = LOWORD(lParam);
    dwClientY = HIWORD(lParam);

    // Calculate the maximum width of a line and the
    // maximum number of lines in the client area.

    dwLineLen = dwClientX - dwCharX;
    dwLines = dwClientY / dwCharY;
    break;


    case WM_SETFOCUS:

    // Create, position, and display the caret when the
    // window receives the keyboard focus.

    CreateCaret(hwndMain, (HBITMAP) 1, 0, dwCharY);
    SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
    ShowCaret(hwndMain);
    break;

    case WM_KILLFOCUS:

    // Hide and destroy the caret when the window loses the
    // keyboard focus.

    HideCaret(hwndMain);
    DestroyCaret();
    break;

    case WM_CHAR:
    // check if current location is close enough to the
    // end of the buffer that a buffer overflow may
    // occur. If so, add null and display contents.
    if (cch > BUFSIZE-5)
    {
    pchInputBuf[cch] = 0x00;
    SendMessage(hwndMain, WM_PAINT, 0, 0);
    }
    switch (wParam)
    {
    case 0x08: // backspace
    case 0x0A: // linefeed
    case 0x1B: // escape
    MessageBeep((UINT) -1);
    return 0;

    case 0x09: // tab

    // Convert tabs to four consecutive spaces.

    for (i = 0; i < 4; i++)
    SendMessage(hwndMain, WM_CHAR, 0x20, 0);
    return 0;

    case 0x0D: // carriage return

    // Record the carriage return and position the
    // caret at the beginning of the new line.

    pchInputBuf[cch++] = 0x0D;
    nCaretPosX = 0;
    nCaretPosY += 1;
    break;

    default: // displayable character

    ch = (TCHAR) wParam;
    HideCaret(hwndMain);

    // Retrieve the character's width and output
    // the character.

    hdc = GetDC(hwndMain);
    GetCharWidth32(hdc, (UINT) wParam, (UINT) wParam,
    &nCharWidth);
    TextOut(hdc, nCaretPosX, nCaretPosY * dwCharY,
    &ch, 1);
    ReleaseDC(hwndMain, hdc);

    // Store the character in the buffer.

    pchInputBuf[cch++] = ch;

    // Calculate the new horizontal position of the
    // caret. If the position exceeds the maximum,
    // insert a carriage return and move the caret
    // to the beginning of the next line.

    nCaretPosX += nCharWidth;
    if ((DWORD) nCaretPosX > dwLineLen)
    {
    nCaretPosX = 0;
    pchInputBuf[cch++] = 0x0D;
    ++nCaretPosY;
    }
    nCurChar = cch;
    ShowCaret(hwndMain);
    break;
    }
    SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
    break;

    case WM_KEYDOWN:
    switch (wParam)
    {
    case VK_LEFT: // LEFT ARROW

    // The caret can move only to the beginning of
    // the current line.

    if (nCaretPosX > 0)
    {
    HideCaret(hwndMain);

    // Retrieve the character to the left of
    // the caret, calculate the character's
    // width, then subtract the width from the
    // current horizontal position of the caret
    // to obtain the new position.

    ch = pchInputBuf[--nCurChar];
    hdc = GetDC(hwndMain);
    GetCharWidth32(hdc, ch, ch, &nCharWidth);
    ReleaseDC(hwndMain, hdc);
    nCaretPosX = max(nCaretPosX - nCharWidth,
    0);
    ShowCaret(hwndMain);
    }
    break;

    case VK_RIGHT: // RIGHT ARROW

    // Caret moves to the right or, when a carriage
    // return is encountered, to the beginning of
    // the next line.

    if (nCurChar < cch)
    {
    HideCaret(hwndMain);

    // Retrieve the character to the right of
    // the caret. If it's a carriage return,
    // position the caret at the beginning of
    // the next line.

    ch = pchInputBuf[nCurChar];
    if (ch == 0x0D)
    {
    nCaretPosX = 0;
    nCaretPosY++;
    }

    // If the character isn't a carriage
    // return, check to see whether the SHIFT
    // key is down. If it is, invert the text
    // colors and output the character.

    else
    {
    hdc = GetDC(hwndMain);
    nVirtKey = GetKeyState(VK_SHIFT);
    if (nVirtKey & SHIFTED)
    {
    crPrevText = SetTextColor(hdc,
    RGB(255, 255, 255));
    crPrevBk = SetBkColor(hdc,
    RGB(0,0,0));
    TextOut(hdc, nCaretPosX,
    nCaretPosY * dwCharY,
    &ch, 1);
    SetTextColor(hdc, crPrevText);
    SetBkColor(hdc, crPrevBk);
    }

    // Get the width of the character and
    // calculate the new horizontal
    // position of the caret.

    GetCharWidth32(hdc, ch, ch, &nCharWidth);
    ReleaseDC(hwndMain, hdc);
    nCaretPosX = nCaretPosX + nCharWidth;
    }
    nCurChar++;
    ShowCaret(hwndMain);
    break;
    }
    break;

    case VK_UP: // UP ARROW
    case VK_DOWN: // DOWN ARROW
    MessageBeep((UINT) -1);
    return 0;

    case VK_HOME: // HOME

    // Set the caret's position to the upper left
    // corner of the client area.

    nCaretPosX = nCaretPosY = 0;
    nCurChar = 0;
    break;

    case VK_END: // END

    // Move the caret to the end of the text.

    for (i=0; i < cch; i++)
    {
    // Count the carriage returns and save the
    // index of the last one.

    if (pchInputBuf[i] == 0x0D)
    {
    cCR++;
    nCRIndex = i + 1;
    }
    }
    nCaretPosY = cCR;

    // Copy all text between the last carriage
    // return and the end of the keyboard input
    // buffer to a temporary buffer.

    for (i = nCRIndex, j = 0; i < cch; i++, j++)
    szBuf[j] = pchInputBuf[i];
    szBuf[j] = TEXT('\0');

    // Retrieve the text extent and use it
    // to set the horizontal position of the
    // caret.

    hdc = GetDC(hwndMain);
    hResult = StringCchLength(szBuf, 128, pcch);
    if (FAILED(hResult))
    {
    // TODO: write error handler
    }
    GetTextExtentPoint32(hdc, szBuf, *pcch,
    &sz);
    nCaretPosX = sz.cx;
    ReleaseDC(hwndMain, hdc);
    nCurChar = cch;
    break;

    default:
    break;
    }
    SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
    break;

    case WM_PAINT:
    if (cch == 0) // nothing in input buffer
    break;

    hdc = BeginPaint(hwndMain, &ps);
    HideCaret(hwndMain);

    // Set the clipping rectangle, and then draw the text
    // into it.

    SetRect(&rc, 0, 0, dwLineLen, dwClientY);
    DrawText(hdc, pchInputBuf, -1, &rc, DT_LEFT);

    ShowCaret(hwndMain);
    EndPaint(hwndMain, &ps);
    break;

    // Process other messages.

    case WM_DESTROY:
    PostQuitMessage(0);

    // Free the input buffer.

    GlobalFree((HGLOBAL) pchInputBuf);
    UnregisterHotKey(hwndMain, 0xAAAA);
    break;

    default:
    return DefWindowProc(hwndMain, uMsg, wParam, lParam);
    }
    return NULL;
    Sunday, August 29, 2010 1:11 PM

Answers

  • Hello Richard,

     

    1. The code listed in your post is an example window procedure that shows how keyboard characters can be processed in a Windows application.

     

    2. A window procedure is an essential part of a Windows application that intends to display a window. Note however, that a Windows application also requires a WinMain() function that serves as the entry point into the application itself.

     

    3. The WinMain() function was not included in the example code. It is a code snippet and the author of the article most probably assumed that you will supply one already for your application.

     

    4. Along with the WinMain() entry point function, other important elements of a Windows application are :

    4.1 The window class.

    Each window is created based on a window class. Such a class is defined by using a WNDCLASSEX struct. It is in this structure that the window procedure is specified.

    4.2 Registration of the window class.

    The registration of a window class is performed via the RegisterClassEx() API.

    4.3 Creation of the window (based on the window class).

    This is performed via the CreateWindow() API.

    4.4 Message loop.

    This is what keeps the window "alive". Messages must be pumped into the window procedure of a window otherwise the window will become unresponsive ("hung").

     

    5. I suggest that you use the Visual Studio wizard to generate a skeleton Win32 Windows application.

    5.1 Thereafter, paste the MainWndProc() example code into the source.

    5.2 If you are using Visual Studio 2008, a sample function named MyRegisterClass() will be generated for you.

    5.3 It is in this function that a new window class is created. All you need to do is point the window prcedure of the new window class to MainWndProc() :

    wcex.lpfnWndProc = MainWndProc; //WndProc;

    I just tried it and it worked.

    5.4 Note that the example code references the StringCchLength() API. For this, you need to #include strsafe.h and also link to strsafe.lib.

     

    Best of luck, Richard,

    - Bio.

     

    Sunday, August 29, 2010 2:23 PM

All replies

  • Richard.Holland wrote:

    [code]
    When trying to compile the code below I get this error

    "MSVCRTD.lib(crtexew.obj) : error LNK2019: unresolved external symbol  _WinMain@16 referenced in function ___tmainCRTStartup"

    Can someone please tell me how to fix this error?

    You write a function named WinMain, of course. That's where execution of  your program starts.


    Igor Tandetnik

    Sunday, August 29, 2010 1:25 PM
  • Hello Richard,

     

    1. The code listed in your post is an example window procedure that shows how keyboard characters can be processed in a Windows application.

     

    2. A window procedure is an essential part of a Windows application that intends to display a window. Note however, that a Windows application also requires a WinMain() function that serves as the entry point into the application itself.

     

    3. The WinMain() function was not included in the example code. It is a code snippet and the author of the article most probably assumed that you will supply one already for your application.

     

    4. Along with the WinMain() entry point function, other important elements of a Windows application are :

    4.1 The window class.

    Each window is created based on a window class. Such a class is defined by using a WNDCLASSEX struct. It is in this structure that the window procedure is specified.

    4.2 Registration of the window class.

    The registration of a window class is performed via the RegisterClassEx() API.

    4.3 Creation of the window (based on the window class).

    This is performed via the CreateWindow() API.

    4.4 Message loop.

    This is what keeps the window "alive". Messages must be pumped into the window procedure of a window otherwise the window will become unresponsive ("hung").

     

    5. I suggest that you use the Visual Studio wizard to generate a skeleton Win32 Windows application.

    5.1 Thereafter, paste the MainWndProc() example code into the source.

    5.2 If you are using Visual Studio 2008, a sample function named MyRegisterClass() will be generated for you.

    5.3 It is in this function that a new window class is created. All you need to do is point the window prcedure of the new window class to MainWndProc() :

    wcex.lpfnWndProc = MainWndProc; //WndProc;

    I just tried it and it worked.

    5.4 Note that the example code references the StringCchLength() API. For this, you need to #include strsafe.h and also link to strsafe.lib.

     

    Best of luck, Richard,

    - Bio.

     

    Sunday, August 29, 2010 2:23 PM