Primary Extender conversion tasks

  1. Delete old DLLs and temp files

    In your Extender Project directory, and in the RELEASE and DEBUG directories, delete the old DLLs and also any files with a 32i extension and possibly other temp OBJ files and stuff, as we will be changing the name of the output file to 34I in subsequent steps.
  2. Fix output file name

    In Visual C, settings, LINK tab, change the output file name for BOTH Release and Debug builds from xxx.32i.dll to xxx.34i.dll

  3. Set Structure Alignment

    In Visual C, settings, C/C++ tab, "Code Generation" item in the dropdown box, set "Struct Member Alignment" to 4 bytes in BOTH Release and Debug builds

  4. Update resource file version information

    1. Update fileversion information to match extender version information
    2. Update product version to 2001
    3. Update Copyright notice to 2001
    4. Update original filename so it shows the 34i extension
    5. update internal name so it show the 34i extension

  5. Check String Table

    String table string number 1000 should be a short description of the extender
  6. Update EXTENDERVERSION in source code

    In your source code increment the EXTENDERVERSION define to the next number

  7. Define InterfaceLevel and Extender_Feature_Level

    Add the INTERFACELEFEL define to your code someplace. Usually top of C program or H file someplace.

    If you do not have EXTENDER_FEATURE_LEVEL in your code add it in.

    	#define INTERFACELEVEL  2              // extender interface level (DON'T CHANGE!)
    	#define EXTENDER_FEATURE_LEVEL 1001    // required BATDLL feature interface level
    
      

  8. Replace/Update RET* macros

    Delete existing RET* macros
    Replace with following:

    #define RETLONG(numb)         return (lpViperCallback(((lpViperReturn->x=numb)      +(lpViperReturn->inittype=VARTYPE_INT))      ?RESULT_SUCCESS:RESULT_SUCCESS, ViperInterfaceVersion, lpViperStruct, lpViperReturn))
    #define RETFLOAT(numb)        return (lpViperCallback(((lpViperReturn->flt=numb)    +(lpViperReturn->inittype=VARTYPE_FLOATNUM)) ?RESULT_SUCCESS:RESULT_SUCCESS, ViperInterfaceVersion, lpViperStruct, lpViperReturn))
    #define RETSTRING(str)        return (lpViperCallback(((lpViperReturn->lpstr=str)   +(lpViperReturn->inittype=VARTYPE_STRING))   ?RESULT_SUCCESS:RESULT_SUCCESS, ViperInterfaceVersion, lpViperStruct, lpViperReturn))
    #define RETERROR(sev, errnum) return (lpViperCallback(((LoadString(hinstDLL, (errnum), lpViperReturn->lpstr = szWork, sizeof(szWork)))+(lpViperReturn->inittype = VARTYPE_STRING)) ?(sev)         :(sev)         , ViperInterfaceVersion, lpViperStruct, lpViperReturn))
    #define ANSWERSTRING(str) lpViperCallback(  ((lpViperReturn->lpstr=str)+(lpViperReturn->inittype=VARTYPE_STRING))?RESULT_SUCCESS:RESULT_SUCCESS,ViperInterfaceVersion,lpViperStruct,lpViperReturn)
    #define ANSWERLONG(numb)  lpViperCallback(  ((lpViperReturn->x=numb)+(lpViperReturn->inittype=VARTYPE_INT))?RESULT_SUCCESS:RESULT_SUCCESS,ViperInterfaceVersion,lpViperStruct,lpViperReturn)
    #define ANSWERFLOAT(numb) lpViperCallback(  ((lpViperReturn->flt=numb)+(lpViperReturn->inittype=VARTYPE_FLOATNUM))?RESULT_SUCCESS:RESULT_SUCCESS,ViperInterfaceVersion,lpViperStruct,lpViperReturn)
    #define RETCANCEL return (-5)
        

  9. Fixup Command Table

    1. Change CommandExtTable type from COMMEXTSTRUCT to tablestruct
      It should read...
          tablestruct CommandExtTable[] =
        

    2. Convert CONSTANT entries in CommandExtTable: Basically change
      CONSTANT,
      to
      CONSTANT, 0x0000000000000000,

    3. Convert FUNCTION entries in CommandExtTable:
          Old:
            {10,  FUNCTION,  0x001F0001L,  0,  "xextenderinfo"},
          New:
            {10,  FUNCTION,  0x0000000000011111, 0x00000001L,  0, "xExtenderInfo"},
         

      Note that a quick way to do it is to replace

      0x001F000
      with
      0x0000000000011111, 0x0000000

    4. Add
      0x0000000000000000
      to the final -1 entry.

  10. Add new entrypoint function WILExtenderQuery:

    Basically copy and paste the following code someplace
    
    
      /*===========================================================================
                                     WILExtenderQuery
    
        WILExtenderQuery is an optional (but recommended) entry point.  It is used
        to provide helpful information to the WIL DLL and possibly other callers.
        ===========================================================================*/
    
      DllExport LONG FAR PASCAL WILExtenderQuery
       (short  nRequest,                     // type of information being requested
        LPVOID lpvInfo,                      // information buffer
        LONG   nCount)                       // additional data
      {
        static char szWork[256];
        LONG        i;
    
        switch (nRequest)
        {
      /*---------------------------------------------------------------------------
        case 1 is used to identify yourself to a caller.
    
        If lpvInfo is not NULL, it points to a character buffer where you may copy
        a string describing the extender.
    
        nCount is the size of the buffer pointed to by lpvInfo, in bytes.  When
        called by the WIL DLL, you can expect this to be a 256-byte buffer.
    
        The return value should be the version number of the extender.
        ---------------------------------------------------------------------------*/
          case 1:                            // version information
          {
            if ((lpvInfo) && (nCount > 0))
            {
              LoadString(hinstDLL, 1000, szWork, sizeof(szWork));
              lstrcpyn((LPSTR) lpvInfo, szWork, nCount);
            }
    
            return (EXTENDERVERSION);
          }
    
      /*---------------------------------------------------------------------------
        case 2 is used to inform the WIL DLL of your preferred interface level.
    
        lpvInfo points to an array of LONG's, indicating the interface levels
        supported by the WIL DLL (each element represents one level).
    
        nCount indicates the number of elements in the array pointed to by lpvInfo.
    
        The return value must be the same as one of the elements in the lpvInfo
        array.  Currently, the WIL DLL supports interface levels 1 and 2, so your
        return value should be 1 or 2.  Newly designed extenders (such as WILX)
        use interface level 2 and have a WilExtender2 entry point.  However, it
        is possible to design an extender to support multiple interface levels.
    
        If you return an invalid value, the extender will not be loaded and the
        AddExtender command will fail.
        ---------------------------------------------------------------------------*/
          case 2:                            // preferred interface version
          {
            for (i = 0; i < nCount; i++)
              if (((LPLONG) lpvInfo)[i] == INTERFACELEVEL)  // found one we like
                return (INTERFACELEVEL);
    
            return (-1);                     // didn't find any we like
          }
    
      /*---------------------------------------------------------------------------
        Return 0 for any unknown requests, or any requests you don't handle!
        ---------------------------------------------------------------------------*/
          default:
            return (0);
        }
      }
      

  11. Rename WILExtender function to WILExtender2, and change parameters:

    Rename your WilExtender function to WilExtender2 and change parameters. Basically use the NEW code below

    Old:

    
    DllExport LONG FAR PASCAL WILExtender
      (HWND            hWnd,              // handy hWnd for messageboxes, etc
      HINSTANCE       hInst,             // valid hInstance
      LONG            lVersion,          // don't touch
      short           CmdId,             // case number for big switch
      lpAddOnCallback lpPhoneHome,       // don't touch
      LPSTR           lpBlock,           // don't touch
      LONG FAR *      lpLong,            // pointer to your 32 bits
      LPSTR           lp1,               // parameter 1
      LPSTR           lp2,               // parameter 2
      LPSTR           lp3,               // parameter 3
      LPSTR           lp4,               // parameter 4
      LPSTR           lp5)               // parameter 5
      

    New:

    
    
    DllExport LONG FAR PASCAL WILExtender2
      (HWND            hWnd,                   // hWnd of parent application
      HINSTANCE       hInst,                   // hInstance of parent application
      LONG            ViperInterfaceVersion,   // WIL interface version
      short           CmdId,                   // identifies extender function being called
      LPVIPERCALLBACK lpViperCallback,         // pointer to return value callback function
      LPVIPERSTRUCT   lpViperStruct,           // pointer to information structure
      LPLONG          lpLong,                  // pointer to your 32 bits
      LPVIPERVAR      lpvvArg,                 // pointer to parameter array
      LONG            nArgCount,               // parameter count for lpvvArg
      LPVIPERVAR      lpViperReturn)           // pointer to return value structure
       
  12. Add local variables to WILExtender2:

    In the WilExtender2 function add...
    
      LPSTR  lp1, lp2, lp3, lp4, lp5;
       
  13. Add code to the beginning of WILExtender2:

    This is for the "dumb" conversion to get stuff working ASAP. you might wish to revise this later when you make a complete conversion
    
      if (CmdId >= 0)                      // don't do this for initialization calls
      {
        lp1 = lpvvArg[0].lpstr;
        lp2 = lpvvArg[1].lpstr;
        lp3 = lpvvArg[2].lpstr;
        lp4 = lpvvArg[3].lpstr;
        lp5 = lpvvArg[4].lpstr;
      }
      
    Basically it is converting the new parameter passing stuff to look like the old way so you should not need to convert any functions.
  14. Delete bInterfaceOK stuff

    If you had code in the extender checking the bInterfaceOK flag to determine if the DLL is compatible with the WIL version, delete it. Delete the bInterfaceOK GLOBAL variable also. All this work is done in the case -1 routine (described below)
  15. Add case -1

    Add case -1 to the switch statement. Paste code below. I like to organize my new switched like

    case -1
    case -2
    case -3
    case 0
    case 1
    etc

    Move any one-time initialization code that you were doing in case 98 into this new case -1 routine

    
    /*---------------------------------------------------------------------------
     Case -1 is called once, when your extender is loaded.  It is the place to
     perform your one-time initialization tasks.  The return value should be the
     number of items in your CommandExtTable (functions and constants).  You may
     also return 0 if you are unable to determine the correct number of items.
    
     You may return a negative value (-1) to indicate that your extender was
     unable to successfully initialize, for example, if it is running on an
     unsupported platform or a dependent DLL could not be loaded.  This will
     cause the AddExtender command to fail.  You may additionally provide a
     string indicating the reason for the failure:
    
       lpvvArg points to a character buffer into which you may copy an error
       message.
    
       nArgCount is the size of the buffer pointed to by lpvvArg, in bytes.
       You can expect this to be a 256-byte buffer.
     ---------------------------------------------------------------------------*/
        case -1:                           // Initialization
        {
          BOOL bInterfaceOk;
          bInterfaceOk=FALSE;
          if (lpViperStruct->dwLevel >= EXTENDER_FEATURE_LEVEL)
          {
            bInterfaceOk = TRUE;
            //lpfnDllServices = lpViperStruct->lpfnDllServices;
            //hBatData = lpViperStruct->hBatData;
          }
    
    
          if (bInterfaceOk==FALSE) 
           {
    		 lstrcpy((LPSTR)lpvvArg,"Need newer version of WIL DLL");
           return (-1);
           }
    
    
    	//******* Add your one time initialization code here (if any)
    
        return ((sizeof(CommandExtTable) / sizeof(tablestruct)) - 1);  // 1 extra at end
    
        }
    
  16. Setup Case -2

    In WILExtender2, change case 98 to case -2, and update the code that loads the table information. Consider moving case -2 under case -1.

    In most cases you may be able to delete case 98 and cut and past the following code.

      /*---------------------------------------------------------------------------
        Case -2 is called repeatedly by the WIL extender.  On each call, one
        CommandTable entry is passed back to the WIL extender.  It is unlikely that
        you will need to modify this code.
        ---------------------------------------------------------------------------*/
          case -2:                           // Loading table
          {
            LPTABLESTRUCT lpTable;
            UINT          j;
    
            lpTable = (LPTABLESTRUCT) lpvvArg;
            j = (UINT) nArgCount;
    
            if (CommandExtTable[j].ident == -1)
              return (0);
    
            if (lpTable)
            {
              lpTable->ident  = CommandExtTable[j].ident;
              lpTable->type   = CommandExtTable[j].type;
              lpTable->param1 = CommandExtTable[j].param1;
              lpTable->ulMask = CommandExtTable[j].ulMask;
              lpTable->size   = lstrlen((LPSTR) CommandExtTable[j].delim);
              CharLower(CommandExtTable[j].delim);
              lstrcpy((LPSTR) lpTable->delim, (LPSTR) CommandExtTable[j].delim);
            }
    
            return (1);
          }
    

    In case 98, if you were accessing feature information passed as lp3, lp4, and lp5, that code needs to be updated. The relevant information is now passed as members of the LPVIPERSTRUCT structure. dwLevel can be checked in case -1. lpfnDllServices and hBatData can be saved to global variables in case -1, or used directly in any function that needs them.

  17. Rename case 99 to -3

    In WILExtender2, change case 99 to case -3. Consider moving it under case -2
  18. Delete case 100

    If you have a case 100, just delete it as it is now obsolete. Its functionality has moved to WILExtenderQuery, case 1.
  19. Update ADDONS.H file

    
    // Addon.h   Addon file for Wil 2001 AddOns
    
    typedef LPVOID LPBDS;                  // not really
    typedef LPVOID LPRESULTVAR;            // not really
    typedef LONG (FARPASCAL * DLLSERVICES) (HGLOBAL, WORD, LPSTR, LPSTR, int, DWORD);
    
    typedef struct
    {
      LPBDS       lpbdsptr;                // pointer to lpBDS (internal use)
      LPRESULTVAR lprvptr;                 // WIL resultvar (internal use)
      DWORD       dwLevel;                 // feature interface level
      DWORD       dwSize;                  // size of the structure
      DLLSERVICES lpfnDllServices;         // address of DLLServices function
      HGLOBAL     hBatData;                // buffer pointed to by lpBDS
    } VIPERSTRUCT, FAR *LPVIPERSTRUCT;
    
    typedef int FAR PASCAL AddOnCallback (int,LONG,LPSTR,BOOL,LONG,LPSTR);
    typedef AddOnCallback FAR *lpAddOnCallback;
    
    #define VARTYPE_UNDEF       0          // These are bitmapped, var can be both
    #define VARTYPE_INT         1          // Numeric and string, must check bits
    #define VARTYPE_STRING      2
    #define VARTYPE_FILE        5          // FILE and INT bits set
    #define VARTYPE_OLEOBJECT  17          // OLE AND INT bits set
    #define VARTYPE_FLOATNUM   32          // floating point
    #define VARTYPE_BINARY     65          // BINARY and INT bits set
    #define VARTYPE_ARRAY     256          // an array
    
    typedef struct vipervariable
    {
      double  flt;                         // 8-byte floating point number
      LONG    x;                           // if int variable, value is here
      int     inittype;                    // 0=uninitialized 1=int 2=string 3=both  yes can have both sometimes
      union
      {
        LPSTR lpstr;                       // pointer to string in string table
        DWORD handle;                      // handle for miscellaneous object types
      };
    } vipervar, FAR *LPVIPERVAR;
    
    
    
    
    typedef int FAR PASCAL ViperCallback (int,LONG,LPVIPERSTRUCT,LPVIPERVAR);
    typedef ViperCallback FAR *LPVIPERCALLBACK;
    
    
    
    
    #ifdef WIN32
    #define DllExport   __declspec(dllexport)
    DllExport LONG
    #else
    LONG
    #endif
    
    FAR PASCAL WILExtender2(HWND,
                              HINSTANCE,
                              LONG,
                              short,
                              LPVIPERCALLBACK,
                              LPVIPERSTRUCT,
                              LPLONG,
                              LPVIPERVAR,
                              LONG,
                              LPVIPERVAR);
    
    #ifdef WIN32
    #define DllExport   __declspec(dllexport)
    DllExport LONG
    #else
    LONG
    #endif
    
    FAR PASCAL WILExtenderQuery(short,
                                LPVOID,
                                LONG);
    
    #define COMMEXT_WILSON  0x30030105L
    
    
    //-------------------------------------------------------------------
    // MISC. DEFINITIONS
    //-------------------------------------------------------------------
    #define FUNCTION        2
    #define CONSTANT        3
    
    
    #define RESULT_CALLBACK_ERROR -4
    #define RESULT_FATAL_ERROR    -3
    #define RESULT_MODERATE_ERROR -2
    #define RESULT_MINOR_ERROR    -1
    #define RESULT_SUCCESS         0
    
    //-------------------------------------------------------------------
    //==== DELIMSIZE IS DEFINED BY INTERPRETER, DON'T CHANGE THIS! ======
    //-------------------------------------------------------------------
    #define DELIMSIZE  30
    #define KTDELIMSIZE  30                // Gives us 30 character function names. NO modify
    
    
    //-------------------------------------------------------------------
    // COMMAND EXTENSION STRUCTURES
    //-------------------------------------------------------------------
    
    
    
    typedef struct tableinfo
    {
      LONG    ident;                       // delimindex - must be consecutive!!!!!!
      LONG    type;                        // 2=FUNCTION 3=CONSTANT 4=COMMAND
      __int64 ulMask;                      // 64-bit mask (16 params, 4 bits each)
      LONG    param1;                      // (funct ? hi(reserved) lo(num-args))   (constant ? value)
      short   size;                        // length of function name
      char    delim[KTDELIMSIZE + 1];      // funct/const name - must be lowercase!
    } tablestruct, FAR *LPTABLESTRUCT;
    
    
    
    
    
    
    //#define MBSS(p1, p2) {MessageBox(GetFocus(), (p2), (p1), MB_OK | MB_SETFOREGROUND);}
    //#define MBSN(p1, p2) {char szDebug[20]; MyLtoa((p2), szDebug, 10); MessageBox(GetFocus(), szDebug, (p1), MB_OK | MB_SETFOREGROUND);}
    
    
    

    Additional conversion tasks

  20. Update help files

    References to 32I in the help file, especially in ALL the AddExtender Lines in the examples should be updated to reflect the new 34I name of the DLL. In most cases simply searching for 32I and replacing that with 34I should do the trick.
  21. DAT to EXT conversion and update

    The DAT files used by the old compiler have been renamed to EXT files. Verify the name change.

    Inside the new EXT file the filename of the extender dll should reflect the new 34I extension.

  22. README files

    The readme file accompanying the extender should mention the name change and any other relevant items, like the incompatibility with previous version. E.G.

    Ver 12345  Jan 11, 2001
    		The Wampwuzzy extender has been updated to a new 
    		format to allow more descriptive function names and 
    		additional parameters.  This version of the extender 
    		requires	WinBatch 2001A or newer to run.  This 
    		extender will not work on WinBatch 2000C or older.
    		
    		In addition, so as not to affect existing scripts using 
    		a previous version of this extender, the extender DLL 
    		has been renamed to include a 34I in the DLL name 
    		instead of a 32I.  Old and new versions of this 
    		extender can *usually* co-exist side by side.
    		
    		To use the new extender with old scripts and with 
    		WinBatch 2001A or newer you will need to change the 
    		AddExtender line in the script to reflect the new DLL 
    		name.   e.g.
    		
    		   AddExtender("wwabc32i.dll")
    		should become
    		   AddExtender("wwabc34i.dll")
    
  23. Additional Notes

    This process does a quick and dirty change of the extender to the new formats. With additional work the extender can be modified to accept parameters in "native" format rather than just accepting them as strings. When thus converted, the WIL Extnder can do parameter validation (ints will be ints, etc)