Gabriel Y.
Gabriel Y.

Reputation: 85

LNK2019 error when building solution. Why?

I'm sure this has been addressed in the past. My apologies.

I want to understand why I'm getting error LNK2019.
And what direction to take, to get this resolved.

Errors are LNK2019:
unresolved external symbol __imp__ReportError referenced in function _wmain
unresolved external symbol __imp__Options referenced in function _wmain

This occurs when I build solution in Visual Studio 2010 and up.
Contents of header file for the above methods are described like so:

LIBSPEC DWORD Options (int, LPCTSTR *, LPCTSTR, ...);
LIBSPEC DWORD Options (int, LPCTSTR *, LPCTSTR, ...);

Main code:

#include "Everything.h"

BOOL TraverseDirectory(LPTSTR, LPTSTR, DWORD, LPBOOL);
DWORD FileType(LPWIN32_FIND_DATA);
BOOL ProcessItem(LPWIN32_FIND_DATA, DWORD, LPBOOL);

int _tmain(int argc, LPTSTR argv[])
{
    BOOL flags[MAX_OPTIONS], ok = TRUE;
    TCHAR searchPattern[MAX_PATH + 1], currPath[MAX_PATH_LONG+1], parentPath[MAX_PATH_LONG+1];
    LPTSTR pSlash, pSearchPattern;
    int i, fileIndex;
    DWORD pathLength;

    fileIndex = Options(argc, argv, _T("Rl"), &flags[0], &flags[1], NULL);


    pathLength = GetCurrentDirectory(MAX_PATH_LONG, currPath); 
    if (pathLength == 0 || pathLength >= MAX_PATH_LONG) { /* pathLength >= MAX_PATH_LONG (32780) should be impossible */
        ReportError(_T("GetCurrentDirectory failed"), 1, TRUE);
    }

    if (argc < fileIndex + 1) 
        ok = TraverseDirectory(currPath, _T("*"), MAX_OPTIONS, flags);
    else for (i = fileIndex; i < argc; i++) {
        if (_tcslen(argv[i]) >= MAX_PATH) {
            ReportError(_T("The command line argument is longer than the maximum this program supports"), 2, FALSE);
        }
        _tcscpy(searchPattern, argv[i]);
        _tcscpy(parentPath, argv[i]);

        pSlash = _tstrrchr(parentPath, _T('\\')); 
        if (pSlash != NULL) {
            *pSlash = _T('\0');
            _tcscat(parentPath, _T("\\"));         
            SetCurrentDirectory(parentPath);
            pSlash = _tstrrchr(searchPattern, _T('\\'));  
            pSearchPattern = pSlash + 1;
        } else {
            _tcscpy(parentPath, _T(".\\"));
            pSearchPattern = searchPattern;
        }
        ok = TraverseDirectory(parentPath, pSearchPattern, MAX_OPTIONS, flags) && ok;
        SetCurrentDirectory(currPath);  
    }

    return ok ? 0 : 1;
}

static BOOL TraverseDirectory(LPTSTR parentPath, LPTSTR searchPattern, DWORD numFlags, LPBOOL flags)
{
    HANDLE searchHandle;
    WIN32_FIND_DATA findData;
    BOOL recursive = flags[0];
    DWORD fType, iPass, lenParentPath;
    TCHAR subdirectoryPath[MAX_PATH + 1];

    /* Open up the directory search handle and get the
        first file name to satisfy the path name.
        Make two passes. The first processes the files
        and the second processes the directories. */

    if ( _tcslen(searchPattern) == 0 ) {
        _tcscat(searchPattern, _T("*"));
    }
    /* Add a backslash, if needed, at the end of the parent path */
    if (parentPath[_tcslen(parentPath)-1] != _T('\\') ) { /* Add a \ to the end of the parent path, unless there already is one */
        _tcscat (parentPath, _T("\\"));
    }


    /* Open up the directory search handle and get the
        first file name to satisfy the path name. Make two passes.
        The first processes the files and the second processes the directories. */

    for (iPass = 1; iPass <= 2; iPass++) {
        searchHandle = FindFirstFile(searchPattern, &findData);
        if (searchHandle == INVALID_HANDLE_VALUE) {
            ReportError(_T("Error opening Search Handle."), 0, TRUE);
            return FALSE;
        }


        do {

            fType = FileType(&findData);
            if (iPass == 1) /* ProcessItem is "print attributes". */
                ProcessItem(&findData, MAX_OPTIONS, flags);

            lenParentPath = (DWORD)_tcslen(parentPath);
            /* Traverse the subdirectory on the second pass. */
            if (fType == TYPE_DIR && iPass == 2 && recursive) {
                _tprintf(_T("\n%s%s:"), parentPath, findData.cFileName);
                SetCurrentDirectory(findData.cFileName);
                if (_tcslen(parentPath) + _tcslen(findData.cFileName) >= MAX_PATH_LONG-1) {
                    ReportError(_T("Path Name is too long"), 10, FALSE);
                }
                _tcscpy(subdirectoryPath, parentPath);
                _tcscat (subdirectoryPath, findData.cFileName); /* The parent path terminates with \ before the _tcscat call */
                TraverseDirectory(subdirectoryPath, _T("*"), numFlags, flags);
                SetCurrentDirectory(_T("..")); /* Restore the current directory */
            }

            /* Get the next file or directory name. */

        } while (FindNextFile(searchHandle, &findData));

        FindClose(searchHandle);
    }
    return TRUE;
}

static DWORD FileType(LPWIN32_FIND_DATA pFileData)
{
    BOOL isDir;
    DWORD fType;
    fType = TYPE_FILE;
    isDir =(pFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
    if (isDir)
        if (lstrcmp(pFileData->cFileName, _T(".")) == 0
                || lstrcmp(pFileData->cFileName, _T("..")) == 0)
            fType = TYPE_DOT;
        else fType = TYPE_DIR;
    return fType;
}

static BOOL ProcessItem(LPWIN32_FIND_DATA pFileData, DWORD numFlags, LPBOOL flags)
{
    const TCHAR fileTypeChar[] = {_T(' '), _T('d')};
    DWORD fType = FileType(pFileData);
    BOOL longList = flags[1];
    SYSTEMTIME lastWrite;

    if (fType != TYPE_FILE && fType != TYPE_DIR) return FALSE;

    _tprintf(_T("\n"));
    if (longList) {
        _tprintf(_T("%c"), fileTypeChar[fType - 1]);
        _tprintf(_T("%10d"), pFileData->nFileSizeLow);
        FileTimeToSystemTime(&(pFileData->ftLastWriteTime), &lastWrite);
        _tprintf(_T("   %02d/%02d/%04d %02d:%02d:%02d"),
                lastWrite.wMonth, lastWrite.wDay,
                lastWrite.wYear, lastWrite.wHour,
                lastWrite.wMinute, lastWrite.wSecond);
    }
    _tprintf(_T(" %s"), pFileData->cFileName);
    return TRUE;
}

Upvotes: 2

Views: 847

Answers (2)

Cody Gray
Cody Gray

Reputation: 244732

The error you're getting is from the linker, and it's telling you that it cannot find the definitions of the ReportError and Options functions (both of which are referenced from your main function).

You say that you have included a header file that contains these functions, but that header contains only the declarations of these functions. You know, like their signature. It doesn't have the body (implementation) of the functions. You need the definition for that.

Definitions for functions that you've written are usually located in *.cpp files. If you've written these functions, make sure that the code file that contains their definitions has been added to your project.

For functions that you have not written (i.e. are part of a reusable library of code), you usually provide the linker with a *.lib file that contains what it needs to call the functions. If these functions are from a library, make sure that you've added the *.lib file that came with them to the list of files that the linker will search. To do that in Visual Studio, follow these steps:

  1. Right-click on your project in the Solution Explorer, and open its Properties.
  2. Expand the "Linker" category, and select the "Input" node.
  3. Click in the "Additional Dependencies" field, and press the ... button.
  4. Enter the name of your *.lib file on a new line in the textbox that appears.

Upvotes: 2

abelenky
abelenky

Reputation: 64682

Just because you declared a function in a header file, doesn't mean it has a body anywhere.

The link error says the function doesn't have a body.

This is likely because you didn't link to the proper Library (a .lib file).

Upvotes: 1

Related Questions