# vi: set ts=4 sw=4 :
# vim: set tw=75 :

After writing and testing under linux, I then tried to move the code to
windows, and being unfamiliar with windows coding, I ran into several
issues I wasn't aware of, which I describe here for posterity:


 - Apparently the GiveFnptrsToDll() routine has to be declared "WINAPI",
   which is a macro for "__stdcall".  Without this, the behavior I observed
   was that the routine would be called, and would return seemingly okay,
   but during the following call to GetNewDLLFunctions, the application
   would crash.

   This was especially confusing because, using SDK2.1 source for
   reference, the use of EXPORT and DLLEXPORT macros seemed inconsistent.
   Doing a simple grep for "define.*EXPORT" turns up these definitions:

      cl_dll/cl_dll.h:	   #define EXPORT  _declspec( dllexport )
	  cl_dll/hud_iface.h:  #define EXPORT  _declspec( dllexport )
	  dlls/cbase.h:        #define EXPORT  _declspec( dllexport )

	  cl_dll/in_defs.h:    #define DLLEXPORT __declspec( dllexport )
	  engine/eiface.h:     #define DLLEXPORT __stdcall

   Between "EXPORT", "DLLEXPORT", and "dllexport", and then "_declspec" and
   "__declspec", they all seemed the same to me.  Of course, they aren't.

   It seems "__declspec(dllexport)" (I'm still unsure about the single vs
   double underscore) simply says that the routine should be visible
   externally, outside the DLL.  The "__stdcall" specifier, however,
   changes the way the stack is cleaned up when the routine returns, and no
   doubt having the routine itself using a different convention than the
   caller (the engine) caused memory corruption and thus application
   crashes.  The specifier doesn't seem, to me, to be particularly relative
   to DLL exporting per se, so I'd say the macro name was unfortunate and
   confusing.  

   The other confusion was that GiveFnptrsToDll is apparently the _only_
   function that needs to be declared __stdcall; declaring the other
   external functions (GetEntityAPI, etc) produced MSVC errors and other
   problems (as might be expected).

   Also, it seems "__declspec" has to be placed _before_ the return type,
   whereas "__stdcall" is placed _after_ the return type.  Well, at least
   in MSVC; mingw appears to be looser.

   Further complicating this, the __stdcall generally causes the function
   to be given an internal symbol with a trailing "@" and digits specifying
   the number of bytes in the function arguments (in this case, "8").  At
   least, this is true under the mingw GNU compiler; I couldn't tell if
   MSVC was the same.  In any case, by default then, the function is
   exported as "GiveFnptrsToDll@8()", and the engine can't resolve the name
   properly.  
   
   In mingw you can apparently alias this to the non-@ name via ".def"
   files, but it looked like that if I have a .def file, I'd also have to
   list all the entities in linkfunc.cpp (which would be a pain to
   maintain).  Under MSVC, this didn't appear to be a problem, as both the
   SDK source and adminmod source use a ".def" file, but still export all
   the other functions okay.  I'm not sure why the difference; I may be
   missing a mingw link parameter/option.

   There are, however, mingw link options (--add-stdcall-alias, --kill-at)
   to handle the problem (the first appears to do the job; I'm unsure about
   the second), while still exporting all the other necessary functions.
   Now, reading MSDN:
      http://msdn.microsoft.com/library/devprods/vs6/visualc/vccore/_core_determine_which_exporting_method_to_use.htm
   
   there's apparently an issue of an "export ordinal" and the order of the
   list of exported functions, which is solved by using a .def file.
   Perhaps this is why the SDK uses a .def file, in which case I may have
   problems if I don't specify that GiveFnptrsToDll is the first function
   (as the SDK .def file does).  Although, perhaps this isn't even an issue
   given that the DLL functions are called by name explicitly
   (dlsym/GetFuncPointer), rather than being resolved to an library offset
   at link time.

   In any case, apparently using the conventions in the SDK, and including
   the same headers in the same order produces the correct result, but it
   wasn't at all clear to me, when looking at the source.

   This one was hard for me to track down, and I also found this page to 
   be helpful:
      http://www.geocities.com/Tokyo/Towers/6162/win32/dll/make.html


 - Linux appears to be either (a) much more forgiving about improper
   pointer references in memcpy, or (b) laying out its memory in a manner
   that hides problems with that.  In my case, I had:
      DLL_FUNCTIONS *dllapi_table;
	  dllapi_table=malloc(...)
	  memcpy(pFunctionTable, &dllapi_table, sizeof(DLL_FUNCTIONS));
   
   Since the argument is already a pointer, the extra "&" is improper, and
   should instead be:
	  memcpy(pFunctionTable, dllapi_table, sizeof(DLL_FUNCTIONS));

   Under linux, it didn't seem to be a problem, and program operation was
   (as far as I could tell) correct.  Under windows, though, I got program
   crashes after calling the 4th or 5th entity in linkfunc.cpp.  It
   wasn't at all obvious what the problem was, and took quite a while to
   track down.
   

 - missing functions (strtok_r, snprintf)
 - missing macros (PATH_MAX, NAME_MAX)
 - dlerror, getlasterror
 - LoadLibrary returning 0 on failure (vs dlclose returning 0 on success)
 - limits.h under mingw
