Navigation:  Runtime Engine Version >

Creating a deployable Data Convertor

Previous pageReturn to chapter overviewNext page
Show/Hide Hidden Text

Steps needed to deploy a Clarion program that reads client data files and transfers them to a target database.

(by Russ Eggen)

 

(or you can use the demo executable and clarion7 application we ship and tweak it to your taste and needs (looks) using the INI file technique)

(This executable contains the RT installer and a copy of our Setup Builder script to allow you to better adapt to your "case")

Data Management Center

The first step is to create a thoroughly tested profile.

A profile in DMC is defined as a collection of data about how to connect to a database, location and names of the source data files and the script commands to create all the tables and finally copy the data from source to target.

How one goes about this is beyond the scope of this document, however the steps required in DMC to build a profile is straightforward.

DMC has the ability to convert your Clarion dictionaries and applications to support various flavors of SQL.  It greatly alleviates the tedium and time doing so.

This document assumes that you not only have a working profile, you also have compiled and run your SQL flavored applications.

Why a Profile program?

The profiles DMC creates for you are not executable programs, it’s simply a collection of data and instructions, ready for a program to execute (in this case the DMC runtime).  In addition, you would have to get your customers to run a number of complex steps in the runtime, in the correct order, making zero mistakes to pull off the conversion of their data.  And more than likely a customer won’t instantly sign off on such a project in one go, so profiles must be run every time a client wishes to see the latest data in a database.

It does not happen that way.

Therefore a customer (especially one who has already seen and likes your work) expects to see a program.  Many won’t appreciate a batch file either.  They want and expect GUI.  The easier to set up and run the program, the better your customers like it.  “Just press this button” would be ideal, but in this case, not very practical.

What needs to happen?

What are the design elements, or more specifically, are the pieces to make this work?  What do you have to deploy?  What is sent to the customer to run remotely for their local (in some cases remote) database?.

The Project

DMC builds projects you refer to by number.  The first project number is always 6 since DMC has five built in projects.  It would be nice to refer to these projects by a unique name, but knowing the project number is enough.

Using DMC, execute and run this project over and over until you are happy everything is working and all the data copied to the database.  Having this working perfectly is essential, so test it.  Fix any issue you find and re-make the profile and test it.  Repeat until perfect.

Depending on how you want to use DMC, you can make new projects (with increasing numbers) or delete the old project and re-create it preserving the project number.  Your call as to which one is best for you.  You may wish to make two projects, one for your local database and one for remote.  The connection string is inside the project.  You don’t have to do this as the connection string may be overridden (more on that later).

Export the project

In DMC, you must export the project to make it deployable to the customer.  You perform this step only after you have completed all tests of the project.  This copies two files to folders of your choosing.  This choice is critical as you need to find them later, so don’t choose a folder you never made if you don’t wish to search your drives for where they went.  I’d suggest sub folders under your Clarion project.

You need a project folder and a script folder, but I believe you could use one folder for both.  The files copied are just TPS files and these go with your Clarion program, so don’t leave them behind.

The Clarion Application

DMC makes available a demo application that shows how to run a project, but it’s not everyone’s cup of tea.  If it’s a one-off program meant to be executed only once, then it’s fine.  Learning its complex interface is not really a factor, it’s designed to teach you how to make a deployment program.  It would be best to code your own and make it simple, customized for the customer in mind.

Talking to DMC

Due to your license for DMC, you cannot deploy DMC at your client’s site.  I’d recommend against it as it is a developer interface.  There are lots of things not visible to users that are important, depending on what you need to do.  Besides, your customers are not converting Clarion source code either, and the bulk of its interface deals with just that aspect.

DMC comes with a deployable runtime which you can send to your end users.  This is a typical install program, totally silent and removes itself after installation.  This installation program is important as it sets some things in the registry in addition to copying its required files.  It’s against this environment your Clarion data program operates.

All your program really does is setup its environment for the DMC Runtime to get its instructions and then calls the runtime.  There are a lot of steps required to ensure this runs properly.  One thing to note: You have the option to use INI files settings or Registry settings, but there are some settings in the DMC runtime that are always in the registry.  Do not change these settings or the project will never run.

Note: The actual design of your conversion is up to you.  Thus this document does not incorporate any design ideas.

Sequence of source code

The following code is needed to get your program to work.

Global DMC Extension template

Add the DMC Runtime Engine Global template to your global extensions.  This is simply a list of various global variables used by DMC allowing you to override them with your own.  The defaults in this template work, so the minimal action you need to do is simply add the template.  Any changes to it are optional.

Global embeds

DMC Runtime (hereafter referred to as RT) does not need these equates, they are for you, the developer.  It just makes the code easier to understand.

 

Place this in a GlobalData embed:

eClose              EQUATE(0)       ! RT

eOpenRT             EQUATE(1)

eCallRT             EQUATE(2)

 

ePidCreateDB        EQUATE(1)       ! Tasks

ePidCreateTables    EQUATE(2)

eInfosStartup       EQUATE(3)

 

eLink_INI           EQUATE(1)       ! Tasks

eLink_REG           EQUATE(2)

 

ePidDeploy          EQUATE(6)      !Your project ID

 

Calling the RT is done via the ShellExecute API.  You could use the RUN() statement, I just find the API easier and more flexible.

 

Add this to another GlobalData end:

GLO:ProgramToRun         STRING(255)                        ! ShellExecute

GLO:WaitForProgram       BYTE

GLO:Parameter            STRING(255)

GLO:StartupFolder        STRING(255)

GLO:Elevate              BYTE

GLO:PathToUse            STRING(255)

 

If you need or wish to assign default values to any variables, use the Program Setup embed.

Startup embeds

The choice of which embeds you consider startup is up to you, it may be global, or inside the first procedure.  Either way will work.

 

The following code must be done first; it reads the registry for values placed there by the RT installation program:

DMC_RTPath     = GETREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','Directory Installation')          ! path of the **DMC RT engine** ALWAYS read from REGISTRY  ***DO NOT CHANGE***

DMC_RTPathData = GETREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','Directory Data')                

! path of the DMC RT engine **DATA SUBFOLDER** ALWAYS read from REGISTRY ***DO NOT CHANGE***

 IF ~DMC_RTPath

   DMC_RTPath     = GETREG(REG_LOCAL_MACHINE,'SOFTWARE\CGF\Data Management Center RT','Directory

Installation')

   DMC_RTPathData = GETREG(REG_LOCAL_MACHINE,'SOFTWARE\CGF\Data Management Center RT','Directory Data')

 END

 DMC_RTPathData = CLIP(DMC_RTPathData) & '\cgf_import\'             ! define Final Full Path  ***DO NOT

CHANGE***

 CloseMe = False

 

 ! Read from INI file your settings

 ProjectToRun     = GETINI('Deploy','ProjectID','','.\dmc_converter.ini')

 DMC_GLO:DRIVER_D = GETINI('Deploy','Driver'   ,'','.\dmc_converter.ini')

 DMC_GLO:SERVER_D = GETINI('Deploy','Server'   ,'','.\dmc_converter.ini')

 DMC_GLO:USER_D   = GETINI('Deploy','User'     ,'','.\dmc_converter.ini')

 DMC_GLO:PWD_D    = GETINI('Deploy','Pwd'      ,'','.\dmc_converter.ini')

 DMC_GLO:PORT_D   = GETINI('Deploy','Port'     ,'','.\dmc_converter.ini')

 DMC_GLO:DB_D     = GETINI('Deploy','DBName'   ,'','.\dmc_converter.ini')

 DMC_GLO:TYPE_D   = GETINI('Deploy','SQL_Type' ,'','.\dmc_converter.ini')

 PathToTPS        = GETINI('Deploy','PathToTPS','','.\dmc_converter.ini')

 MasterDBName     = ''

 IF ~DMC_GLO:DRIVER_D

   DMC_GLO:DRIVER_D = 'MySQL ODBC 5.1 Driver'

 END

 ePidDeploy       = ProjectToRun

 

The above simply assigns default values to DMC variables (placed there by the global template).  The above assumes a MySQL 5.1 driver, but it may be any valid SQL driver.  To make this easier, simply copy the driver string used in DMC to establish your ODBC connection and verify it is correct.  You may also setup EQUATEs in you global embeds for all the driver strings you plan on using if more than one.

Close Down Code

Again, this code may be placed in global embeds, before your program quits or in the Kill embed of your first procedure:

 

PUTINI('RT Engine','TaskName','',CLIP(DMC_RTPathData) & 'dmcrt.log') ! Empty all logs

PUTINI('RT Engine','CurrentProgress',0,CLIP(DMC_RTPathData) & 'dmcrt.log')

PUTINI('RT Engine','TotalProgress',0,CLIP(DMC_RTPathData) & 'dmcrt.log')

PUTINI('RT Engine','ProjectEnd',0,CLIP(DMC_RTPathData) & 'dmcrt.log')

 

As the code implies, this above empties the log files.  Just a bit of clean up.  

The Initial Steps

Now comes the series of steps to setup and run your profile.  Most of this code defines the environment the RT expects in order to execute the profile correctly.  Depending on your design, the following code may appear in any procedure (providing the execution sequence of your procedures follows these steps in sequence), or you may place these steps in one procedure.  If you use a procedure template (like a process procedure), each of the following steps are in ThisWindow.Init().

 

Place this code right after the CODE statement in ThisWindow.Init():   DMC_GLO:READ_REG       = 0         ! DMC Runtime Engine side (defining parameters to be passed)        !

 DMC_GLO:READ_INI       = 0

 DMC_GLO:RUN_SILENT     = 0

 DMC_GLO:AUTOCLOSE      = 0

 DMC_RTCommandLine      = ''

 DMC_GV:ProjectStarted  = 0

 DMC:LINK               = ''

 DMC:Errors             = 0

 FREE(DMC_Q)                         ! Free the QUEUE

 CLEAR(DMC_Q)

 

Step One

The RT allows for the option of using either the registry or INI files, but regardless of which one you choose, there are registry values that the RT expects and these are always used (Priority 500)

 

The first part of Step One is to reset the log file used to read the progress bar values:

 PUTINI('RT Engine','ProjectName'     ,''  ,CLIP(DMC_RTPathData) & 'dmcrt.log')

 PUTINI('RT Engine','TaskName'        ,''  ,CLIP(DMC_RTPathData) & 'dmcrt.log')

 PUTINI('RT Engine','CurrentProgress' ,''  ,CLIP(DMC_RTPathData) & 'dmcrt.log')

 PUTINI('RT Engine','TotalProgress'   ,''  ,CLIP(DMC_RTPathData) & 'dmcrt.log')

 PUTINI('RT Engine','ProjectEnd'      ,''  ,CLIP(DMC_RTPathData) & 'dmcrt.log')

 

Reset the INI files used to read values:

 PUTINI('Path','Project'  ,'',CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'Driver'   ,'',CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'Server'   ,'',CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'User'     ,'',CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'Pwd'      ,'',CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'Port'     ,'',CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'DBName'   ,'',CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'SQL_Type' ,'',CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'Path'     ,'',CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'CreateDB' ,'',CLIP(DMC_RTPathData) & 'dmc_rt.ini')    

 PUTINI('DB'  ,'MasterDB' ,'',CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 

Then reset the registry entries the RT needs:

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','PathToUse'     ,'')

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_Driver'     ,'')

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_Server'     ,'')

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_User'       ,'')

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_Pwd'        ,'')

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_Port'       ,'')

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_CreateName' ,'')

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_Type'       ,'')

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_CreateDB'   ,'')

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_MasterDB'   ,'')

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','Script_Path'   ,'')

 

The following code places a value in the registry for the RT to check that its internal structure checks and needed conversions happen as a new version of the RT may have changed internal structures:

 

PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','New Version',2)

 

And finally, set the owner name of the internal RT files so they open correctly.  Do not change this value or your application won’t be able to open the needed files:

 

DMC:OWNER = '#Crypted@'        

Step Two

Prime the internal  variable with your project ID (a project contains many profiles, one for each table):

DMC:PRJ_ID = xProjectID

Step Three

Your application needs to know where the RT’s link table is (defined as a table that contains connection information):

DMC:LINK = CLIP(DMC_LINK_PATH) & '\DMCRT_ODBC.TPS'

Step Four

The RT has the option of running silently, meaning no detailed display is shown to a user.  So if it does run silently, the actions should be written to a log file:

IF DMC_GV:RunSilent

   IF DMC:PRJ_ID = ePidDeploy

     PUTINI('RT Engine','ProjectName','Deploy SQL application',CLIP(DMC_RTPathData) & 'dmcrt.log')

   ELSIF DMC:PRJ_ID = ePidCreateDB

     PUTINI('RT Engine','ProjectName','Create SQL dataBase',CLIP(DMC_RTPathData) & 'dmcrt.log')

   ELSIF DMC:PRJ_ID = ePidCreateTables

     PUTINI('RT Engine','ProjectName','Create all SQL Tables',CLIP(DMC_RTPathData) & 'dmcrt.log')

   END

 END

 ! READ the Project Name for display

 DMC_GV:ProjectName = GETINI('RT Engine','ProjectName','',CLIP(DMC_RTPathData) & 'dmcrt.log')

Step Five

This tells the RT to use either INI or registry settings.

IF LinkMethod = eLink_REG

   DMC_GLO:READ_REG   = 1

   DMC_GLO:READ_INI   = 0

   DO REG_Settings

 ELSIF LinkMethod = eLink_INI

   DMC_GLO:READ_INI   = 1

   DMC_GLO:READ_REG   = 0

   DO INI_Settings

 END

Step Six

Inform the RT to run silently as a default.  Depending on your design, this could be overridden by user action:

DMC_GLO:RUN_SILENT = DMC_GV:RunSilent

Step Seven

Set the auto closedown value and check for errors: DMC_GLO:AUTOCLOSE  = CLIP(DMC_GV:AutoClose)

 

IF (DMC_GLO:READ_REG = 1 AND DMC_GLO:READ_INI = 1) OR (DMC_GLO:RUN_SILENT = 1 AND DMC_GLO:AUTOCLOSE  <> 1)

 MESSAGE('Error in settings')

 DMC:Errors = 1

 RETURN LEVEL:User

ELSE

 DO AffectVariables

END

Step Eight

This and the next step are really the same step, depends if you are using the INI method to communicate with the RT or the registry.  The following is the INI code:

INI_Settings            ROUTINE  

 PUTINI('Path','Project'  ,DMC_LINK_PATH   ,CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'Driver'   ,DMC_GLO:DRIVER_D,CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'Server'   ,DMC_GLO:SERVER_D,CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'User'     ,DMC_GLO:USER_D  ,CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'Pwd'      ,DMC_GLO:PWD_D   ,CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'Port'     ,DMC_GLO:PORT_D  ,CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'DBName'   ,DMC_GLO:DB_D    ,CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'SQL_Type' ,DMC_GLO:TYPE_D  ,CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB'  ,'MasterDB' ,MasterDBName    ,CLIP(DMC_RTPathData) & 'dmc_rt.ini')  

 PUTINI('DB'  ,'Path'     ,DMC_SCRIPT_PATH ,CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 IF DMC:PRJ_ID    = ePidDeploy                               ! Deploy

   PUTINI('DB'  ,'CreateDB' ,'YES'         ,CLIP(DMC_RTPathData) & 'dmc_rt.ini')  

 ELSIF DMC:PRJ_ID = ePidCreateDB                             ! Create DataBase

   PUTINI('DB'  ,'CreateDB' ,'YES'         ,CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 ELSIF DMC:PRJ_ID = ePidCreateTables                         ! Create all SQL tables

   PUTINI('DB'  ,'CreateDB','NO'           ,CLIP(DMC_RTPathData) & 'dmc_rt.ini')  

 END

 EXIT

Step Nine

REG_Settings            ROUTINE    

 PUTINI('DB','CreateDB','YES',CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTINI('DB','MasterDB',MasterDBName    ,CLIP(DMC_RTPathData) & 'dmc_rt.ini')

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','PathToUse',DMC_LINK_PATH   )        

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_Driver',DMC_GLO:DRIVER_D)      

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_Server',DMC_GLO:SERVER_D)    

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_User',DMC_GLO:USER_D  )  

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_Pwd',DMC_GLO:PWD_D   )  

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_Port',DMC_GLO:PORT_D  )    

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_CreateName',DMC_GLO:DB_D    )  

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_Type',DMC_GLO:TYPE_D  )  

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_MasterDB',MasterDBName    )  

 PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','Script_Path',DMC_SCRIPT_PATH )

 IF DMC:PRJ_ID = ePidDeploy

   PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_CreateDB','YES'           )

 ELSIF DMC:PRJ_ID = ePidCreateDB

   PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_CreateDB','YES'           )

 ELSIF DMC:PRJ_ID = ePidCreateTables

   PUTREG(REG_CURRENT_USER,'SOFTWARE\CGF\Data Management Center RT','DB_CreateDB','NO'            )

 END

 EXIT

Step Ten

This simply assigns the path your customer’s data files.  The assumption here is that you provide a user interface to allow the customer to select the folder where their data is.

AffectVariables      ROUTINE    

 IF DMC:PRJ_ID = ePidDeploy

   DMC_GLO:PATH_S  = PathToTPS

 END

 EXIT

Step Eleven

If this is a process procedure (recommended for reading through the DMCRT_ODBC.TPS file), then the final step is to build the command line for the RT.  It’s very important the command line arguments are built in the correct order.

IF DMC:Errors = 0    

 DMC_RTCommandLine = '/A:' & CLIP(DMC_GLO:AUTOCLOSE)   ! AutoClose parameter

 IF DMC:PRJ_ID = ePidDeploy                            ! PROJECT Id parameter

   DMC_RTCommandLine = '/A:' & CLIP(DMC_GLO:AUTOCLOSE) & ' /B:' & DMC:PRJ_ID & ' /DEPLOY:1'

 ELSIF DMC:PRJ_ID = ePidCreateDB

   DMC_RTCommandLine = CLIP(DMC_RTCommandLine) & ' /DB:1'

 ELSIF DMC:PRJ_ID = ePidCreateTables

   DMC_RTCommandLine = CLIP(DMC_RTCommandLine) & ' /SCRIPT:1'

 END

 

Next instruct the RT to read from registry or INI if not in viewer mode:

IF DMC_GLO:READ_REG = 1    

   DMC_RTCommandLine = CLIP(DMC_RTCommandLine) & ' /R:1'

 ELSIF DMC_GLO:READ_INI = 1  

  DMC_RTCommandLine = CLIP(DMC_RTCommandLine) & ' /I:1'

 END

 

Instruct the RT to run in silent mode or not:

IF DMC_GLO:RUN_SILENT = 1

   DMC_RTCommandLine = CLIP(DMC_RTCommandLine) & ' /S:1'

 ELSE

   DMC_RTCommandLine = CLIP(DMC_RTCommandLine) & ' /S:0'

 END

 

Final parameter and check for any errors at this point:

DMC_RTCommandLine = CLIP(DMC_RTCommandLine) & ' /L:1'

 DMC_GV:CarryOn = eCallRT                             ! Notify the Main Window to run the RT engine

ELSIF DMC:Errors = 2

 MESSAGE('Error while updating the project')

 DMC_GV:CarryOn = eClose

END

Calling the DMC Runtime Engine

You are most likely to define a different procedure to call the RT.  You don’t actually have to, depends on your design.  You do need some structures for ShellExecute, so use this code in a data embed:

 

ITV       LIKE(IT_OSVERSIONINFO)               ! ShellExecute

Res       IT_Bool

pi        LIKE(IT_PROCESS_INFORMATION)

si        LIKE(IT_STARTUPINFO)

cCmdLine  &CSTRING

cParam    &CSTRING

RetVal    LONG

RetValue  LONG

hProc     IT_HANDLE

lRetCode  IT_DWORD

SHi       LIKE(IT_SHELLEXECUTEINFO)

Verb      CSTRING(31)

P         CSTRING(260)

The following is a routine that calls ShellExecute.  This is where the RT launches:

 

IT_RunProg     ROUTINE           ! Do not touch - Routine to run the DMC RT

 IF GLO:ProgramToRun

   cCmdLine &= NEW CSTRING(LEN(CLIP(GLO:ProgramToRun))+1)

   cCmdLine = CLIP(GLO:ProgramToRun)

   cParam &= NEW CSTRING(LEN(GLO:Parameter)+1)

   cParam = GLO:Parameter

   P = GLO:StartupFolder

   P = SHORTPATH(P)

   Verb = IT_SE_Open   !! Defaults to not elevated

   IF GLO:Elevate

     Verb = IT_SE_RunAs  !! Elevate to requireAdministrator

   END

   SHi.fMask                  =  IT_SEE_MASK_NOCLOSEPROCESS

   SHi.hwnd                   =  0{PROP:Handle}

   SHi.lpVerb                 =  ADDRESS(Verb)

   SHi.lpFile                 =  ADDRESS(cCmdLine)

   SHi.lpParameters           =  ADDRESS(cParam)

   SHi.lpDirectory            =  ADDRESS(P)

   SHi.nShow                  =  IT_SW_SHOWNORMAL

   SHi.lpIDList               =  0

   SHi.lpClass                =  0

   SHi.hkeyClass              =  0

   SHi.dwHotKey               =  0

   SHi.DUMMYUNIONNAME         =  0

   SHi.cbSize                 =  SIZE(SHi)

   IF NOT IT_ShellExecEx(ADDRESS(SHi))

     hProc = 0

   ELSE

     hProc = Shi.hProcess

   END

 END

 IF hProc

   IF GLO:WaitForProgram

     RetVal = IT_WaitForSingleObject(hProc,-1)

     IF IT_GetExitCodeProcess(hProc, lRetCode)

       RetValue = lRetCode

     ELSE

       RetValue = RetVal

     END

     RetVal = IT_CloseHandle(hProc)

   END

 END

 IF NOT cCmdLine &= NULL

   DISPOSE(cCmdLine)

 END

 IF NOT cParam &= NULL

   DISPOSE(cParam)

 END  

 EXIT

Calling the ShellExecute Routine

This code is placed in the EVENT:Timer embed, so add a timer attribute to your window.  A one second timer value works fine, so enter 600 for the timer value in your window.  Note: if you add to small of a number, the EVENT:Timer fires too quickly and may actually slow your application down.

 IF DMC_GV:CarryOn = eOpenRT

   DMC_GV:CarryOn = eClose       ! To stop the Timer sending a second time

   DO ClearDisplays              !Optional routine for interface

   DMC_RT_Process(DMC_GV:ProjID) ! ID of Profile to Run

 END

 

The final pieces for ShellExecute and calling the above routine:

 

 IF DMC_GV:CarryOn = eCallRT

   DMC_GV:CarryOn = eClose       ! To stop the Timer sending a second time

   DMC_GV:ProjectStarted = True

   ITV.dwOSVersionInfoSize = SIZE(ITV)

   Res = IT_GetVersionEx(ITV)

   GLO:ProgramToRun =  '"' & CLIP(DMC_RTPath) & '\dmcrt.exe' & '"'

   GLO:WaitForProgram =  0

   GLO:Parameter = ' ' & CLIP(DMC_RTCommandLine)

   GLO:StartupFolder = DMC_RTPath

   GLO:Elevate = CHOOSE(ITV.dwMajorVersion =>6,False,True)

   DO IT_RunProg         ! The call to run RT

 END

 

Note: If you set the above GLO:WaitForProgram to 1, your application may appear to freeze until the RT finishes.

The next code to execute in the timer embed is to update the progress bars:

 

 IF DMC_RTPathData AND DMC_GV:RunSilent = True AND DMC_GV:ProjectStarted = True

    IF DMC_GV:ProjID = ePidDeploy  !Progress bar updated for backup and deploy tasks

      DMC_GV:ProgressTotal = GETINI('RT Engine','TotalProgress',0 ,CLIP(DMC_RTPathData) & 'dmcrt.log')

    END

    DMC_GV:ProgressCurrent = GETINI('RT Engine','CurrentProgress',0 ,CLIP(DMC_RTPathData) & 'dmcrt.log')

    DMC_GV:TaskName = GETINI('RT Engine','TaskName','',CLIP(DMC_RTPathData) & 'dmcrt.log')

    DMC_GV:ProjectEnd = GETINI('RT Engine','ProjectEnd',0 ,CLIP(DMC_RTPathData) & 'dmcrt.log')

   IF DMC_GV:ProjectEnd = True

     DO DisplayEndProject   !Optional routine to update displays at end

     POST(Event:CloseWindow)

   END

 ELSIF DMC_RTPathData AND DMC_GV:RunSilent = False AND DMC_GV:ProjectStarted = True

       DMC_GV:ProjectEnd = GETINI('RT Engine','ProjectEnd'    ,0 ,CLIP(DMC_RTPathData) & 'dmcrt.log')

   IF DMC_GV:ProjectEnd = True        ! end of Project

     DO DisplayEndProject   !Optional routine to update displays at end

     POST(Event:CloseWindow)

   END

 END

Summary of your conversion program

The above is the essential elements needed for a conversion of data.  The design element and look and feel is up to you thus are deliberately omitted from this document.  The recommendation is a program that may be run many times as on-site testing requires.  This means it must be very easy for non-technical, yet trusted users to run. You may make the design as complex or as simple as you want.  You may even wish to use a hand coded project with minimal user interface or an ABC application that walks them through each step or something in between.

Good designs are everywhere, but what makes a good design is minimal required action on the part of a user or asking them to interact with something they may not even know the meaning of.  For this reason, I really don’t favor a wizard type interface.  That’s fine for the first time its run, but then the program feels slow as the user is required to click through windows they know are not changing.

Simple is good: just make a one window interface with minimal required interactions.  Does not mean you can’t expose more technical information, but such elements confuse end users.  The final design is really up to you and who your users are.

Deploying your conversion program

You now have a program that copies data from the source data to the target on your development machine.  Now you need to deploy your application to the user so they may test.  How this is done varies, so that is up to you.

What this section covers is more of what you must send to your customers.  There is more to it than simply the executable and any DLLs.  You need some files DMC created when you made the project with the profiles.

This document assumes a sub folder where the EXE runs, but there is no reason why they cannot be in the same folder where the EXE runs or some other deployment folders, as long as you know where to find it without thinking.

Note: For purposes of this discussion, the install location of DMC is always omitted since its installation program allows you to place it anywhere you want.

When you export a project, DMC creates all the items you need in a folder called \cgf_import\prj\exports\<project name>.  All the files there must be deployed with your program.

Summary

This is just a quick summary of what your conversion program must do so customers may do the conversions on their own and safely.

Actual program design varies of course.