Skip to content

Functions and Variables Declaration

Mir Drualga edited this page Oct 12, 2021 · 1 revision

Functions and variables are declared and defined with standard C syntax in D2Template89. This means that unlike D2Template, there are no D2VAR, D2FUNC, or D2PTR macros, and declarations and definitions have to done manually. But on the plus side, the definition and declaration core is not too difficult to understand for a programmer that has some experience with C.

This guide will not make much sense without a reference. Several examples are already provided in the standard D2Template89 project, to help serve as a template for new functions and variables.

Warning on Uninitialized Pointers

All pointers are not initialized prior to the call to DllMain. This means that any access of Diablo II functions or variables through D2Template prior to the call to initialization functions is undefined behavior. It is only safe to access functions and variables after their respective initialization functions are completed. In C, such cases are very unlikely to occur, as the initialization rules are much more strict than C++. Unfortunately, the C++ initialization rules may permit invalid initialization of variables from uninitialized Diablo II functions and variables.

Hierarchy

At the top level, there is src/d2_functions.h. This file includes all of the header files for DLL functions. In addition, it also declares a single function used to initialize the function pointers for every DLL to be used. If a new DLL is added, src/d2_functions.c will need to be modified.

Below that are the DLL function files, such as src/d2_functions/fog_functions.h. This file includes all of the header files for functions within the scope of the DLL. This means that Storm.dll functions should not appear in src/d2_functions/fog_functions.h. A pointer initialization function is used to initialize the function pointers for every function within the scope of the DLL. If a new function is defined, src/d2_functions/fog_functions.c will need to be modified.

Below that are the functions themselves. Two functions should be provided: one function to initialize the pointer, and the other to call the actual underlying function.

Variables also apply this same concept, but for variables. Variables are less varied than functions, as variables only need to provide the type for the variable. Variables are access through a pointer to the Diablo II variable.

Pointer Initialization

Pointers are initialized using one of the D2Dll_GetAddressFrom functions in src/d2_dll.h. The DLL should match the folder that contains the function or variable. An offset, ordinal, or exported name has to be provided.

Function Declaration and Definition

Functions should be declared in a straightforward way in the .h file, without the use of calling conventions, __declspec(naked), or any other extra attributes that are non-standard.

In the declaration, the actual specifics of the underlying function will need to be specified in the .c file. That means adding the calling conventions, if applicable.

In the case where D2PTR is typically provided, it should be declared extern in the .c file for C or extern "C" in the .cpp file for C++. An x86 NASM shim file should be provided in order to reorganize the function parameters into the correct custom calling convention.

Variable Declaration and Definition

A variable is very easy to define. The variable should be declared extern in C in the .h file, and the definition (without extern) needs to be provided in the .c file.