mirror of
https://github.com/rehlds/metamod-r.git
synced 2025-02-06 18:42:18 +03:00
111 lines
5.3 KiB
Plaintext
111 lines
5.3 KiB
Plaintext
# 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
|