template link errors  
Author Message
akb825





PostPosted: Visual C++ Express Edition, template link errors Top

I've been looking for a solution for this all day now, and it's driving me crazy. I have a C++ couple of C++ template classes that I'm using in a test executable for a DLL I built. The templates are used in the DLL as well, but in all cases that I use it, to avoid errors, I have all the template code in the header, so when it's included all the code is available for the compiler to do the type resolutions. When I build the DLL, it compiles and links just fine. However, when I build the executable, I get unresolved token and unresolved external symbol errors for the template, but only for the one that I use in the executable, not for the ones used in the DLL. I have tried to change the type temporarily to int and have copied and pasted the code directly into the source, neither of which fixed anything. In case it helps, the project is set up to be a command line executable. The same code works flawlessly on both Linux and Mac OS X. Any help would be appreciated.


Visual Studio Express Editions12  
 
 
Jonathan Caves - MSFT





PostPosted: Visual C++ Express Edition, template link errors Top

The same code works on Linux and Mac OS X But Linux and Mac OS X don't have DLLs. They may shared libraries which not work the same way as a DLL.

Does the executable include the header file

Could you provide a small example that illustrates the problem



 
 
akb825





PostPosted: Visual C++ Express Edition, template link errors Top

Just because the same code is used in Linux and OS X doesn't mean it has to be compiled as a DLL. It can just as easily be compiled as a static library, shared object, dynamic library, or framework by simply changing the compiler command.

I did in fact include the header, otherwise it wouldn't have even compiled. As I said before, I even copied the template's source directly into the file at one point, even though it's pretty much the equivalent of including the file, and it didn't make any difference. I also used #error macros to make sure that the compiler was getting to those places.

Since I'm not at work, I can't really give you an exact example, but the setup of the files is simple enough. In the template's header, I have 2 template classes (a node and a list class), and all the functions are defined in the class definitions. (mainly because for some reason, when I defined the functions outside using the class::function resolution, the compiler would complain that it's illegal to use dllimport for those functions, even though I never used the dllimport macro on any of them) The main source file then includes the header, and uses the list class (*** well as the node class, some) the way you normally would. Nothing really special is going on, which is why I'm baffled as to why it won't link. If you need some more concrete examples, I can post both source files later.

 
 
nobugz





PostPosted: Visual C++ Express Edition, template link errors Top

Please post the linker errors.


 
 
akb825





PostPosted: Visual C++ Express Edition, template link errors Top

Tomorrow I will be able to post the exact errors, since I will be at work. I have 3 unresolved token errors and 17 unresolved external symbol errors, one for each function in the list. (the node class doesn't produce any errors, for some reason) Each one shows the data type I used in the executable in the space for the template data type. (with a bunch of other symbols, which I'm guessing is just name mangling)

If a solution isn't posted by tomorrow, first thing I'll do when I get to work is post the complete source for the template and executable files to see if there's something that Microsoft's compiler just doesn't like in it, as well as the build report. (fortunately the source isn't too long, since the executable is really just a test application)

 
 
akb825





PostPosted: Visual C++ Express Edition, template link errors Top

As promised, here's the code:

the template file:
#ifndef GGUI_LIST_H
#define GGUI_LIST_H

#ifndef NULL
#define NULL 0
#endif

/*
* generic doubly linked list that will be used for many things, and can be used
* freely by the programmer using this library; note that it will use pointers
* to store the objects. That means that if you specify it to use ints, it will
* use int pointers for everything. That way it decreases the overhead of
* copying the data back and forth. (also, it's mainly meant to use larger
* objects and classes, rather than simple things such as ints)
*/

/*
* NOTE: T must have the following operator> function prototype
* bool T::operator>(T &other)
* or
* bool operator>(T &first, T &second)
* and the following operator== prototype
* bool T::operator==(T &other)
* or
* bool operator==(T &first, T &second)
* you could also have it without the references, but it's not recommended
* due to the slowdown
*/


template <class T> class GGUIList;
//the nodes containted by the list
template <class T> class GGUINode
{
friend class GGUIList<T>;
protected:
GGUINode<T> *left;
GGUINode<T> *right;
T *data;

public:
GGUINode<T>(T *data, GGUINode<T> *left, GGUINode<T> *right)
{
this->data = data;
this->left = left;
this->right = right;
if (this->right)
this->right->left = this;
if (this->left)
this->left->right = this;
}

T *getData()
{
return data;
}
GGUINode *getLeft()
{
return left;
}
GGUINode *getRight()
{
return right;
}
//shift left for sorting
void shiftLeft(GGUIList<T> *parentList)
{
if (!this->left)
return;
GGUINode<T> *temp = this->left;

//if this is the end, reconnect to the left node
if (this == parentList->ending)
parentList->ending = this->left;
//if the left node is the beginning, reconnect that
if (this->left == parentList->beginning)
parentList->beginning = this;
//reconnect the left of the right node to the node on the left
if (this->right)
this->right->left = this->left;
//make the left point to the left node's left
if (this->left)
this->left = this->left->left;
//make the left hand's right point to the node on the right
temp->right = this->right;
//make the left hand node's left point to this
temp->left = this;
//reconnect the right side of this node to the one on the left
this->right = temp;
//have the new left point to this
if (this->left)
this->left->right = this;
}

bool operator>(GGUINode &node2)
{
if (!this->data || !node2.data)
return false;
return *this->data > *node2.data;
}

~GGUINode()
{
//data will be deleted from the list if needed
GGUINode<T> *temp = this->right;
if (this->right)
this->right->left = this->left;
if (this->left)
this->left->right = temp;
}
};

//the main list class
template <class T> class GGUIList
{
friend class GGUINode<T>;
protected:
GGUINode<T> *beginning;
GGUINode<T> *ending;
int count;
bool deleteData;

public:
//can choose to delete data when the list is being deleted; default is true
GGUIList<T>(bool deleteDataOnDelete = true)
{
deleteData = deleteDataOnDelete;
beginning = NULL;
ending = NULL;
count = 0;
}

/*
* get or change the behavior of deleting stored items when the nodes are
* deleted
*/
bool deletesDataOnDelete()
{
return deleteData;
}
void setDeletesDataOnDelete(bool deleteDataOnDelete)
{
deleteData = deleteDataOnDelete;
}

//insert method; made virtual in case the user uses a better method to insert
//negative index or 0 means the beginning, >= count means end
virtual void insertItem(T *item, int index = -1)
{
//empty list
if (!count)
{
beginning = new GGUINode<T>(item, NULL, NULL);
ending = beginning;
}
//insert at the beginning
else if (index <= 0)
beginning = new GGUINode<T>(item, NULL, beginning);
//insert at the end
else if (index >= count)
ending = new GGUINode<T>(item, ending, NULL);
//insert somewhere in the beginning
else
{
GGUINode<T> *left;
GGUINode<T> *right;
int cutoff = count/2;
if (index < count/2)
{
right = beginning;
for (int i = 0; i < index; ++i)
right = right->right;
left = right->left;
}
else
{
right = ending;
for (int i = count - 1; i > index; --i)
right = right->left;
left = right->left;
}
new GGUINode<T>(item, left, right);
}
++count;
}
/*
* this is for quick inserting for things that keep track of which node is
* selected, but should be used with caution; it doesn't check to make sure
* that the node is within the list; (if it's the beginning or end node,
* then it will handle it correctly, though) it will insert directly after
* the specified node
*/
virtual void insertItem(T *item, GGUINode<T> *node)
{
if (!node || !count)
insertItem(item);
else if (node == ending)
ending = new GGUINode<T>(item, ending, NULL);
else
new GGUINode<T>(item, node, node->right);
}

/*
* does not implement qsort, but this will be faster if the list is almost
* sorted when you do sort. (ideal for things such as self-sorting tables;
* it uses a insertion-style sort without an extra array, to be exact)
* sublcass if you want to add qsort (made virtual to make it easier on the
* programmer if they do intend to have an alternative sorting method)
*/
virtual void sort()
{
//move up the list, then move back each time, moving the node to the left
//until it can't go left any farther
if (!count)
return;
GGUINode<T> *currentNode = beginning->right;
GGUINode<T> *nextNode;
for (int i = 1; i < count; ++i)
{
nextNode = currentNode->right;
for (int j = i; j > 0; --j)
{
if (*currentNode->left > *currentNode)
currentNode->shiftLeft(this);
else
break;
}
currentNode = nextNode;
}
}

/*
* get method; made virtual in case the user wants to implement a better
* search; returns NULL if the index is out of bound or -1 if the item could
* not be found; note that searching for an item will visit every node that's
* in the list until it is found; searching from an index starts from one
* end and moves in, depending on which end is closer; note that searching
* by item finds the exact item (through equality of pointers)
*/
virtual T *getItem(int index)
{
GGUINode<T> *node;
return (node = getNodeOfItem(index)) node->data : NULL;
}
virtual GGUINode<T> *getNodeOfItem(int index)
{
GGUINode<T> *node;
int cutoff = count/2;
if (index == 0)
return beginning;
else if (index == count - 1)
return ending;
else if (index < 0 || index >= count)
return NULL;
else if (index < count/2)
{
node = beginning;
for (int i = 0; i < index; ++i)
node = node->right;
}
else
{
node = ending;
for (int i = count - 1; i > index; --i)
node = node->left;
}

return node;
}
virtual int indexOfItem(T *item)
{
GGUINode<T> *currentNode = beginning;
int i;
for (i = 0; i < count; ++i)
{
if (currentNode->data != item)
currentNode = currentNode->right;
else
break;
}
return (i < count) i : -1;
}
virtual GGUINode<T> *getNodeOfItem(T *item)
{
GGUINode<T> *currentNode = beginning;
for (int i = 0; i < count; ++i)
{
if (currentNode->data != item)
currentNode = currentNode->right;
else
break;
}
//will automatically be NULL if not found
return currentNode;
}
//same as usual lookup methods, but searches for object equality rather than
//pointer equality; NOTE: may be much slower, but sometimes necessary
virtual int indexOfEquivalentItem(T *item)
{
GGUINode<T> *currentNode = beginning;
int i;
for (i = 0; i < count; ++i)
{
if (currentNode->data && item && *currentNode->data == *item)
break;
else
currentNode = currentNode->right;
}
return (i < count) i : -1;
}
virtual GGUINode<T> *getNodeOfEquivalentItem(T *item)
{
GGUINode<T> *currentNode = beginning;
for (int i = 0; i < count; ++i)
{
if (currentNode->data && item && *currentNode->data == *item)
break;
else
currentNode = currentNode->right;
}
//will automatically be NULL if not found
return currentNode;
}

//delete methods; made virtual in case the user uses a better search method
//to delete the object
virtual bool deleteItem(T *item)
{
GGUINode<T> *node = getNodeOfItem(item);
if (!node)
return false;
if (node == beginning)
beginning = node->right;
if (node == ending)
ending = node->left;
if (deleteData)
delete node->data;
--count;
delete node;
return true;
}
virtual bool deleteEquivalentItem(T *item)
{
GGUINode<T> *node = getNodeOfEquivalentItem(item);
if (!node)
return false;
if (node == beginning)
beginning = node->right;
if (node == ending)
ending = node->left;
if (deleteData)
delete node->data;
--count;
delete node;
return true;
}
virtual bool deleteItem(int index)
{
GGUINode<T> *node = getNodeOfItem(index);
if (!node)
return false;
if (node == beginning)
beginning = node->right;
if (node == ending)
ending = node->left;
if (deleteData)
delete node->data;
--count;
delete node;
return true;
}
//use this rather than just deleting a node yourself, in case it happens
//to be the beginning or end
virtual bool deleteNode(GGUINode<T> *node)
{
if (!node)
return false;
if (node == beginning)
beginning = node->right;
if (node == ending)
ending = node->left;
if (deleteData)
delete node->data;
--count;
delete node;
return true;
}

//node access methods for custom list manipulations
GGUINode<T> *getBeginning()
{
return beginning;
}

GGUINode<T> *getEnding()
{
return ending;
}

int getCount()
{
return count;
}

virtual ~GGUIList()
{
GGUINode<T> *currentNode = beginning, *nextNode;
while (count--)
{
if (deleteData)
delete currentNode->data;
nextNode = currentNode->right;
delete currentNode;
currentNode = nextNode;
}
}
};

#endif

the executable file:
#include <iostream>

#include "gguiContext.h"
#include "gguiList.h"
#include "gguiButton.h"
#include "gguiLabel.h"
#include "gguiColorRect.h"
#include "gguiCheckBox.h"
#include "gguiRadioButton.h"
#include "gguiSlider.h"
#include "gguiTextBox.h"
#include "gguiTable.h"
#include "gguiTableItem.h"
#include "gguiPopUpList.h"
#include "SDL/SDL.h"
#ifndef _WIN32
#include <sys/time.h>
#endif

#ifdef __APPLE__
//#define FONT "/Library/Fonts/Verdana"
#define FONT "/System/Library/Fonts/Helvetica.dfont"
#elif defined(_WIN32)
#define FONT "/WINDOWS/Fonts/GARA.TTF"
#else
#define FONT "/usr/share/fonts/bitstream-vera/Vera.ttf"
#endif

#define DEL 127

const float mainColor[] = {0.4, 0.8, 1, 1};
const float rolloverColor[] = {0.5, 0.9, 0.9, 1};
const float activeColor[] = {0.8, 0.8, 0.6, 1};
const float disabledColor[] = {0.7, 0.9, 1.0, 1};
const float *borderColor = gguiBlack;
const float *textColor = gguiBlack;
const float *highlightedTextColor = gguiWhite;
const float highlightColor[] = {0.2, 0.5, 0.7, 1};
const float deselectedHighlightColor[] = {0.6, 0.6, 0.6, 1};

const char *radioColors[] = {"\e[33m", "\e[34m", "\e[35m"};

int x, y;
int numClicks;

struct TimerCallback
{
void (*callback)(int value);
int value;
double time;
TimerCallback(void (*callbackFunc)(int value), int passedValue, int msecs)
{
callback = callbackFunc;
value = passedValue;
time = msecs/1000.0;
}
bool operator==(TimerCallback &other)
{
return false;
}
bool operator>(TimerCallback &other)
{
return false;
}
};

GGUIList<TimerCallback> *timerList;
double lastTime;

using namespace std;

GGUIContext *globalContext;
GGUITextBox *firstTextBox;

int height;

struct TestTableItem : public GGUITableItem
{
char *text;
TestTableItem(GGUITable *parentTable, GGUIContext *parentContext,
unsigned int ptSize, float width, float height,
const char *text) :
GGUITableItem(parentTable, parentContext, ptSize, width,
height)
{
this->text = strdup(text);
GGUIFont *font = getFont();
font->FaceSize(ptSize);
this->height = font->LineHeight() + 10;
}
void draw()
{
GGUIFont *font = getFont();
glPushMatrix();

if (parentTable->getSelectedItem() == this)
{
if (parentContext->getSelectedDrawable() == parentTable)
glColor4fv(highlightColor);
else
glColor4fv(deselectedHighlightColor);

glBegin(GL_QUADS);

glVertex2f(0, 0);
glVertex2f(width, 0);
glVertex2f(width, height);
glVertex2f(0, height);

glEnd();
}


if (parentTable->getSelectedItem() == this)
glColor4fv(highlightedTextColor);
else
glColor4fv(textColor);

font->FaceSize(ptSize);
glTranslatef(5, 5, 0);
font->Render(text);

glPopMatrix();
}

~TestTableItem()
{
free(text);
}
};

struct TestGUI : public GGUIResponder
{
GGUIButton *testButton;
GGUICheckBox *checkBox;

GGUIRadioButtonMatrix *radioButtons;
GGUIRadioButton *radio1;
GGUIRadioButton *radio2;
GGUIRadioButton *radio3;

GGUISlider *slider;
GGUILabel *sliderLabel;

GGUITextBox *oneLineBox;
GGUITextBox *multiLineBox;

GGUITable *table;

GGUIPopUpList *list;
TestGUI(GGUIContext *context)
{
GGUIDrawable *currentDrawable;
testButton = new GGUIButton(context, 10, 10, "Test", 20, 0);
testButton->setResponder(this);

new GGUILabel(context, 50, 50, "\tHEY!\nThis is\n\ta\t\tTest\n12\t3457\t8", 20, 50);

currentDrawable = new GGUIColorRect(context, 0, 0, 30, 20, gguiRed);
currentDrawable->setDependentDimensions(40, 30, 0, 0);
((GGUIColorRect *)currentDrawable)->setHasBorderColor(false);

checkBox = new GGUICheckBox(context, 0, 10, "Test", 20, 1);
checkBox->setDependentDimensions(100, 0, 0, 0);
checkBox->setResponder(this);

radioButtons = new GGUIRadioButtonMatrix(context);
radioButtons->setResponder(this);
radio1 = radioButtons->insertRadioButton(10, 240, "Test 1", 20);
radio2 = new GGUIRadioButton(radioButtons, 10, 210, "Test 2", 20);
radio3 = radioButtons->insertRadioButton(10, 180, "Test 3", 20);

slider = new GGUISlider(context, 15, 270, 150);
slider->setResponder(this);
sliderLabel = new GGUILabel(context, 195, 270, "0.000", 18);

oneLineBox = new GGUITextBox(context, 0, 40, 200, 0, NULL, 16, true, 40);
oneLineBox->setDependentDimensions(220, 0, 0, 0);
oneLineBox->setResponder(this);
firstTextBox = oneLineBox;

multiLineBox = new GGUITextBox(context, 0, 80, 300, 300, "Testing", 14,
false, 30);
multiLineBox->setDependentDimensions(320, 0, 0, 0);

table = new GGUITable(context, 0, 80, 300, 300);
table->setDependentDimensions(320, 0, 0, 0);
table->setVisible(false);
table->appendItem(new TestTableItem(table, context, 14, 0, 0, "This"));
table->appendItem(new TestTableItem(table, context, 14, 0, 0, "is"));
table->appendItem(new TestTableItem(table, context, 14, 0, 0, "a"));
table->appendItem(new TestTableItem(table, context, 14, 0, 0, "test"));

list = new GGUIPopUpList(context, 0, 400, 200, 14, 7);
list->setResponder(this);
list->setDependentDimensions(320, 0, 0, 0);
list->appendItem("This");
list->appendItem("is");
list->appendItem("a");
list->appendItem("test");
list->appendItem("and");
list->appendItem("it");
list->appendItem("will");
list->appendItem("keep");
list->appendItem("on");
list->appendItem("going");
list->appendItem("until");
list->appendItem("the");
list->appendItem("end");
}
void action(GGUIDrawable *sender)
{
if (sender == testButton)
{
printf("\e[36mTest button pressed.\e[0m\n");
const char *tempText = testButton->getText();
if (!strcmp(tempText, "Test"))
{
testButton->setText("Switched!", 2);
testButton->setFontSize(24);
checkBox->setEnabled(false);
radioButtons->setVisible(false);
}
else
{
testButton->setText("Test", 0);
testButton->setFontSize(20);
checkBox->setEnabled(true);
radioButtons->setVisible(true);
}
table->insertItemAfterSelection(new TestTableItem(table, globalContext,
14, 0, 0, "test"));
}
else if (sender == checkBox)
{
if (checkBox->isSelected())
{
radioButtons->setEnabled(false);
printf("\e[32mThe check box is selected.\e[0m\n");
slider->setVertical(true);
slider->setLocationX(10);
slider->setLocationY(275);
sliderLabel->setLocationX(40);
table->setVisible(true);
multiLineBox->setVisible(false);
}
else
{
radioButtons->setEnabled(true);
printf("\e[31mhe check box is not selected.\e[0m\n");
slider->setVertical(false);
slider->setLocationX(15);
slider->setLocationY(270);
sliderLabel->setLocationX(195);
table->setVisible(false);
multiLineBox->setVisible(true);
}
}
else if (sender == radioButtons)
printf("%sIndex %d selected.\e[0m\n", radioColors[radioButtons->selectedRadioButtonIndex()],
radioButtons->selectedRadioButtonIndex());
else if (sender == oneLineBox)
printf("Enter pressed in the one-line box.\n");
else if (sender == list)
printf("You selected \"%s\"\n", list->getSelectedItem());
}
void changed(GGUIDrawable *sender)
{
if (sender == slider)
{
char temp[11];
sprintf(temp, "%01.3f", slider->getValue());
sliderLabel->setText(temp);
}
}
};

TestGUI *testResponder;

//functions to satisfy gguiInit
void setCursor(int cursorType)
{
}

int keyModifiers()
{
int modifier = SDL_GetModState();

int retval = 0;
if (modifier & KMOD_SHIFT)
retval |= GGUI_SHIFT_KEY;
if (modifier & KMOD_CTRL)
retval |= GGUI_CTRL_KEY;
if (modifier & KMOD_META)
retval |= GGUI_COMMAND_KEY;
if (modifier & KMOD_ALT)
retval |= GGUI_OPTION_KEY;
if (modifier & KMOD_CAPS)
retval |= GGUI_CAPS_KEY;

return retval;
}

void mousePressed(int button, int state, int x, int y)
{
switch (button)
{
case SDL_BUTTON_LEFT:
button = GGUI_LEFT_BUTTON;
break;
case SDL_BUTTON_MIDDLE:
button = GGUI_MIDDLE_BUTTON;
break;
case SDL_BUTTON_RIGHT:
button = GGUI_RIGHT_BUTTON;
break;
case SDL_BUTTON_WHEELUP:
globalContext->scrollWheel(GGUI_WHEEL_UP, x, y);
return;
case SDL_BUTTON_WHEELDOWN:
globalContext->scrollWheel(GGUI_WHEEL_DOWN, x, y);
return;
}
if (state == SDL_PRESSED)
{
++numClicks;
globalContext->mouseDown(button, x, y);
}
else
{
--numClicks;
globalContext->mouseUp(button, x, y);
}
}

void mouseMove(int x, int y)
{
globalContext->mouseMove(x, y);
}

void mouseDrag(int x, int y)
{
globalContext->mouseDrag(x, y);
}

void keyDown(int key, int x, int y)
{
int modifiers = keyModifiers();
if (key == SDLK_NUMLOCK || key == SDLK_CAPSLOCK || key == SDLK_RSHIFT ||
key == SDLK_LSHIFT || key == SDLK_RCTRL || key == SDLK_LCTRL ||
key == SDLK_RALT || key == SDLK_LALT || key == SDLK_RMETA ||
key == SDLK_LMETA || key == SDLK_LSUPER || key == SDLK_RSUPER)
return;
if (modifiers & GGUI_SHIFT_KEY || modifiers & GGUI_CAPS_KEY)
{
if (key >= 'a' && key <='z')
key += 'A' - 'a';
if (modifiers & GGUI_SHIFT_KEY)
{
switch (key)
{
case '`':
key = '~';
break;
case '1':
key = '!';
break;
case '2':

break;
case '3':
key = '#';
break;
case '4':
key = '$';
break;
case '5':
key = '%';
break;
case '6':
key = '^';
break;
case '7':
key = '&';
break;
case '8':
key = '*';
break;
case '9':
key = '(';
break;
case '0':
key = ')';
break;
case '-':
key = '_';
break;
case '=':
key = '+';
break;
case '[':
key = '{';
break;
case ']':
key = '}';
break;
case '\\':
key = '|';
break;
case ';':
key = ':';
break;
case '\'':
key = '\"';
break;
case ',':
key = '<';
break;
case '.':
key = '>';
break;
case '/':
key = ' ';
break;
}
}
}
if (key == 'q' && keyModifiers() ==
#ifdef __APPLE__
GGUI_COMMAND_KEY
#else
GGUI_CTRL_KEY
#endif
)
exit(0);
else if (key == '\t' && !globalContext->getSelectedDrawable())
globalContext->setSelectedDrawable(firstTextBox);
else
globalContext->keyDown(key, x, y);
}

void keyUp(int key, int x, int y)
{
if (key == SDLK_NUMLOCK || key == SDLK_CAPSLOCK || key == SDLK_RSHIFT ||
key == SDLK_LSHIFT || key == SDLK_RCTRL || key == SDLK_LCTRL ||
key == SDLK_RALT || key == SDLK_LALT || key == SDLK_RMETA ||
key == SDLK_LMETA || key == SDLK_LSUPER || key == SDLK_RSUPER)
return;
globalContext->keyUp(key, x, y);
}

void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glLoadIdentity();
glPushMatrix();

globalContext->draw();

glPopMatrix();
SDL_GL_SwapBuffers();
}

void resize(int x, int y)
{
glViewport(0, 0, x, y);
height = y;
globalContext->resize(x, y);
display();
}

void setup()
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadeModel(GL_SMOOTH);
glDisable(GL_CULL_FACE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_POINT_SMOOTH);
glClearColor(1, 1, 1, 1);
}

int getKey(SDL_KeyboardEvent *keyboard)
{
int key = keyboard->keysym.sym;
switch (key)
{
case SDLK_F1:
key = GGUI_F1_KEY;
break;
case SDLK_F2:
key = GGUI_F2_KEY;
break;
case SDLK_F3:
key = GGUI_F3_KEY;
break;
case SDLK_F4:
key = GGUI_F4_KEY;
break;
case SDLK_F5:
key = GGUI_F5_KEY;
break;
case SDLK_F6:
key = GGUI_F6_KEY;
break;
case SDLK_F7:
key = GGUI_F7_KEY;
break;
case SDLK_F8:
key = GGUI_F8_KEY;
break;
case SDLK_F9:
key = GGUI_F9_KEY;
break;
case SDLK_F10:
key = GGUI_F10_KEY;
break;
case SDLK_F11:
key = GGUI_F11_KEY;
break;
case SDLK_F12:
key = GGUI_F12_KEY;
break;
case SDLK_LEFT:
key = GGUI_LEFT_KEY;
break;
case SDLK_RIGHT:
key = GGUI_RIGHT_KEY;
break;
case SDLK_UP:
key = GGUI_UP_KEY;
break;
case SDLK_DOWN:
key = GGUI_DOWN_KEY;
break;
case SDLK_PAGEUP:
key = GGUI_PAGE_UP_KEY;
break;
case SDLK_PAGEDOWN:
key = GGUI_PAGE_DOWN_KEY;
break;
case SDLK_HOME:
key = GGUI_HOME_KEY;
break;
case SDLK_END:
key = GGUI_END_KEY;
break;
case SDLK_INSERT:
key = GGUI_INSERT_KEY;
break;
case '\r':
key = '\n';
break;
}
return key;
}

void pollEvents()
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_KEYDOWN:
keyDown(getKey((SDL_KeyboardEvent *)&event), x, y);
break;
case SDL_KEYUP:
keyUp(getKey((SDL_KeyboardEvent *)&event), x, y);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
{
SDL_MouseButtonEvent *mouse = (SDL_MouseButtonEvent *)&event;
x = mouse->x;
y = height - mouse->y;
mousePressed(mouse->button, mouse->state, x, y);
break;
}
case SDL_MOUSEMOTION:
{
SDL_MouseMotionEvent *mouse = (SDL_MouseMotionEvent *)&event;
x = mouse->x;
y = height - mouse->y;
if (mouse->state)
mouseDrag(x, y);
else
mouseMove(x, y);
break;
}
case SDL_VIDEORESIZE:
{
SDL_ResizeEvent *newSize = (SDL_ResizeEvent *)&event;
resize(newSize->w, newSize->h);
}
case SDL_QUIT:
exit(0);
break;
}
}
}

void addTimer(unsigned int msecs, void (*callback)(int value), int value)
{
timerList->insertItem(new TimerCallback(callback, value, msecs));
}

void exitFunc()
{
delete globalContext;
delete timerList;
SDL_Quit();
}

int main(int argc, char **argv)
{
SDL_Init(SDL_INIT_VIDEO);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, true);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_SetVideoMode(640, 480, 32, SDL_OPENGL | SDL_RESIZABLE);
SDL_WM_SetCaption("TestGUI", NULL);
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
timerList = new GGUIList<TimerCallback>;

struct timeval time;
double currentTime;
gettimeofday(&time, NULL);
lastTime = time.tv_sec + time.tv_usec*1e-6;

setup();

gguiInit(addTimer, setCursor, keyModifiers);
globalContext = new GGUIContext(640, 480, FONT, mainColor, rolloverColor,
activeColor, disabledColor,borderColor, textColor, highlightedTextColor,
highlightColor, deselectedHighlightColor);
TestGUI test(globalContext);
testResponder = &test;

atexit(exitFunc);
resize(640, 480);
while (true)
{
pollEvents();
if (globalContext->needsRedisplay())
display();

//handle the timers
gettimeofday(&time, NULL);
currentTime = time.tv_sec + time.tv_usec*1e-6;
if (timerList->getCount())
{
GGUINode<TimerCallback> *node = timerList->getBeginning(), *nextNode;
TimerCallback *currentCallback;
while (node)
{
nextNode = node->getRight();
currentCallback = node->getData();
currentCallback->time -= currentTime - lastTime;
if (currentCallback->time <= 0)
{
currentCallback->callback(currentCallback->value);
timerList->deleteNode(node);
}
node = nextNode;
}
}
lastTime = currentTime;
}

return 0;
}


Her's the exact linking errors
Linking...



















TestGUI.obj : error LNK2019: unresolved external symbol

 
 
nobugz





PostPosted: Visual C++ Express Edition, template link errors Top



#include "stdafx.h"
#include <iostream>
#include "gguiList.h"
#ifndef _WIN32
#include <sys/time.h>
#endif

struct TimerCallback
{
void (*callback)(int value);
int value;
double time;
TimerCallback(void (*callbackFunc)(int value), int passedValue, int msecs)
{
callback = callbackFunc;
value = passedValue;
time = msecs/1000.0;
}
bool operator==(TimerCallback &other)
{
return false;
}
bool operator>(TimerCallback &other)
{
return false;
}
};

GGUIList<TimerCallback> *timerList;
double lastTime;
double currentTime;

void addTimer(unsigned int msecs, void (*callback)(int value), int value)
{
timerList->insertItem(new TimerCallback(callback, value, msecs));
}

int _tmain(int argc, _TCHAR* argv[])
{
timerList = new GGUIList<TimerCallback>;
if (timerList->getCount())
{
GGUINode<TimerCallback> *node = timerList->getBeginning(), *nextNode;
TimerCallback *currentCallback;
while (node)
{
nextNode = node->getRight();
currentCallback = node->getData();
currentCallback->time -= currentTime - lastTime;
if (currentCallback->time <= 0)
{
currentCallback->callback(currentCallback->value);
timerList->deleteNode(node);
}
node = nextNode;
}
}
lastTime = currentTime;
return 0;
}



 
 
akb825





PostPosted: Visual C++ Express Edition, template link errors Top

I forgot to mention that I did get it to compile by taking out all the template code. ;)

Here's a link to a project that has the TestGUI.cpp file and all the headers necessary, as well as all the dlls and libs necessary to get it to work. I also included the test program that I used to test my lsit: TestList.cpp, which compiles just fine. http://akb825.com/downloads/TestGUI.zip Thanks for your help.

 
 
akb825





PostPosted: Visual C++ Express Edition, template link errors Top

I've narrowed it down to this set of lines in one of my header files:
#ifdef _MSC_VER
#ifdef GGUI_COMPILE
#define GGUI_EXPORT __declspec(dllexport)
#else
#define GGUI_EXPORT __declspec(dllimport)
#endif
#else
#define GGUI_EXPORT
#endif

I take it to mean that it doesn't like the precense of __declspec(dllimport), even though I don't use it anywhere in my template code. Any suggestions about this