 |
| Author |
Message |
akb825

|
Posted: 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 Editions24
|
| |
|
| |
 |
Jonathan Caves - MSFT

|
Posted: 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

|
Posted: 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

|
Posted: Visual C++ Express Edition, template link errors |
Top |
Please post the linker errors.
|
| |
|
| |
 |
akb825

|
Posted: 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

|
Posted: 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':
key = '@';
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 LNK2028: unresolved token (0A0001CD) "public:
__thiscall GGUIList<struct TimerCallback>::GGUIList<struct
TimerCallback>(bool)" ( 0 $GGUIList@UTimerCallback@@@@$$FQAE@_N@Z)
referenced in function "extern "C" int __cdecl SDL_main(int,char * *
const)" ( SDL_main@@$$J0YAHHQAPAD@Z)
TestGUI.obj : error LNK2028: unresolved token (0A0001DB) "public: class
GGUINode<struct TimerCallback> * __thiscall GGUIList<struct
TimerCallback>::getBeginning(void)"
( getBeginning@ $GGUIList@UTimerCallback@@@@$$FQAEPAV $GGUINode@UTimerCallback@@@@XZ)
referenced in function "extern "C" int __cdecl SDL_main(int,char * *
const)" ( SDL_main@@$$J0YAHHQAPAD@Z)
TestGUI.obj : error LNK2028: unresolved token (0A0001DC) "public: int
__thiscall GGUIList<struct TimerCallback>::getCount(void)"
( getCount@ $GGUIList@UTimerCallback@@@@$$FQAEHXZ) referenced in
function "extern "C" int __cdecl SDL_main(int,char * * const)"
( SDL_main@@$$J0YAHHQAPAD@Z)
TestGUI.obj : error LNK2019: unresolved external symbol "public: class
GGUINode<struct TimerCallback> * __thiscall GGUIList<struct
TimerCallback>::getBeginning(void)"
( getBeginning@ $GGUIList@UTimerCallback@@@@$$FQAEPAV $GGUINode@UTimerCallback@@@@XZ)
referenced in function "extern "C" int __cdecl SDL_main(int,char * *
const)" ( SDL_main@@$$J0YAHHQAPAD@Z)
TestGUI.obj : error LNK2019: unresolved external symbol "public: int
__thiscall GGUIList<struct TimerCallback>::getCount(void)"
( getCount@ $GGUIList@UTimerCallback@@@@$$FQAEHXZ) referenced in
function "extern "C" int __cdecl SDL_main(int,char * * const)"
( SDL_main@@$$J0YAHHQAPAD@Z)
TestGUI.obj : error LNK2019: unresolved external symbol "public:
__thiscall GGUIList<struct TimerCallback>::GGUIList<struct
TimerCallback>(bool)" ( 0 $GGUIList@UTimerCallback@@@@$$FQAE@_N@Z)
referenced in function "extern "C" int __cdecl SDL_main(int,char * *
const)" ( SDL_main@@$$J0YAHHQAPAD@Z)
TestGUI.obj : error LNK2001: unresolved external symbol "public:
virtual void __thiscall GGUIList<struct
TimerCallback>::insertItem(struct TimerCallback *,class
GGUINode<struct TimerCallback> *)"
( insertItem@ $GGUIList@UTimerCallback@@@@UAEXPAUTimerCallback@@PAV $GGUINode@UTimerCallback@@@@@Z)
TestGUI.obj : error LNK2001: unresolved external symbol "public:
virtual void __thiscall GGUIList<struct
TimerCallback>::insertItem(struct TimerCallback *,int)"
( insertItem@ $GGUIList@UTimerCallback@@@@UAEXPAUTimerCallback@@H@Z)
TestGUI.obj : error LNK2001: unresolved external symbol "public:
virtual void __thiscall GGUIList<struct
TimerCallback>::sort(void)"
( sort@ $GGUIList@UTimerCallback@@@@UAEXXZ)
TestGUI.obj : error LNK2001: unresolved external symbol "public:
virtual struct TimerCallback * __thiscall GGUIList<struct
TimerCallback>::getItem(int)"
( getItem@ $GGUIList@UTimerCallback@@@@UAEPAUTimerCallback@@H@Z)
TestGUI.obj : error LNK2001: unresolved external symbol "public:
virtual class GGUINode<struct TimerCallback> * __thiscall
GGUIList<struct TimerCallback>::getNodeOfItem(struct
TimerCallback *)"
( getNodeOfItem@ $GGUIList@UTimerCallback@@@@UAEPAV $GGUINode@UTimerCallback@@@@PAUTimerCallback@@@Z)
TestGUI.obj : error LNK2001: unresolved external symbol "public:
virtual class GGUINode<struct TimerCallback> * __thiscall
GGUIList<struct TimerCallback>::getNodeOfItem(int)"
( getNodeOfItem@ $GGUIList@UTimerCallback@@@@UAEPAV $GGUINode@UTimerCallback@@@@H@Z)
TestGUI.obj : error LNK2001: unresolved external symbol "public:
virtual int __thiscall GGUIList<struct
TimerCallback>::indexOfItem(struct TimerCallback *)"
( indexOfItem@ $GGUIList@UTimerCallback@@@@UAEHPAUTimerCallback@@@Z)
TestGUI.obj : error LNK2001: unresolved external symbol "public:
virtual int __thiscall GGUIList<struct
TimerCallback>::indexOfEquivalentItem(struct TimerCallback *)"
( indexOfEquivalentItem@ $GGUIList@UTimerCallback@@@@UAEHPAUTimerCallback@@@Z)
TestGUI.obj : error LNK2001: unresolved external symbol "public:
virtual class GGUINode<struct TimerCallback> * __thiscall
GGUIList<struct TimerCallback>::getNodeOfEquivalentItem(struct
TimerCallback *)"
( getNodeOfEquivalentItem@ $GGUIList@UTimerCallback@@@@UAEPAV $GGUINode@UTimerCallback@@@@PAUTimerCallback@@@Z)
TestGUI.obj : error LNK2001: unresolved external symbol "public:
virtual bool __thiscall GGUIList<struct
TimerCallback>::deleteItem(int)"
( deleteItem@ $GGUIList@UTimerCallback@@@@UAE_NH@Z)
TestGUI.obj : error LNK2001: unresolved external symbol "public:
virtual bool __thiscall GGUIList<struct
TimerCallback>::deleteItem(struct TimerCallback *)"
( deleteItem@ $GGUIList@UTimerCallback@@@@UAE_NPAUTimerCallback@@@Z)
TestGUI.obj : error LNK2001: unresolved external symbol "public:
virtual bool __thiscall GGUIList<struct
TimerCallback>::deleteEquivalentItem(struct TimerCallback *)"
( deleteEquivalentItem@ $GGUIList@UTimerCallback@@@@UAE_NPAUTimerCallback@@@Z)
TestGUI.obj : error LNK2001: unresolved external symbol "public:
virtual bool __thiscall GGUIList<struct
TimerCallback>::deleteNode(class GGUINode<struct
TimerCallback> *)"
( deleteNode@ $GGUIList@UTimerCallback@@@@UAE_NPAV $GGUINode@UTimerCallback@@@@@Z)
TestGUI.obj : error LNK2019: unresolved external symbol
|
| |
|
| |
 |
nobugz

|
Posted: Visual C++ Express Edition, template link errors |
Top |
I
narrowed it down to the code below to get it to compile with the
missing header files. Try it yourself. I didn't get any
compile nor linker errors. Email me the entire project if you
want me to diagnose it. |Monkeytail| = @
#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

|
Posted: 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

|
Posted: 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
|
| |
|
| |
 |
| |
|