I've been trying not to post about my competition project for help since I felt it would be inappropriate, but this is one of the few problems I haven't been able to fix after trying for quite a while. I could fix the rest of the problems through debugging and through what people on this forum have told me before. I don't have enough experience in linking to fix my current problem.
In general, my problem is that I've been trying to reorganize the project I and my group are working on into separate project files. Everything was working perfectly fine before, but now I'm facing the wrath of undefined reference errors when I try to call my DLL functions.
I have them declared and included in the central header file here :
Code:
/* DLL functions */
typedef void ( * t_wait )( int milliseconds, const int frames_per_seconds );
typedef clock_t ( * ft_timer )( int command, t_timer * timer_object ); /* clock_t is usually defined as long */
typedef void ( * t_SDL_errorexit )( const char * message );
typedef SDL_Surface * ( * t_load_image )( char * image_path, unsigned is_transparent );
typedef Mix_Music * ( * t_load_music )( const char * file_name );
typedef void ( * t_play_music )( Mix_Music * game_music, int loops );
typedef Mix_Music * ( * t_start_music )( const char * file_name, int loops );
typedef Mix_Chunk * ( * t_load_sound )( const char * file_name );
typedef void ( * t_play_sound )( int channel, Mix_Chunk * game_music, int loops );
typedef int ( * t_character_to_digit )( char value );
typedef int ( * t_number_of_value_places )( int value );
typedef char * ( * t_convert_number_to_string )( int value, int * value_places );
typedef projectile * ( * t_create ) ( );
typedef void ( * t_print_list )( projectile * head );
typedef projectile * ( * t_free_list )( projectile * head );
typedef projectile * ( * t_add )( projectile * head, int h, int w, int x, int y, int speed );
typedef projectile * ( * t_delete_node )( projectile * head, projectile * node );
typedef maze_level * ( * t_create_level )( );
typedef maze_level * ( * t_add_level )( maze_level * head, int * maze_data, const int w, const int h, const int array_size );
typedef void ( * t_free_level_list )( maze_level * head );
typedef void ( * t_print_maze_list )( maze_level * head );
typedef maze_level * ( * t_delete_level )( maze_level * head, maze_level * node );
typedef FILE * ( * t_loadfile_RW )( const char * file_name );
typedef char * ( * t_read_file )( FILE * target_file, int * bytes_received );
typedef maze_level * ( * t_load_level_data )( const char * file_name );
/* Function pointers to imported DLL functions */
extern t_wait wait;
extern ft_timer timer;
extern t_SDL_errorexit SDL_errorexit;
extern t_load_image load_image;
extern t_load_music load_music;
extern t_play_music play_music;
extern t_start_music start_music;
extern t_load_sound load_sound;
extern t_play_sound play_sound;
extern t_character_to_digit character_to_digit;
extern t_number_of_value_places number_of_value_places;
extern t_convert_number_to_string convert_number_to_string;
extern t_create create;
extern t_print_list print_list;
extern t_free_list free_list;
extern t_add add;
extern t_delete_node delete_node;
extern t_create_level create_level;
extern t_add_level add_level;
extern t_free_level_list free_level_list;
extern t_print_maze_list print_maze_list;
extern t_delete_level delete_level;
extern t_loadfile_RW loadfile_RW;
extern t_read_file read_file;
extern t_load_level_data load_level_data;
Then I have them imported here :
Code:
/* ******************************************************** */
/* ********* win_error( char *, bool ) ********* */
/* ******************************************************** */
/* - Displays a GUI for a windows specific error message, */
/* pass true to it to have it exit the program, pass false */
/* to have it continue */
/* ******************************************************** */
extern void win_error( char * message, bool is_exit )
{
/* Note : win_error uses the Win32 Api */
/* ********************************** */
char buffer[BUFSIZ] = { 0 }; /* This is the buffer where the error message is stored from the FormatMessage( )
function.
*/
DWORD error_code = GetLastError( ); /* GetLastError( ) returns the last system error code */
/* Formats an error message from the system */
FormatMessage
(
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
error_code,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
( LPTSTR ) buffer,
BUFSIZ,
NULL
);
MessageBox( NULL, buffer, message, MB_ICONWARNING | MB_OK ); /* Shows the user a message box with the message */
if ( is_exit ) exit( error_code );
return;
}
/* ******************************************************** */
/* ********* dll_functions_init( game_data * ) ********* */
/* ******************************************************** */
/* - Imports any functions we need to use from our DLL */
/* ******************************************************** */
static void dll_functions_init( game_data * game )
{
/* Note : DLL_functions_init uses the Win32 Api */
/* ******************************************** */
/* Load the DLL dynamically */
if ( !( game->game_dll = LoadLibrary( "game_lib_dynamic.dll" ) ) )
win_error( ( char * )"Loading DLL", true );
/* Get the addresses of our functions for use in the game */
if ( !( wait = ( t_wait )GetProcAddress( game->game_dll, "wait" ) ) )
win_error( ( char * )"wait( )", true );
if ( !( timer = ( ft_timer )GetProcAddress( game->game_dll, "timer" ) ) )
win_error( ( char * )"timer( )", true );
if ( !( SDL_errorexit = ( t_SDL_errorexit )GetProcAddress( game->game_dll, "SDL_errorexit" ) ) )
win_error( ( char * )"SDL_errorexit( )", true );
if ( !( load_image = ( t_load_image )GetProcAddress( game->game_dll, "load_image" ) ) )
win_error( ( char * )"load_image( )", true );
if ( !( load_music = ( t_load_music )GetProcAddress( game->game_dll, "load_music" ) ) )
{
win_error( ( char * )"load_music( ) ( warning : no music will be played )", false );
game->sound_data.invalid_music_functions = true;
}
if ( !( play_music = ( t_play_music )GetProcAddress( game->game_dll, "play_music" ) ) )
{
win_error( ( char * )"play_image( ) ( warning : no music will be played )", false );
game->sound_data.invalid_music_functions = true;
}
if ( !( start_music = ( t_start_music )GetProcAddress( game->game_dll, "start_music" ) ) )
{
win_error( ( char * )"start_music( ) ( warning : no music will be played )", true );
game->sound_data.invalid_music_functions = true;
}
if ( !( load_sound = ( t_load_sound )GetProcAddress( game->game_dll, "load_sound" ) ) )
{
win_error( ( char * )"load_sound( ) ( warning : no sounds will be played )", false );
game->sound_data.invalid_sound_functions = true;
}
if ( !( play_sound = ( t_play_sound )GetProcAddress( game->game_dll, "play_sound" ) ) )
{
win_error( ( char * )"play_sound( ) ( warning : no sounds will be played )", true );
game->sound_data.invalid_sound_functions = true;
}
if ( !( character_to_digit = ( t_character_to_digit )GetProcAddress( game->game_dll, "character_to_digit" ) ) )
win_error( ( char * )"character_to_digit( )", true );
if ( !( number_of_value_places = ( t_number_of_value_places )GetProcAddress( game->game_dll, "number_of_value_places" ) ) )
win_error( ( char * )"number_of_value_places( )", true );
if ( !( convert_number_to_string = ( t_convert_number_to_string )GetProcAddress( game->game_dll, "convert_number_to_string" ) ) )
win_error( ( char * )"convert_number_to_string( )", true );
if ( !( create = ( t_create )GetProcAddress( game->game_dll, "create" ) ) )
win_error( ( char * )"create( )", false );
if ( !( print_list = ( t_print_list )GetProcAddress( game->game_dll, "print_list" ) ) )
win_error( ( char * )"print_list( )", false );
if ( !( free_list = ( t_free_list )GetProcAddress( game->game_dll, "free_list" ) ) )
win_error( ( char * )"free_list( )", false );
if ( !( add = ( t_add )GetProcAddress( game->game_dll, "add" ) ) )
win_error( ( char * )"add( )", false );
if ( !( delete_node = ( t_delete_node )GetProcAddress( game->game_dll, "delete_node" ) ) )
win_error( ( char * )"delete_node( )", false );
if ( !( create_level = ( t_create_level )GetProcAddress( game->game_dll, "create_level" ) ) )
win_error( ( char * )"create_level( )", true );
if ( !( add_level = ( t_add_level )GetProcAddress( game->game_dll, "add_level" ) ) )
win_error( ( char * )"add_level( )", true );
if ( !( free_level_list = ( t_free_level_list )GetProcAddress( game->game_dll, "free_level_list" ) ) )
win_error( ( char * )"free_level_list( )", true );
if ( !( print_maze_list = ( t_print_maze_list )GetProcAddress( game->game_dll, "print_maze_list" ) ) )
win_error( ( char * )"print_maze_list( )", true );
if ( !( delete_level = ( t_delete_level )GetProcAddress( game->game_dll, "delete_level" ) ) )
win_error( ( char * )"delete_level( )", true );
if ( !( loadfile_RW = ( t_loadfile_RW )GetProcAddress( game->game_dll, "loadfile_RW" ) ) )
win_error( ( char * )"loadfile_RW( )", true );
if ( !( read_file = ( t_read_file )GetProcAddress( game->game_dll, "read_file" ) ) )
win_error( ( char * )"read_file( )", true );
if ( !( load_level_data = ( t_load_level_data )GetProcAddress( game->game_dll, "load_level_data" ) ) )
win_error( ( char * )"load_level_data( )", true );
return;
}
This doesn't work, as my compiler sees it that I am trying to call invalid functions, whereas I have made sure to import the functions before calling. Obviously my compiler can't tell that, and is trying to protect me from calling them. I tried re-reading one of my C book's chapters on multiple source files, but it didn't help. It didn't talk about dynamic linking and sharing imported functions.
Any help is appreciated.
Extra notes :
The source files are compiled as C++, but I'm using C-style code instead of true C++ code.
Obviously I'm using Windows style DLL linking, but if the only ways to share imported functions are non-standard, please only post ways that will work on as low as Windows XP.
I have tried to statically link them before, but that led to a problem that I posted a while back. Which led me to dynamically linking, which was problem-free until I separated my code into separate files.