#include <gmapi.h>

using namespace gm;

CGMAPI* g_pGmapi;
GMFUNCTIONINFO* g_pPreviousTable;

// GM function type definition example
void __fastcall NewShowMessage( int aNumberOfArgs, // Number of parameters passed to the function
                                PGMINSTANCE aInstance, // Pointer to the instance which called the function
                                PGMVALUE aResult, // Pointer to a GMVALUE structure which holds the result
                                int aMaxArgs, // Maximal allowed number of arguments
                                GMVALUE* aArguments ) { // Arguments passed to the function

  // Show message box
  MessageBoxA( g_pGmapi->GetMainWindowHandle(),
               aArguments[0].string, // get show_message's "str" argument
               "Test",
               MB_ICONINFORMATION );

  // Safely change the result (the method safely allocates Delphi string for the runner)
  CGMAPI::SetGMFunctionResult( aResult, "Hello !" );
}

// Entrypoint

BOOL WINAPI DllMain( HMODULE aHandle, int aReason, void* aReserved ) {
  switch ( aReason ) {
    case DLL_PROCESS_ATTACH: {
      DisableThreadLibraryCalls( aHandle );

      DWORD result = 0;
      g_pGmapi = CGMAPI::Create( &result );

      if ( result != GMAPI_INITIALIZATION_SUCCESS ) {
        MessageBox( 0, "Unable to initialize GMAPI.", 0, MB_SYSTEMMODAL | MB_ICONERROR );
        return FALSE;
      }

      // Preserve GM's function table to restore it later on DLL unload
      g_pPreviousTable = g_pGmapi->PreserveFunctionData();
      
      // Replace GM function with user-defined function
      g_pGmapi->SetGMFunctionAddress( "show_message", NewShowMessage );
      break;
    }

    case DLL_PROCESS_DETACH:
      // Restore the function table
      g_pGmapi->RestoreFunctionData( g_pPreviousTable );
      g_pGmapi->Destroy();
  }

  return TRUE;
}

// Dummy function
extern "C" __declspec( dllexport ) double Nothing() {
  return 0.0;
}
