Hello. I have been trying to seperate a little skeleton program into different source files, but I keep getting a linking error...

DirectX.obj : error LNK2001: unresolved external symbol _WinMain@16

I know what the error means, I just don't know how to fix it. I tried searching on the forum, but I couldn't find an example of someone putting WinMain and WinProc in seperate files outside the main program. I would really appreciate it if someone could take a look at the code (Maybe a total of 100 lines) and tell me what I am doing wrong. Thanks a lot for any help.
Posted on 2001-10-28 19:52:36 by AlexEiffel
Hi

here is our (Hostile Encounter) testing pad main programm.
its TASM oriented but it works the same for MASM, just ignore the TASM stuff :)

There are lots of things here (its a big testing pad) but you can see how we split our project into multiple files in the includes section

I was going to give this game making testing pad away for free in my RTS tutorials anyway...until then



;********************************************
;
; jocxxx.ASM for TESTING
;
;********************************************

; Assembler specific instructions for 32 bit ASM code

.386 ; minimum processor needed :)

;================================
; TASM stuff
;================================
locals
nosmart
nojumps


;===========================================
;
; FLAT memory model and
; STDCALL calling conventions
;
; used for:
;======================
; all segments default to 32 bits
; all called procedures must clear the stack before exit
; params are pushed in right to left order (reverse of reading)
;===========================================

.model flat, STDCALL
;==================================================
; TASM stuff
; activates a lots of MASM styles and gadgets
; like @@: temp labels
;==================================================
quirks
masm51

;==========================================
; ALL CODE IS CASE SENZITIVE!
; win32api is anyway
; option given directly to assembler: /ml
;
; below option is for MASM only
; option casemap :none
;==========================================


;*****************************************************
; ALL LIBS WE USE TO LINK ARE HERE
;
; can also be given to linker comandline
; at link time, but comandline has a fixed length
; not funny if u link to many libs
; also much easy to keep track of them here :)
;******************************************************

includelib .\libs\import32.lib
includelib .\libs\ddraw.lib
includelib .\libs\dinput.lib
includelib .\libs\dsound.lib
includelib .\libs\dxguid.lib
includelib .\libs\dplayx.lib





;---------------------------------------------------------------------
; 1. szText
; A macro to insert TEXT into the code section for convenient and
; more intuitive coding of functions that use byte data as text.
;---------------------------------------------------------------------
szText MACRO Name, Text:VARARG
LOCAL lbl
jmp lbl
Name db Text,0
lbl:
ENDM



;***********************************************
; INCLUDES START HERE
;***********************************************

;----------------------------------------------
; Win 32 Stuff
;----------------------------------------------
include .\win32stuff\win32api_constants.asm
;--------------------------------------------
; most API external functions declared here
;--------------------------------------------
include .\win32stuff\extern.inc

include .\win32stuff\win_main_setup.asm
include .\win32stuff\win_main_callback.asm
;----------------------------------------------------
; Multi Threading stuff
;----------------------------------------------------
include .\threads\thread_flip.asm
include .\threads\thread_paint.asm
;-------------------------------
; Clean Up
;--------------------------------
include .\cleanup\ExitGame.asm


;-------------------------------------------------------
; DIRECT DRAW FILES
;-------------------------------------------------------
include .\ddraw\Direct_Draw_Include.asm
INCLUDE .\ddraw\DIRECT_DRAW_INIT.ASM
INCLUDE .\ddraw\DIRECT_DRAW_CORE.ASM
;--------------------------------------------------------
; DIRECT INPUT FILES
;--------------------------------------------------------
include .\dinput\direct_input_include.asm
include .\dinput\direct_input_init.asm
;---------------------------------------------------------
; direct sound structures and ecuates are here
;---------------------------------------------------------
include .\dsound\direct_sound_include.asm

;-------------------------------------------
; UTILITY FUNCTIONS
;-------------------------------------------
include .\utils\UTIL.ASM
include .\utils\bmps_loops.asm

;-------------------------------------------------
; MMX equates and macros for TASM
; just in case we will ever use them
;-------------------------------------------------
; .\utils\include ibmmx.inc

;------------------------------------
; GraFiX
;------------------------------------
include .\gfx\util_gfx.asm
include .\gfx\colors.asm
include .\gfx\paint_text.asm
include .\gfx\paint_text001.asm
include .\gfx\paint_manually.asm
include .\gfx\paint_bground.asm

;-------------------------------------------------
; Lightening
;-------------------------------------------------
include .\fulger\draw_line.asm
include .\fulger\draw_fulger.asm

;-------------------------------------------------
; INTRO
;-------------------------------------------------
include .\gfx\paint_intro.asm
;-------------------------------------------------
; Keyboard and Mouse
;-------------------------------------------------
include .\mouse\mouse.asm

include .\keyboard\keyboard.asm
include .\keyboard\edit_line.asm


;============================================
;RLE TEST
;============================================
include .\rle\rle_main.asm

;------------------------------------
; Loads of bitmaps, sounds etc
;------------------------------------
include .\loads\load_bmp_fonts.asm
include .\loads\load_bmp_galaxy.asm



;------------------------------------
; GUI Tests
;------------------------------------
include .\gui\gui_main.asm

;*******************************************************
; END of INCLUDES
;*******************************************************



;===================================================
; some main vars for game and application
;===================================================
.data
contor dd 0 ; main frame counter
game_is_on dd 0
surface_is_lost dd 0 ;we have to restore
game_is_paused dd 0 ;no moving
;---------------------------------------------
; 1=stop the windows msg loop
;---------------------------------------------
flag_no_messages dd 0
.code


;*********************************************
; MAIN PROGRAM ENTRY POINT
; linker will jump us here
;*********************************************


Start:

;===========================================
; get the module handle for this instance
;===========================================
mov eax,0 ;NULL
push eax
call GetModuleHandleA
mov [hinstmain], eax ; and store it


.data
sz001 db "001=HE TestPad Started",13,10,0
.code
call OutputDebugStringA,offset sz001




.data
ALIGN 4
csection_flip RTL_CRITICAL_SECTION <0>

ALIGN 4
csection_paint RTL_CRITICAL_SECTION <0>
.code

;====================================================
; Initialize critical section for the Flip thread
;====================================================


.data
sz002 db "Init Critical Sections Started",13,10,0
.code

call OutputDebugStringA,offset sz002

mov eax,offset csection_flip
push eax
call InitializeCriticalSection

;=====================================================
; initialize critical section for paint thread
;=====================================================
mov eax,offset csection_paint
push eax
call InitializeCriticalSection



;=========================================================
; setup main
; -register main window class
; -create main window
; -show main window
;=========================================================

.data
sz003 db "Win Main Setup Started",13,10,0
.code

call OutputDebugStringA,offset sz003

call Win_Main_Setup


;===========================================================
; Direct DRAW initialization
; app will go full screen exclusive here
; notice that main message loop has't even started
;===========================================================

.data
sz004 db "DirectDraw Setup Started",13,10,0
.code

call OutputDebugStringA,offset sz004


call Direct_Draw_Setup

;=====================================
; clear system ram located back buffer
;=====================================
; call Clear_Back_Back


;=====================================
; clear video buffer to black
;=====================================
.data
sz005 db "Clear Video Buffer",13,10,0
.code

call OutputDebugStringA,offset sz005

call Clear_Video_Buffer


;=====================================
; clear video ram located back buffer
;=====================================

.data
sz006 db "Clear Back Buffer",13,0
.code

call OutputDebugStringA,offset sz006

call ClearBack


;======================================
; paint our intro screen instead
;======================================
call paint_intro


;=============================
; Init Direct input system
;===========================
Call Direct_Input_Init



;**********************************
; load bitmaps for sprites etc
;**********************************
call load_bmp_mouse

call load_rle_colector
call load_rle_selection

call load_bmp_fonts
call load_bmp_galaxy

call init_msg

call calc_proc_freq

;========================================
; Setup Threads and start them
;========================================
call Thread_Flip_Setup
mov [thread_can_flip],1

call Thread_Paint_Setup
mov [thread_can_paint],1


;************************************
; WinMain MESSAGE LOOP STARTS HERE
;************************************

msg_loop:

;==========================================================
; we use PeekMessage in order to detect idle (no messages)
; time we can use
;========================================================
push PM_NOREMOVE
;push PM_REMOVE
push 0
push 0
push 0
push offset msg
call PeekMessageA

;===============================
; test: do we have messages?
;==============================
cmp eax, 0
je nu_sunt_msg ; happy jump if we dont

; ===============================
; but no so happy..
; if we have to handle them
; ===============================
push 0
push 0
push 0
push offset msg
call GetMessageA

;===================================
; test: is this message WM_QUIT ?
; =================================
cmp eax,0 ; GetMessageA will return zero if it is...?
je end_loop ; EXIT PROGRAM IF TRUE!!!!

;================================================
; default action (let windows do it's dirty job)
; for all other messages
;================================================
push offset msg
call TranslateMessage

push offset msg
call DispatchMessageA

;=========================================
; and jump back to do it all over again
;======================================
jmp msg_loop

;=================================
; Here ENDS Our Program (normaly)
;==================================
end_loop:
push [msg.msWPARAM]
call ExitProcess ;exit to windows

;===================================
; we should never reach this point
; but who knows?
;===================================
ret


;=========================================
; so...there are no win messages....
; HERE we do our GAME MAIN LOOP
;=========================================

nu_sunt_msg:
push eax ; save that eax stuff
push ebx
push ecx
push edx

push esi
push edi

;=========================================================
; test: is game loop on?
; so that in future we dont make useless/dummy/dangerouse
; paint to screen/direct draw even on pause....
;=========================================================

;==================================
; just return to WIN message loop
;=================================

pop edi
pop esi

pop edx
pop ecx
pop ebx
pop eax


;====================================
; return to main Message Loop
;====================================
cmp [flag_no_messages],1
jz nu_sunt_msg
jmp msg_loop





;******************************
; END OF PROGRAM TEXT
;******************************
end Start
Posted on 2001-10-28 20:18:52 by BogdanOntanu
Thanks BogdanOntanu. I really appreciate the time you took to help, but I still do not know what I am doing wrong in my program :confused: Does anyone have another way of explaining it to me?
Posted on 2001-10-28 20:57:06 by AlexEiffel
I guess that here is the problem:



OPTION SCOPED ; Local labels are enabled, global labels inside
; PROC should be defined with double colons (LABEL::)

......



this makes your WinMain PROC below a local :)
so other modules can not know of its existence
either define it with :: or kill that SCOPED option

i can tell for sure until i see your .bat used for compile and linking
Posted on 2001-10-28 21:10:45 by BogdanOntanu
While that was being posted, i studied your source.

There problem is the way you want to break things apart (WinMain and WinProc as separate obj's, and included only by its proto definitions in DirectX).

Your on the right track but your method involved some extra work and care (why i dont prefer it, but many others do).

When you separated out WinProc it compiled fine. This is because you've fully supported it with needed includes and directives (as well as an END statement).

You attempted the same format to WinMain but your ran into headaches... The problem is by simply tearing funcitons out into files, you over looked the fact they use 'special' data declairations like "ClassName", "AppName", and "hInstance". WinProc doesnt use this so you got away without headaches here.

To fix things up, you need to add extra information in the WinMain file for the linker about these issues:

EXTERN AppName:DWORD ;used as a pointer
EXTERN ClassName:DWORD ;used as a pointer
EXTERN hInstance:DWORD ; cause it is :)

As well you need to define them in your DirectX.asm test program. Since you overlooked them there too.

ClassName db "Dx Class",0
AppName db "A DX App",0
hInstance dd 0

And to make the whole shin-dig compile, this is still not enought, as they are now defined, but at the moment PRIVATE to the file they are defined in!!! So linking this you still wont get the job done... the last thing to add in DirectX.asm is info to make them seen globally amungst the separate files:

PUBLIC ClassName
PUBLIC AppName
PUBLIC hInstance

Now...

Compile All 3...
Link *.obj

And your done:


PS: You also had a spelling typo that didnt help matters.. On line 26 of the WinMain.asm file, you have 'offset WndProc' , but the file youre declairing for this role is being called 'WinProc' (IN vs ND) in the spelling. So this is why you got your posted error, the function is not found because there is NO proto that matches the function.

Anywho.. this is the fix...

Enjoy!

NaN
Posted on 2001-10-28 21:11:42 by NaN
Thank you very much both BogdanOntanu and NaN :alright: That was exactly what I needed to know :grin: I am in your debt.
Posted on 2001-10-28 21:45:42 by AlexEiffel
I almost had the same error as you but the reasons on this list didn't help me so I thought I would tell you the error I ended up finding incase anyone else looked up the problem.

unresolved external symbol _WinMain@16

this got produced in the error codes when I put the end start directive before WinMain.

I know most of you will think this is simple but I'm a beginner and getting the simple stuff right is important
Posted on 2003-11-20 16:21:04 by Phase Verocity
Hi

the END directive

should be the last thing in your source code
nothing beyound this point will be assembled anymore
Posted on 2003-11-20 16:38:58 by BogdanOntanu