Calling an External DLL Function

You can also program functionality in any 64-bit programming environment that can create a Windows DLL, and call that function directly from the your GX using the Geosoft GX Language.  

Sections on this page

GX Based DLL Development

In order for your DLL code to interact via a GX all of the functionality must be wrapped in a function which will be called within GXC code. The function must be exported from the DLL using the "C" calling convention in order to be accessible from within GXC. The first parameter in the exported function MUST BE the Geosoft handle, and is the only required parameter. If your function is providing it's own user interface that will typically be all that is passed.

excerpt from callfunc.c
// In this example taken from the callfunc example the user interface 
// is being provided by the GX and all parameters are being passed in.  
// GX_OBJECT_PTR is a void pointer and is defined in geoengine.core.gxlib.h
__declspec(dllexport) 
long __cdecl iSum_CALLFUNC(       // returns sum of two numbers
		GX_OBJECT_PTR pGeo,  // geosoft handle 
 		const long *pl1,     // first number
		const long *pl2)     // second number


// Strings are a special case, you need to pass the length as well
__declspec(dllexport)
long __cdecl iStringFunction(
		GX_OBJECT_PTR pGeo,  // geosoft handle 
		char * myString,
        const long * pmyStringLen)


The exported function will not be visible to your GXC code without being declared either in a GXH file or within the GXC itself. The function declaration does not include the geosoft handle. Note also that the integer pointers expected by the DLL are declared simply as type int within the header. There are no pointers in the GXC language. Strings are a special case. The length of the string must always be passed along with the string.


Callfunc.gxh
//----------------------------------------------------------
// iSum_CALLFUNC    Return the sum of two numbers
[callfunc] // --- this is the name of the DLL (callfunc.dll) ---
int iSum_CALLFUNC( int,      // first number
                   int );    // second number

[MyDLL] // name of DLL containing iStringFunction
int  iStringFunction(	string,
						int); // length of string;

The alternative to declaring the function in a GXH is to declare it within the GXC file. See the iMyFunction example below.

Finally, the last step is to call the function from within a GX. 

Error Handling

It is good practice for your DLL function to return a code to the calling GX indicating succesful completion or an error code. For example if the user presses Cancel on your DLL controlled form it would be advantageous to capture that information in the GX so that the GX and any script calling the GX can be halted.

__declspec(dllexport)
long __cdecl iMyFunction(
		GX_OBJECT_PTR pGeo){
	const GX_RESULT_OK = 0;
	const GX_RESULT_CANCEL = 1;
	const GX_RESULT_ERROR = -1;
	
	if ( .. something that returns an error...) {
		return GX_RESULT_ERROR;
	} else if ( .. user pressed cancel...) {
		return GX_RESULT_CANCEL;
	} else {
		return GX_RESULT_OK;
	}	
}
MyFunction.gxc
//=================================================
NAME              ="MyFunction"
VERSION           ="v1.00  "
DESCRIPTION       ="Does something wonderful, I'm sure
"
//===========================================================================
#include <all.gxh>
[MyDLL] int iMyFunction();
//===========================================================================
{	
	switch  (iMyFunction()) {
		case -1:
			Abort_SYS();
		case 1:
			Cancel_SYS();
	}
}

NOTE: The actual effect of Cancel_SYS is to cause the GX to end without logging it in the event log or displaying an error message, which is sufficient in an interactive sense. However when the user Cancels the execution of a GX during a script they generally want the script to end as well. This can be accomplished by beginning the script with the "CANCEL_AS_ERROR ON" command as the first item. Terminating your GX with Abort_SYS will always terminate a script and show an error message.

Installing your custom DLL

Third party applications are usually placed in the <geosoft>\bin or the <geosoft>\resourcefiles\bin directory but can be placed in a different location if desired.  A registry setting is required to locate each DLL that is not placed in a \bin directory.  Add the following registry key to the system running the application:

HKEY_LOCAL_MACHINE\SOFTWARE\Geosoft\{KEY}\3rdPartyDLLs.

The {KEY} is the version of oasis montaj that will be running. In the standard Oasis montaj version this key is “Oasis montaj” and for the Viewer it is “Oasis montaj Viewer”. However, some special versions of montaj for our CS customers do have unique key names. Note that in this case version doesn't refer to the version number, but rather the name of the product.

Once this key is created, populate it with the names of each DLL needing to be redirected to a different location.  For example, if a custom GX called a method in my geocustom.dll file installed in c:\program files\custom, I would create a new string in the registry:

 Name: geocustom.dll

Data: <Program Files>\custom\geocustom.dll

The first time your GX is run, montaj will try to load the DLL from <geosoft>\bin first.  If it is not found there, it will check this registry setting for any matches of the DLL name and load it from the specified path instead.  Until montaj has been restarted, the DLL will always be loaded from the alternate location.