ANY-maze Help > The ANY-maze reference > ANY-maze plug-ins > The ANY-maze demo plug-in > The DemoPlugIn.cpp source code file

The DemoPlugIn.cpp source code file

The DemoPlugIn.cpp file contains the source code of the demo ANY-maze plug-in. Although this is a C++ file, the code is essentially just C.

The listing

  

/*---------------------------------------------------------------------------------

  

  Name        : DemoPlugIn

  

  Description : Example of an ANY-maze plug in (also know as an analysis extension

                DLL).

                This plug-in implements the following plug-ins:

               

                Animal in apparatus centre

                --------------------------

                This returns an "Animal in centre" ON/OFF result to ANY-maze

                whenever the animal's centre point is within the centre of the

                apparatus. The definition of "in the centre of the apparatus"

                is that the animal is within a certain distance of the point

                at the centre of a rectangle that exactly encloses the apparatus.

                This distance defaults to 10cm, but can be edited by the user

                via the plug-in's settings dialog.

  

  

                Record animal position    

                ----------------------

                This plug in dumps the animal's centre x,y coordinates with a

                time value, to a csv file named for the animal and trial being

                performed. Thus this plug-in does not return any result. Nor

                does this plug-in does not a have a settings dialog.

               

  

  History

  -------

  7/2/2008  CPL   Created first version of this example code

  

-----------------------------------------------------------------------------------*/

  

#include

#include

#include

#include "plugin.h"

#include "resource.h"

  

  

//GUIDs for our analysis. These can be created using guidgen.exe

static const GUID GUID_INCENTREANALYSIS = {0xf5c18c7b,0x5a39,0x47f8,{0x99,0x2b,0x13,0x37,0xfe,0x0f,0x90,0xd5}};

static const GUID GUID_POSNEXPORT       = {0xbf44eea9,0x4a72,0x4b1d,{0xb4,0xaf,0x67,0xdd,0x80,0x5a,0x16,0xd2}};

  

  

//Type used to hold settings for in centre analysis

typedef struct {

  bool Initialised;

  int  Distance;

}INCENTREANALYSISSETTINGS, *LPINCENTREANALYSISSETTINGS;

  

  

  

//Globals

static HMODULE hInstance;

  

/*----------------------------------------------------------------------------------

  

  Name    CentreWindow

 

  Desc    Centres a top level window on the screen. This routine can't centre child

          windows

  

  Params  hWnd   Handle of the window to centre

 

  Return  None

  

-----------------------------------------------------------------------------------*/

  

void CentreWindow (HWND hWnd)

{

//Vars

  RECT Rect, MaxSize;

  int  x, y;

  

//BEGIN

  //Get the window's rectangle

  GetWindowRect (hWnd, &Rect);

  

  //Get screen area not obscured by the task bar

  SystemParametersInfo (SPI_GETWORKAREA, 0, &MaxSize, 0);

  

  //Adjust the window rectangle to the centre of the screen

  x = MaxSize.left + (((MaxSize.right-MaxSize.left)-(Rect.right-Rect.left))/2);

  y = MaxSize.top + (((MaxSize.bottom-MaxSize.top)-(Rect.bottom-Rect.top))/2);

  

  //Centre the window

  SetWindowPos (hWnd, NULL, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);

}

  

/******************************* Posn export routines *******************************

  

  Name    PosnExport

 

  Desc    Part of the example analysis: This routine exports the posn of the

          animal's centre point to a CSV file

 

  Params  Mesg     The type of message ANY-maze is sending to the plug in. This code

                   handles the "Test" messages: AME_TESTSTART, AME_POSN, AME_TESTEND

                   and AME_TESTABORT

          wParam   wParam sent with the message - depends on the message

          lParam   lParam sent with the message - depends on the message

  

  Return  And AME_xxx return code

  

-----------------------------------------------------------------------------------*/

  

int PosnExport (DWORD   Mesg,

                WPARAM  wParam,

                LPARAM  lParam)

{

//Types

  typedef struct {

    char   FileName[MAX_PATH];

    HANDLE hFile;

  }POSNEXPORTRECORD, *LPPOSNEXPORTRECORD;

  

//Vars

  LPAME_TESTDATA     AME_TestData;

  LPAME_POSNDATA     AME_PosnData;

  LPPOSNEXPORTRECORD PosnExportRec;

  char               str[32];

  DWORD              BytesWritten;

  

//BEGIN

  //Action depends on the message

  switch (Mesg)

  {

    case AME_TESTSTART :

      //The lParam points at a AME_TESTDATA record and the wParam is the

      //size of the record. Check the size

      assert (wParam >= sizeof(AME_TESTDATA));

      if (wParam < sizeof(AME_TESTDATA)) return AME_ERROR;

  

      //Access the AME_TESTDATA record

      AME_TestData = (LPAME_TESTDATA)lParam;

  

      //Allocate a PosnExportRecord - if this fails return Context set to NULL.

      //We'll use this in subsequent calls to determine that we can't export

      PosnExportRec = new POSNEXPORTRECORD;

      if (PosnExportRec == NULL) {

        AME_TestData->Context = NULL;

        return AME_ERROR;

      }

  

      //Build the file name for the file we'll export to

      wsprintf (PosnExportRec->FileName,

                "c:\\Animal %u Trial %u.csv",

                AME_TestData->AnimalNum,

                AME_TestData->TrialNum);

  

      //Create the file, replacing any file that already exists

      PosnExportRec->hFile = CreateFile (PosnExportRec->FileName,

                                         GENERIC_WRITE,

                                         0,

                                         NULL,

                                         CREATE_ALWAYS,

                                         FILE_ATTRIBUTE_NORMAL,

                                         NULL);

 

      //If failed junk the PosnExportRec and return Context set to NULL

      if (PosnExportRec->hFile == INVALID_HANDLE_VALUE) {

        delete PosnExportRec;

        AME_TestData->Context = NULL;

        return AME_ERROR;

      }

  

      //Success. Set Context to the address of the PosnExportRec

      AME_TestData->Context = (LPVOID)PosnExportRec;

      return AME_OK;

  

  

    case AME_POSN :  

      //The lParam points at a AME_POSNDATA record and the wParam is the

      //size of the record. Check the size

      assert (wParam >= sizeof(AME_POSNDATA));

      if (wParam < sizeof(AME_POSNDATA)) return AME_ERROR;

  

      //Access the AME_POSNDATA record

      AME_PosnData = (LPAME_POSNDATA)lParam;

  

      //Access the PosnExportRec

      if (AME_PosnData->Context == NULL) return AME_ERROR;

      PosnExportRec = (LPPOSNEXPORTRECORD)AME_PosnData->Context;

  

      //Build an entry that describes this posn. This is of the form "time,x,y"

      wsprintf (str,

                "%u,%d,%d\r\n",

                AME_PosnData->Time_xy,

                AME_PosnData->x,

                AME_PosnData->y);

  

      //Write the entry to the file

      WriteFile (PosnExportRec->hFile, str, (DWORD)strlen(str), &BytesWritten, NULL);

  

      //We don't return any result

      AME_PosnData->ResultType = RT_NONE;

  

      //Done

      return AME_OK;

  

  

    case AME_TESTEND   :

    case AME_TESTABORT :

      //The lParam is our context value

      if (lParam == NULL) return AME_ERROR;

      PosnExportRec = (LPPOSNEXPORTRECORD)lParam;

  

      //Close the file

      CloseHandle (PosnExportRec->hFile);

  

      //If Type is Abort then delete the file

      if (Mesg == AME_TESTABORT) DeleteFile (PosnExportRec->FileName);

  

      //Delete the PosnExportRec

      delete PosnExportRec;

      return AME_OK;

  

  

    default :

      //What's this

      assert (false);

      return AME_NOTIMPLEMENTED;

  

  }

}

  

/***************************  In centre analysis routines **************************

  

  Name    InCentreAnalysisSettingsDlgProc

 

  Desc    Dialog proc for the in centre analysis settings dialog - this allows the

          user to set the distance from the centre that the analysis uses

 

  Params  hDlg         Std

          Message      Std

          wParam       Std

          lParam       Std

 

  Return  Std

-----------------------------------------------------------------------------------*/

  

BOOL CALLBACK InCentreAnalysisSettingsDlgProc (HWND   hDlg,

                                               UINT   Mesg,

                                               WPARAM wParam,

                                               LPARAM lParam)

{

//Vars

  static LPINCENTREANALYSISSETTINGS Settings;

  

//BEGIN

  //Action depends on the mesg

  switch (Mesg)

  {

    case WM_INITDIALOG :

      //lParam points at the settings we're to edit. Note the pointer

      Settings = (LPINCENTREANALYSISSETTINGS)lParam;

  

      //Centre the dialog

      CentreWindow (hDlg);

  

      //Check for uninitialised settings (in which case all fields are zero) and

      //set them to some sensible defaults

      if (!Settings->Initialised) {

        Settings->Distance    = 10;

        Settings->Initialised = true;

      }

  

      //Set the edit control to the current distance and limit the control to

      //3 characters, i.e. 999cm

      SetDlgItemInt (hDlg, IDC_DISTANCE, Settings->Distance, false);

      SendDlgItemMessage (hDlg, IDC_DISTANCE, EM_LIMITTEXT, 3, 0);

      break;

  

  

    case WM_COMMAND :

      //Action depends on the control

      switch (LOWORD(wParam))

      {

        case IDOK :

          //Save the user's entry in the Settings

          Settings->Distance = max (1, GetDlgItemInt (hDlg, IDC_DISTANCE, NULL, false));

                       

          //Close the dialog, returning IDOK to signal that the settings need to be

          //saved

          EndDialog (hDlg, IDOK);

          break;

  

                       

        case IDCANCEL :

          //Close the dialog returning IDCANCEL to signal that the settings need not be

          //saved

          EndDialog (hDlg, IDCANCEL);

          break;

      }

      break;

  

    default:

      //We didn't process the message

      return 0;

  }

  //We did process the message

  return 1;

}

  

  

/*-----------------------------------------------------------------------------------

  

  Name    EditInCentreAnalysisSettings

 

  Desc    Displays a dialog box where the user can set the distance from the centre

          for the analysis

 

  Params  Settings  Pointer to the InCentreAnalysis settings record that the user

                    will be editing

 

  Return  True if the user edited the settings and they should now be saved

-----------------------------------------------------------------------------------*/

  

bool EditInCentreAnalysisSettings (LPINCENTREANALYSISSETTINGS Settings)

{

//BEGIN

  //Display the in centre analysis settings dialog, passing the settings

  //pointer as lParam. The dialog will edit the settings in place

  return (DialogBoxParam (hInstance,

                          MAKEINTRESOURCE(IDD_INCENTREANALYSISSETTINGS),

                          NULL,

                          InCentreAnalysisSettingsDlgProc,

                          (LPARAM)Settings) == IDOK);

}

  

/*----------------------------------------------------------------------------------

  

  Name    InCentreAnalysis

 

  Desc    Part of the example analysis: This routine determines when the animal is

          in the centre of the apparatus. "Centre" is defined as within a certain

          distance of the centre which the user can set using the analysis settings

          (the default is 10cm)

 

  Params  Mesg     The type of message ANY-maze is sending to the plug in. This code

                   handles the "Test" messages: AME_TESTSTART, AME_POSN, AME_TESTEND

                   and AME_TESTABORT

          wParam   wParam sent with the message - depends on the message

          lParam   lParam sent with the message - depends on the message

  

  Return  And AME_xxx return code

-----------------------------------------------------------------------------------*/

                

int InCentreAnalysis (DWORD   Mesg,

                      WPARAM  wParam,

                      LPARAM  lParam)

{

//Types

  typedef struct {

    double Distance;

    int    AppCentreX;

    int    AppCentreY;

    bool   InCentre;

}INCENTREANALYSISRECORD, *LPINCENTREANALYSISRECORD;

  

//Vars

  LPAME_TESTDATA             AME_TestData;

  LPAME_POSNDATA             AME_PosnData;

  LPINCENTREANALYSISRECORD   InCentreAnalysisRec;

  LPINCENTREANALYSISSETTINGS Settings;

  double                     d, dx, dy;

  bool                       NowInCentre;

  

//BEGIN

  //Action depends on the type

  switch (Mesg)

  {

    case AME_TESTSTART :

      //The lParam points at a AME_TESTDATA record and the wParam is the

      //size of the record. Check the size

      assert (wParam >= sizeof(AME_TESTDATA));

      if (wParam < sizeof(AME_TESTDATA)) return AME_ERROR;

  

      //Access the AME_TESTDATA record

      AME_TestData = (LPAME_TESTDATA)lParam;

  

      //Allocate a InCentreAnalysisRecord - if this fails return AME_ERROR

      InCentreAnalysisRec = new INCENTREANALYSISRECORD;

      if (InCentreAnalysisRec == NULL) return AME_ERROR;

  

      //Calculate and note the centre point of the apparatus

      InCentreAnalysisRec->AppCentreX = (AME_TestData->ApparatusRect.left + AME_TestData->ApparatusRect.right) / 2;

      InCentreAnalysisRec->AppCentreY = (AME_TestData->ApparatusRect.top + AME_TestData->ApparatusRect.bottom) / 2;

  

      //The passed AME_TestData record includes a pointer to the settings

      //for this analysis. The settings define the distance from the centre

      //that we consider to be the "centre" of the apparatus. Convert this

      //distance to pixels and note it in the InCentreAnalysisRec. If the

      //distance is zero then the user has not specified a distance so

      //use a default of 10cm

      Settings = (LPINCENTREANALYSISSETTINGS)AME_TestData->Settings;

      if (!Settings->Initialised) Settings->Distance = 10;

      d = (double)Settings->Distance;

  

      //Convert from cm to mm

      d = d * 10;

  

      //Convert from mm to pixels

      InCentreAnalysisRec->Distance = d * AME_TestData->Scaling;

  

      //Start by assuming the animal is not in the centre of the apparatus

      InCentreAnalysisRec->InCentre = false;

  

      //Set Context to the address of the InCentreAnalysisRec

      AME_TestData->Context = (LPVOID)InCentreAnalysisRec;

      return AME_OK;

  

  

    case AME_POSN :

      //The lParam points at a AME_POSNDATA record and the wParam is the

      //size of the record. Check the size

      assert (wParam >= sizeof(AME_POSNDATA));

      if (wParam < sizeof(AME_POSNDATA)) return AME_ERROR;

  

      //Access the AME_POSNDATA record

      AME_PosnData = (LPAME_POSNDATA)lParam;

  

      //Access the InCentreAnalysisRec

      if (AME_PosnData->Context == NULL) return false;

      InCentreAnalysisRec = (LPINCENTREANALYSISRECORD)AME_PosnData->Context;

  

      //Calculate the distance from the animal's posn to the apparatus centre

      dx = AME_PosnData->x - InCentreAnalysisRec->AppCentreX;

      dy = AME_PosnData->y - InCentreAnalysisRec->AppCentreY;

      d  = sqrt((dx * dx) + (dy * dy));

  

      //Is the animal within the required distance of the apparatus centre

      NowInCentre = (d < InCentreAnalysisRec->Distance);

  

      //Has the animal's "InCentre" state changed

      if (NowInCentre != InCentreAnalysisRec->InCentre)

      {

        //Yes, so return a suitable result

        AME_PosnData->ResultType  = RT_ONOFF;

        AME_PosnData->ResultValue = NowInCentre ? 1 : 0;

  

        //Update the in centre state

        InCentreAnalysisRec->InCentre = NowInCentre;

      }

      else

      {

        //We're not returning a result

        AME_PosnData->ResultType = RT_NONE;

      }

  

      //Processed successfully

      return AME_OK;

  

  

    case AME_TESTEND   :

    case AME_TESTABORT :

      //The lParam is our context value

      if (lParam == NULL) return false;

      InCentreAnalysisRec = (LPINCENTREANALYSISRECORD)lParam;

  

      //Delete the InCentreAnalysisRec

      delete InCentreAnalysisRec;

  

      //Done

      return AME_OK;

  

  

    default :

      //What's this?

      assert (false);

      return AME_NOTIMPLEMENTED;

  }

}

  

/*----------------------------------------------------------------------------------

  

  Name    ANYmazeExtension_Main

 

  Desc    When starting up ANY-maze will search the same directory as the executable

          file for any DLLs. For each one it finds it will call GetProcAddress for

          a routine with the name "ANYmazeExtension_Main".

          DLLs which export this routine will be considered to be ANY-maze plug-ins.

  

          This routine is the interface between ANY-maze and the plug-in. ANY-maze

          will call this routine passing it a Mesg and a w- and l- param (much like

          windows message processing).

          This routine should process the obligatory messages and can implement as

          many of the options messages as it wishes. For details of each message

          and its parameters refer to the ANY-maze help.

  

  Params  guid        Pointer to a GUID that identifies the analysis to which the

                      message is addressed. When the message is AME_ENUMERATE this

                      param will hold the guid if the analysis returned by the

                      prior call, or it will be GUID_NULL when the enumeration is

                      starting.

          Mesg        One of the AME_xxx message constants                      

          wParam      Depends on the message, but typically used for integer

                      parameters.

          lParam      Depends on the message, but typically a pointer to a buffer

 

  Return  One of the AME_xxx return constants. For any messages not implmented for

          a certain analysis the return should be AME_NOTIMPLEMENTED

-----------------------------------------------------------------------------------*/

  

extern "C"

__declspec(dllexport) int ANYmazeExtension_Main (LPGUID guid,

                                                 DWORD  Mesg,

                                                 WPARAM wParam,

                                                 LPARAM lParam)

{

//Vars

  int RscID;

  

//BEGIN

  //Action depends on the Mesg

  switch (Mesg)

  {

    case AME_ENUMERATE :

      //Simply enumerate the GUIDs of the analysis we can perform, returning the

      //next GUID in the buffer pointed at by lParam. When enumeration starts we

      //are passed a null GUID

      if (*guid == GUID_NULL)

        *((LPGUID)lParam) = GUID_INCENTREANALYSIS;

      else if (*guid == GUID_INCENTREANALYSIS)

        *((LPGUID)lParam) = GUID_POSNEXPORT;

      else

        return AME_NOTIMPLEMENTED;

      return AME_OK;

  

  

    case AME_GETNAME        :

    case AME_GETHELPTITLE   :

    case AME_GETHELPINTRO   :

    case AME_GETHELPDETAILS :

      //These all return strings, which we load from the DLL's resources. The

      //strings could be hard coded here instead

      if ((Mesg == AME_GETNAME) && (*guid == GUID_INCENTREANALYSIS))

        RscID = IDS_INCENTREANALYSIS_HELP_NAME;

      else if ((Mesg == AME_GETNAME) && (*guid == GUID_POSNEXPORT))

        RscID = IDS_POSNEXPORT_HELP_NAME;

      else if ((Mesg == AME_GETHELPTITLE) && (*guid == GUID_INCENTREANALYSIS))

        RscID = IDS_INCENTREANALYSIS_HELP_TITLE;

      else if ((Mesg == AME_GETHELPTITLE) && (*guid == GUID_POSNEXPORT))

        RscID = IDS_POSNEXPORT_HELP_TITLE;

      else if ((Mesg == AME_GETHELPINTRO) && (*guid == GUID_INCENTREANALYSIS))

        RscID = IDS_INCENTREANALYSIS_HELP_INTRO;

      else if ((Mesg == AME_GETHELPINTRO) && (*guid == GUID_POSNEXPORT))

        RscID = IDS_POSNEXPORT_HELP_INTRO;

      else if ((Mesg == AME_GETHELPDETAILS) && (*guid == GUID_INCENTREANALYSIS))

        RscID = IDS_INCENTREANALYSIS_HELP_DETAILS;

      else if ((Mesg == AME_GETHELPDETAILS) && (*guid == GUID_POSNEXPORT))

        RscID = IDS_POSNEXPORT_HELP_DETAILS;

      else

        return AME_ERROR;

      

      //Load the resource

      return ((LoadString (hInstance, RscID, (LPSTR)lParam, (int)wParam) != 0) ? AME_OK : AME_ERROR);

  

  

    case AME_GETRESULTTYPE :

      //Return the result type in the unsigned char pointed to by lParam

      if (*guid == GUID_INCENTREANALYSIS)

        *((unsigned char*)lParam) = RT_ONOFF;

      else if (*guid == GUID_POSNEXPORT)

        *((unsigned char*)lParam) = RT_NONE;

      else

        return AME_ERROR;

      return AME_OK;

     

  

    case AME_EDITSETTINGS :

      //Edit the settings of the analysis whose GUID is passed. wParam is size of a buffer

      //pointed to by lParam which holds the current settings. If return is false

      //which the title should be returned

      if (*guid == GUID_INCENTREANALYSIS)

      {

        //Check the passed buffer is no larger than the settings we maintain

        //for in centre analysis

        assert (wParam >= sizeof (INCENTREANALYSISSETTINGS));

        return (EditInCentreAnalysisSettings ((LPINCENTREANALYSISSETTINGS)lParam) ? AME_OK : AME_CANCELLED);

      }

      else if (*guid == GUID_POSNEXPORT)

      {

        //Posn export has no settings

        return AME_NOTIMPLEMENTED;

      }

      else

      {

        //What's this?

        return AME_ERROR;

      }

      break;

  

  

    case AME_TESTSTART :

    case AME_POSN      :

    case AME_TESTEND   :

    case AME_TESTABORT :

      //Pass to analysis specific routine for processing

      if (*guid == GUID_INCENTREANALYSIS)

        return InCentreAnalysis (Mesg, wParam, lParam);

      else if (*guid == GUID_POSNEXPORT)

        return PosnExport (Mesg, wParam, lParam);

      else

        return AME_ERROR;

      break;

  

  

    default :

      //What's this message?

      return AME_NOTIMPLEMENTED;

  }

}

  

/*----------------------------------------------------------------------------------

  

  Name    DllMain

 

  Desc    Main entry point for the DLL. Just notes the instance handle

 

  Params  Std

 

  Return  Std

-----------------------------------------------------------------------------------*/

  

BOOL APIENTRY DllMain( HMODULE hModule,

                       DWORD   ul_reason_for_call,

                       LPVOID  lpReserved)

{

//BEGIN

  switch (ul_reason_for_call)

  {

    case DLL_PROCESS_ATTACH : //Note the module handle

                              hInstance = hModule;

                              break;

    case DLL_THREAD_ATTACH  :

    case DLL_THREAD_DETACH  :

    case DLL_PROCESS_DETACH : //Nothing to do

                              break;

  }

  

  //Done

  return TRUE;

}

  

//===================================================================================

  

© Copyright 2003-2026 Stoelting Co. All rights reserved

ANY-maze help topic T1002