error LNK2019: unresolved external symbol

EDN Admin

Well-known member
Joined
Aug 7, 2010
Messages
12,794
Location
In the Machine
Im a total newbie to C++, using VS 2008. I was looking at MS WIC/GDI app that opened a TIF and displayed it on a form. I modified the code to split the multipage TIF into individual files. This was working fine
But I wanted to see if I could recreate it as a DLL called objTiffSplitter. So I got rid of the form, and started a new console app, and moved the code into the new project. Compiles fine. When I tried to run it, I got dozens of "unresolved external
symbol" errors. So I added a couple of Lib files on the Linker screen (such as Gdiplus.Lib). This got rid of all the "unresolved external symbol" errors except one.
The weird thing is that this last "unresolved external symbol" isnt referring to an external library - the error message has the name of my own class !!! (objTiffSplitterr).

Error 6 error LNK2019: unresolved external symbol "public: __thiscall objTiffSplitter::objTiffSplitter(void)" (??0objTiffSplitter@@QAE@XZ) referenced in function _wmain TiffSplitter.obj
TiffSplitter


The error occurs (at runtime) when I try to instanciate my class.

<pre>int _tmain(int argc, _TCHAR* argv[])
{
objTiffSplitter* pSplitter = new objTiffSplitter();<br/>return 0;<br/> }[/code]

I tried it with and without the parentheses() but didnt make a difference. Maybe the problem is that I only have a .CPP file? (I put the header-code stuff directly in the CPP file). Heres the complete code:

<pre>// TiffSplitter.cpp : Defines the entry point for the console application.
//




#ifndef WINVER // Allow use of features specific to Windows XP or later.
#define WINVER 0x0501 // Change this to the appropriate value to target other versions of Windows.
#endif

#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
#endif

#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later.
#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
#endif

#ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later.
#define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE.
#endif

#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers


#include <windows.h>
#include <wincodec.h>
#include <commdlg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <winuser.h>
#include <wchar.h>
#include "stdafx.h"
#include <objbase.h>
#include <gdiplus.h>
#include <wincodecsdk.h>
#include<iostream>


template <typename T>
inline void SafeRelease(T *&p)
{
if (NULL != p)
{
p->Release();
p = NULL;
}
}


class objTiffSplitter
{
public:
objTiffSplitter::objTiffSplitter();
objTiffSplitter::~objTiffSplitter();
void objTiffSplitter::splitTiff(LPCWSTR sourceFile, LPCWSTR outputDirectoryPlusPrefixWithPercentD, int *numPagesProcessed);


private:
BYTE *m_pbBuffer;
IWICBitmapSource *m_pOriginalBitmapSource;
HRESULT objTiffSplitter::ConvertBitmapSource(IWICBitmapSource **ppToRenderBitmapSource);
HRESULT objTiffSplitter::CreateDIBSectionFromBitmapSource(IWICBitmapSource *pToRenderBitmapSource);
void objTiffSplitter::DeleteBufferAndBmp();
void objTiffSplitter::subGetCLSID(WCHAR* format, CLSID* pClsid);
Gdiplus::Bitmap *m_pGdiPlusBitmap;
IWICImagingFactory *m_pIWICFactory;

};

objTiffSplitter::~objTiffSplitter()
{
SafeRelease(m_pIWICFactory);
SafeRelease(m_pOriginalBitmapSource);
DeleteBufferAndBmp();
}

void objTiffSplitter::splitTiff(LPCWSTR sourceFile, LPCWSTR outputDirectoryPlusPrefixWithPercentD, int *numPagesProcessed)
{
numPagesProcessed =0;
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
IWICBitmapFrameDecode *pFrame = NULL;
IWICBitmapDecoder *pDecoder = NULL; //pass in this decoder-pointer byRef as to create the decoder.
if (!SUCCEEDED(hr)) goto ExitSub;
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
Gdiplus::Status status = Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
if(status != Gdiplus::Ok) goto ExitSub;
CLSID *pClsid = new CLSID;
subGetCLSID(L"TIFF", pClsid);
// Step 2: Decode the source image to IWICBitmapSource
// Create a decoder specific to the image file on disk.
hr = m_pIWICFactory->CreateDecoderFromFilename(
sourceFile, // The file on disk to be decoded.
NULL, // Do not prefer a particular vendor
GENERIC_READ, // Desired read access to the file
WICDecodeMetadataCacheOnDemand, // Cache metadata when needed
&pDecoder // Pointer to the decoder
);
if (!SUCCEEDED(hr)) goto ExitSub;
// Retrieve the first frame of the image from the decoder

UINT numPages = 1;
hr = pDecoder->GetFrameCount(&numPages);
if (!SUCCEEDED(hr)) numPages =1;
for (UINT intFrameIndex = 0; intFrameIndex < numPages; intFrameIndex++)
{
hr = pDecoder->GetFrame(intFrameIndex, &pFrame); //<------ loads the frame into pFrame.
// Retrieve IWICBitmapSource from the frame
// m_pOriginalBitmapSource contains the original bitmap and acts as an intermediate
SafeRelease(m_pOriginalBitmapSource);
pFrame->QueryInterface( IID_IWICBitmapSource, reinterpret_cast<void **>(&m_pOriginalBitmapSource));
// Step 3: Convert the pixel format to 32bppBGR because it is is compatible with GDIplus
IWICBitmapSource *pToRenderBitmapSource = NULL;
hr = ConvertBitmapSource(&pToRenderBitmapSource);
// Step 4: Create a DIB from the converted IWICBitmapSource
hr = CreateDIBSectionFromBitmapSource(pToRenderBitmapSource);
SafeRelease(pToRenderBitmapSource); //todo - release memory here?
TCHAR pathToDestFile[1000];
wsprintf(pathToDestFile, outputDirectoryPlusPrefixWithPercentD , intFrameIndex +1);
m_pGdiPlusBitmap->Save(pathToDestFile, pClsid, 0);
numPagesProcessed++;
}

ExitSub:;
SafeRelease(pDecoder);
SafeRelease(pFrame);
Gdiplus::GdiplusShutdown(gdiplusToken);
CoUninitialize();
}


// Converts to 32bppBGR
HRESULT objTiffSplitter::ConvertBitmapSource(IWICBitmapSource **ppToRenderBitmapSource)
{
HRESULT hr = S_OK;
*ppToRenderBitmapSource = NULL;
IWICFormatConverter *pConverter = NULL;
hr = m_pIWICFactory->CreateFormatConverter(&pConverter);
if (!SUCCEEDED(hr)) return hr;

hr = pConverter->Initialize(
m_pOriginalBitmapSource, // Input bitmap to convert
GUID_WICPixelFormat32bppBGR, // Destination pixel format
WICBitmapDitherTypeNone, // Specified dither patterm
NULL, // Specify a particular palette
0.f, // Alpha threshold
WICBitmapPaletteTypeCustom // Palette translation type
);
if (!SUCCEEDED(hr)) goto ExitSub;
// Store the converted bitmap as ppToRenderBitmapSource
hr = pConverter->QueryInterface( IID_PPV_ARGS(ppToRenderBitmapSource));
ExitSub:
SafeRelease(pConverter);
return hr;
}


// Creates a DIB Section from the converted IWICBitmapSource *
HRESULT objTiffSplitter::CreateDIBSectionFromBitmapSource(IWICBitmapSource *pToRenderBitmapSource)
{
HRESULT hr = S_OK;
UINT width = 0;
UINT height = 0;
// Check BitmapSource format
WICPixelFormatGUID pixelFormat;
hr = pToRenderBitmapSource->GetPixelFormat(&pixelFormat);
if (SUCCEEDED(hr)) hr = (pixelFormat == GUID_WICPixelFormat32bppBGR) ? S_OK : E_FAIL;
if (SUCCEEDED(hr)) hr = pToRenderBitmapSource->GetSize(&width, &height);
UINT cbStride = 0;
// Size of a scan line represented in bytes: 4 bytes each pixel
if (SUCCEEDED(hr)) hr = UIntMult(width, sizeof(Gdiplus::ARGB), &cbStride);
UINT cbBufferSize = 0;
if (SUCCEEDED(hr)) hr = UIntMult(cbStride, height, &cbBufferSize); // Size of the image, represented in bytes
if (!SUCCEEDED(hr)) return hr;
DeleteBufferAndBmp(); // Make sure to free previously allocated buffer and bitmap
m_pbBuffer = new BYTE[cbBufferSize];
hr = (m_pbBuffer) ? S_OK : E_FAIL;
if (!SUCCEEDED(hr)) return hr;
WICRect rc = { 0, 0, width, height };
// Extract the image into the GDI+ Bitmap
hr = pToRenderBitmapSource->CopyPixels(&rc, cbStride, cbBufferSize, m_pbBuffer);
if (!SUCCEEDED(hr)) return hr;
m_pGdiPlusBitmap = new Gdiplus::Bitmap( width, height, cbStride, PixelFormat32bppRGB, m_pbBuffer);
hr = m_pGdiPlusBitmap ? S_OK : E_FAIL;
if (!SUCCEEDED(hr)) return hr;
if (m_pGdiPlusBitmap->GetLastStatus() != Gdiplus::Ok) hr = E_FAIL;
if (FAILED(hr)) DeleteBufferAndBmp();
return hr;
}

void objTiffSplitter::DeleteBufferAndBmp()
{
SafeRelease(m_pIWICFactory);
SafeRelease(m_pOriginalBitmapSource);
DeleteBufferAndBmp();
}
//todo return numpages to caller.

void objTiffSplitter::subGetCLSID(WCHAR* format, CLSID* pClsid)
{
CLSID classID;
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes
Gdiplus::ImageCodecInfo* pImageCodecInfo = NULL;
Gdiplus::GetImageEncodersSize(&num, &size);
pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size));
GetImageEncoders(num, size, pImageCodecInfo);
for(UINT j = 0; j < num; ++j)
if( wcscmp(pImageCodecInfo[j].FormatDescription, format) == 0 )
{
classID = pImageCodecInfo[j].Clsid;
*pClsid = classID;
free(pImageCodecInfo);
return;
}
}


//todo - try to get the percent d moved.
int _tmain(int argc, _TCHAR* argv[])
{
objTiffSplitter* pSplitter = new objTiffSplitter();
/*int* pNumPages = new int;
LPCWSTR sourceImage = TEXT("C:z.tif");
LPCWSTR destDirectory = TEXT("C:zoutz0000%d.tif");
(*pSplitter).splitTiff(sourceImage, destDirectory, pNumPages);
delete pSplitter;
std::cout << *pNumPages << std::endl;*/
return 0;
}

[/code]



<br/>
<br/>

View the full article
 
Back
Top