70
#GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants Mariano Gomez MVP Senior Software Engineer, Mekorma

#GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

Embed Size (px)

Citation preview

Page 1: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

#GPUGSummit

25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES

David Musgrave MVPManaging Director,

Winthrop Development Consultants

Mariano Gomez MVPSenior Software Engineer,

Mekorma

Page 2: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 2

Introductions

What is this madness?

25 Tricks and Hacks– Dexterity– Visual Studio Tools

Q & A

AGENDA

Page 3: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 3

Managing Director of Winthrop Development Consultants

Microsoft Dynamics GP Most Valuable Professional (MVP)

Worked with Microsoft for 13 and a half years

Lives in Winthrop, a suburb in the city of Perth

Where is Perth, Western Australia?

DAVID MUSGRAVE

Page 4: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

Fun facts:Perth is the most isolated capital city in the world

Perth has the largest inner city park in the world, Kings Park, yes, bigger than even New York’s Central Park. It was also the first park to be designated for public use in Australia in 1872 and host to Australia's largest wild flower show and exhibition.Sharks

Dolphins

Sharks

Sharks with Lasers for EyesStinging

Jellyfish

Razor Sharp Coral

Cyclones

Stingrays

Sharks

Fires

Poisonous Snakes

Crocodiles

Giant Rats

Dingoes

Scorpions

Scorching Desert

Giant Spiders

Mosquitoes

Man-eating Koalas

Drop Bears

NOTHINGFloods

Tasmanian Devils

Page 5: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

© Kirk Hille – All rights reserved. Photograph used with express permission from Kirk Hille.

Page 6: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 6

Senior Software Engineer at Mekorma

Microsoft Dynamics GP Most Valuable Professional (MVP)

Lives in Atlanta, Georgia, USA

Born on a small Colombian island off the coast of Nicaragua

Where is San Andres Island?

MARIANO GOMEZ

Page 7: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

Fun facts:At only 39 square km, the island of San Andres is one of the smallest islands in the Caribbean Sea

It belongs to Colombia, but was a former British territory up to the early 1800s

Page 8: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

© Thierry Desgans – All rights reserved. Photograph used with express permission from Thierry Desgans.

Page 9: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 9

Introductions

What is this madness?

25 Tricks and Hacks– Dexterity– Visual Studio Tools

Q & A

AGENDA

Page 10: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 10

Who has not worked with any of the tools? Who has worked with Modifier with VBA? Who has worked with Visual Studio Tools? Who has worked with Dexterity? Who has worked with Dexterity SBA or .Net Interop? Who has worked with more than one tool? Who has worked with more than one tool on a single project?

UNDERSTANDING THE AUDIENCE

Page 11: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 11

After the success of Mark Polino’s 50 tips in 50 minutes session at Convergence we thought we would try something similar

We wanted to provide an overview of some tricks that will make your development life easier

Also, we wanted to show some new techniques that you probably have not heard of before.

WHAT IS THIS MADNESS?

Page 12: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

LET’S GET STARTED

HOLD ON TIGHT

ASK QUESTIONS AT THE END

Page 13: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

DEXTERITY BEST PRACTICES

Page 14: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 14

Use a Binary sort order for your development and testing SQL Server environments

– This will ensure that any code executed directly on SQL Server, such as Pass through SQL, Range where clauses and stored procedures will have the correct case for database, table and column names.

– Avoids issues where supposedly working code starts failing at some customers when it works at other due to a Binary sort order.

– While Binary is not as commonly used now, there are many legacy sites still using it.

– Using Binary during development means that all code will work correctly for both Binary and DOCI.

1 OF 25: DEVELOP ON A BINARY SQL DATABASE

Page 15: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 15

Use a separate Dex.ini file for each project– Create a shortcut in the project folder to launch Dex.exe and pass the Dictionary file and Dex.ini file.

Source Code Control provides version control– Tools such as Visual Source Safe and Team Foundation Server provide version control and can assist

with multiple developers working on a single project. The generic text provide can still restore back to last version.

Source Code Control must be used for upgrades– As resource IDs can change between versions, you can no longer use Dexterity Utilities Transfer >>

Developer Update to upgrade between versions as this links using resource IDs when Source Code Control links using resource names. Using Developer Update can result in incorrect fields, datatypes, strings, etc. being used on a form.

– Developer Update is still great for combining an extracted source dictionary back into a clean Dynamics.dic dictionary of the same version to create a development dictionary.

2 OF 25: USE SOURCE CODE CONTROL (SCC)

Page 16: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 16

Use of an Index File with Source Code Control is not optional– As Source Code Control uses Resource Names as the primary key and does not store Resource IDs,

we must use an Index File to keep track of the Resource IDs assigned to resources.

– Always use the Update… option from the Explorer >> Source Control menu and check use Index File. Never use the Update button on the Resource Explorer window as this does not use the Index File.

– Always Update Index File when creating a new build for release to ensure any newly created resources are tracked.

What happens if you don’t use an Index File– Chunk Files can get corrupted when extracting over the previous extract dictionary.– Security records, shortcuts & command navigation become corrupted as resource IDs have

changed.

3 OF 25: USE AN INDEX FILE WITH SCC

Page 17: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 17

What is a _DUP Script?– A Dexterity event script on a form or window has two parts: The source code (with executable p-

code) and a link to a focus event, such as Form Pre, Window Post or Field Change.

– If you compile the code, but then fail to save the window or form, the script will exist in the dictionary, but the link will not have been saved.

– When you attempt the add the script again, the script name has already been used and so a _DUP suffix will be added.

Avoid _DUP Scripts with these simple steps– Immediately after creating a form or a window, close and save the window and click OK on the form.– Avoid discarding window changes or clicking cancel on forms after changes have been made to

scripts.

4 OF 25: SAVE FORMS & WINDOWS TO AVOID _DUP

Page 18: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 18

Create Worksets to group logical sections of your project together– Worksets are a collection of shortcuts to resources of any type in the

dictionary. Worksets can make finding resources much simpler. Using Worksets helps with memory

– Having a workset for a project will help when revisiting old projects or new developers to a project.

Create new resources while showing a workset– When new resources are created using the down arrow on the new button,

they are automatically added to the current workset. Backup the ctree files used to store the Worksets

– Make sure you backup the *ResExWsH.dat, *ResExWsH.idx, *ResExWsM.dat, *ResExWsM.idx files.

5 OF 25: USE DEXTERITY WORKSETS

Page 19: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 19

This is a little thing that can be very annoying– Please always add a blank line at the end of your scripts.

Why?– Because it allows the mouse to select the last line of the script when highlight with a

mouse.

– It allows for a new line to be added easily to the end of the script.

– It makes sure the syntax highlighting works as you are typing the script.

– It’s like putting the toilet seat down at home, it makes it much nicer for the next person.

6 OF 25: FINISH A SCRIPT WITH A BLANK LINE

Page 20: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 20

It is best to always create scripts so they compile with no errors or warnings.– This makes it easy to see when an issue has been introduced.

Handle Datatype mismatches– Either use the correct datatype to avoid overflow errors or use typing functions such as integer(),

long().– Avoid overflowing string datatypes, make sure they are long enough or use substring() to truncate.

As a last resort, use Pragma precompiler commands– For developer only warnings, pass through Dexterity sanScript or SQL code, use:– pragma(disable warning LiteralStringUsed); pragma(enable warning LiteralStringUsed); – For unused parameters on function and procedure trigger handling scripts, use:– pragma(disable warning UnusedVariable); – For placeholder scripts used for triggering against, use:– pragma(disable warning NoExecutableCode);

7 OF 25: CREATE CODE WITH 0 ERRORS & 0 WARNINGS

Page 21: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 21

When creating your trigger registrations make sure that every trigger failure error message is unique.– Include identification that the trigger is from your product:

<product name>:

– A suggestion is to use the fully qualified name of the resource:<field> of window <window> of form <form>

– Include the trigger type and attach type:field focus before change

Why?– It will make it simple for anyone to provide accurate information on exactly which trigger is causing

issues, probably due to a parameter change on a script, or a change on a 3 rd party form.

8 OF 25: UNIQUE ERRORS WHEN REGISTERING TRIGGERS

Page 22: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 22

Make the bare minimum changes needed to move or add fields.– Never delete an original field as this is likely to break existing code.– Add whatever additional fields you need, use align tools to help get user interface

layout correct.– Don’t forget to link prompts, link lookups and set the tab sequence.– No need to associate additional tables to the form.– Use Triggers to add scripts to form and include a check to see if alternate is in use to

avoid illegal address errors. Why?

– This approach is much easier to maintain, as you can identify where the scripts are without needing to check fields, run a script report, or find semicolons on the form.

– If you need to recreate the alternate window between versions, it is simple and you will get compile errors if you missed adding a field.

9 OF 25: DON’T ADD SCRIPTS TO ALTERNATE WINDOWS

Page 23: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

CHECKING IF ALTERNATE FORM IS IN USE - PART 1Global Procedure: Startup (excerpt)pragma(disable warning LiteralStringUsed);if Trigger_RegisterFocus(anonymous(form 'IV_Item_Maintenance'), TRIGGER_FOCUS_PRE, TRIGGER_BEFORE_ORIGINAL, script WDC_IV_Item_Maintenance_FORM_PRE) <> SY_NOERR then

warning “WDC: IV_Item_Maintenance form focus before pre trigger registration failed.";end if;pragma(enable warning LiteralStringUsed);

Global Trigger Procedure: WDC_IV_Item_Maintenance_FORM_PRE'WDC Alternate IV_Item_Maintenance' of globals = WDC_Check_Security_Alternate(Runtime_GetCurrentProductID(), FORMTYPE, technicalname(form IV_Item_Maintenance));

Page 24: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

CHECKING IF ALTERNATE FORM IS IN USE - PART 2Global Function: WDC_Check_Security_Alternate()function returns boolean OUT_Alternate;in integer l_AltDictID;in 'Restype' l_restype;in 'Resname' l_resname;local 'Resid' l_resid;local integer dictid;local string l_Alias;

OUT_Alternate = false;if l_AltDictID = DYNAMICS then

{ In Test Mode }OUT_Alternate = true;

elseif IMIntegrationMode of globals then

{ Integration Manager is running }OUT_Alternate = false;

else{ Runtime Mode }l_resid = Resource_GetID(l_AltDictID,l_restype,l_resname);dictid = DYNAMICS;

Page 25: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

CHECKING IF ALTERNATE FORM IS IN USE - PART 3Global Function: WDC_Check_Security_Alternate() cont.

case Security(dictid, l_restype, l_resid, l_Alias)in [REJECT_RECORD] { Access Denied }

OUT_Alternate = false;in [REJECT_SCRIPT] { Access to alternate and/or modified failed }

OUT_Alternate = false;else

if dictid <> DYNAMICS thenif dictid = l_AltDictID then

if l_Alias = str(l_resid) then{ Access to My Modified

Alternate }OUT_Alternate = true;

else{ Access to My Alternate }OUT_Alternate = true;

end if;end if;

end if;end case;

end if;end if;

Page 26: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 26

Using Runtime_GetCurrentProductID() creates code that works in both test mode and runtime mode.– In Dexterity Test mode, the function will return 0 as you are developing in a copy of the

Dynamics.dic dictionary.– In Runtime mode it will return the product ID of your product. – This is especially helpful when working with commands, command forms and menu

navigation.

When referencing your resources added by your product– Use Runtime_GetCurrentProductID().

When referencing existing resources in Dynamics.dic– Use the constant DYNAMICS, which has a value of 0.

10 OF 25: USE RUNTIME_GETCURRENTPRODUCTID()

Page 27: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 27

Well behaved ranges are inclusive ranges– Inclusive range: specify start record and end record and includes all records in between based on index

– Inclusive ranges behave the same on all database platforms, so will work with Ctree and Memory tables

Rules for a Well Behaved Range– In order of the segments/fields defined in the key/index:

1. Start and End segment must have 0 or more fields with the same value.

2. Start and End segment must have 0 or 1 field with different values (with Start less than End value)

3. Start and End segments must have the remaining values cleared/filled.

11 OF 25: USE WELL BEHAVED RANGES

Page 28: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 28

If you have a segment marked as descending in a key– All table actions involving that segment need to be treated in reverse.

Range Setting– If using different values, then Start value must be greater than End value

– If Clearing and Filling then Start value must be filled and End value cleared

Moving through the table– If wanting to move in ascending order, need to use get last table and get

prev table inside loop

12 OF 25: WORKING WITH DESCENDING KEY FIELDS

Page 29: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 29

Range Setting Requirements– Key fields for index in table buffer need to be set to start values when range start command issued.– Key fields for index in table buffer need to be set to end values when range end command issued.

Traditional Method of Range Setting– Clear table, set start values, range start table, set end value, fill remaining end values, range end table

Future Proof Range Setting– Clear table, set start values, range start table, fill table, set end values, range end table

Why?– Only need to add code for fields getting set to specific values, the rest are automatically cleared/filled– If additional key segments are added to the index, no need to revisit code to fix range

13 OF 25: USE FUTURE PROOF RANGE SETTING

Page 30: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

FUTURE PROOF RANGE SETTINGrange clear table <Table Name>;

clear table <Table Name>;‘<Field1>' of table <Table Name> = SingleValue;‘<Field2>' of table <Table Name> = StartValue;range start table <Table Name> by number <Sort>;

fill table <Table Name>;‘<Field1>' of table <Table Name> = SingleValue;‘<Field2>' of table <Table Name> = EndValue;range end table <Table Name> by number <Sort>;

Page 31: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

DEXTERITY ADVANCED TECHNIQUES

Page 32: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 32

Record a macro file while creating the chunk file– Start recording by closing Source, Editable and Destination Dictionaries– Record all steps including exiting Dexterity Utilities when finished– Edit the Macro file with Notepad.exe:

Change Second line: Logging file nulEnsure Last line: MenuSelect title File entry Exit

Launching the macro file– Create a shortcut to DexUtils.exe and pass the macro as a parameter; or– Create a batch file which runs DexUtils.exe and passes the macro as a parameter

Why?– Using a macro ensures that all builds are created with same settings and steps, avoids human error– You can manually edit the macro to include additional alternate forms and reports, if needed– You can manually edit build numbers when creating a new build– You can find and replace folder paths & update version numbers when starting a new version

14 OF 25: AUTOMATE CHUNK FILE CREATION

Page 33: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 33

Use a Batch File to automate chunk file deployment– Copy chunk file from development folder to application folder– Launch Dynamics application in unchunk only mode using /CNKONLY

Extend Batch File to create Dictionary Assemblies– Delete existing Dictionary Assembly *.xml and *.dll files– Run DAG.EXE (Dictionary Assembly Generator Tool)– Copy resulting Dictionary Assembly *.xml and *.dll files back to the development folder

Signing and Code Signing (Digital Signature)– DAG.EXE can sign the dll files generate using the /S option and passing in a *.snk key file– Signing should be used to give the dll files a unique and constant GUID. Required for web client– SIGNTOOL.EXE can be used to Code Signing the dll files to add a Digital Signature– If shipping a product, Code Sign the dll files so they are trusted & don’t need to be unblocked

15 OF 25: AUTOMATE CHUNK FILE DEPLOYMENT

Page 34: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

BATCH FILE TO AUTOMATE CHUNK FILE DEPLOYMENTCD C:\DEX1400\Projectcopy Project.cnk C:\DYN1400\*.*CD C:\DYN1400Dynamics.exe Dynamics.set /CNKONLY

if exist Application.ProjectName.dll del Application.ProjectName.dllif exist Application.ProjectName.xml del Application.ProjectName.xmlif exist Application.ProjectName.Metadata.dll del Application.ProjectName.Metadata.dllif exist Application.ProjectName.Metadata.xml del Application.ProjectName.Metadata.xml

C:\DEX1400\DAG.EXE ### /M /N:ProjectNamerem C:\DEX1400\DAG.EXE ### /M /N:ProjectName /S:C:\DEX1400\Project\Project.snkrem signtool sign /f "<Path to .pfx file>" /p <password> /t <web path to timestamp server>

Application.ProjectName.dll Application.ProjectName.Metadata.dll

copy /y Application.ProjectName.dll C:\DEX1400\Project\Application.ProjectName.dllcopy /y Application.ProjectName.xml C:\DEX1400\Project\Application.ProjectName.xmlcopy /y Application.ProjectName.Metadata.dll C:\DEX1400\Project\Application.ProjectName.Metadata.dllcopy /y Application.ProjectName.Metadata.xml C:\DEX1400\Project\Application.ProjectName.Metadata.xml

Page 35: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 35

A quick check for triggers against Dynamics.dic– Just going into Test Mode by pressing Ctrl-T from the Dexterity Development environment will

run the Startup script and its child scripts and validate that the triggers register without errors

– Pressing Ctrl-T once the login window is displayed returns you to the Development environment

Notes– Does not work for triggers against 3rd party products as Test mode does not have 3rd party

dictionaries loaded

– Does not work for triggers registered after login

– Handy quick check after upgrading to a new version of Dynamics to see if parameters have changed

16 OF 25: TRIGGER REGISTRATION ERRORS QUICK TEST

Page 36: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 36

What is the Command Form?– The Command Form is a hidden form used as a container for a products navigation commands– It is opened when the application starts and remains open until the application is closed– To make the form hidden, the form contains a window with AutoOpen=False and Title=~internal~

Store data on the hidden window on Command form– Once the form is open, the windows exist even if they are not displayed to the user– Additional fields can be added to the hidden window and used to store data instead of global variables– Additional hidden windows can also be created if you want to “organize” the fields

Why?– There is a limit to the memory that can be used as global variables, this method avoids hitting the limit– Faster than using memory tables or temporary tables to temporarily store data

17 OF 25: EXTRA USE FOR THE COMMAND FORM

Page 37: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 37

It is not always possible to stop Dexterity code– Reject script command only works for Focus event triggers running before the original– Sometimes it is just not possible to stop Dexterity code from running

Using a pre and post trigger you can change behavior– The pre trigger can store a value into a global variable or hidden field on command form and

replace the value with a custom value– The original code now runs with the custom value– The post trigger then restores the original value back from the global variable or hidden field

Why?– Depending the original code, this method can be used to either prevent original code from

working or make it work for you using your value rather than the original value– Re-uses existing code, can be much better than replacing the script and rejecting script– Allows other third party code triggering on the same location to still work

18 OF 25: THE TWO TRIGGER TECHNIQUE

Page 38: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

TWO TRIGGER TECHNIQUETrigger Procedure: WDC_Zoom_Button_CHG_PRE{ Back up Original Item Number }'WDC Item Number' of globals = 'Item Number';{ Replace Item Number with new value for Zoom }'Item Number' = 'New Item Number';

Trigger Procedure: WDC_Zoom_Button_CHG_POST{ Restore Original Item Number}'Item Number' = 'WDC Item Number' of globals;

Page 39: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 39

Two common uses for the technique– Limiting a trigger on a commonly called script so that the trigger is only executed when you want it– Capturing data or table references in one location to be used in a second location based on timing

Limiting execution of a Trigger to one location– Procedure A calls Function B, but Function B is used in many only locations. Want Trigger on Function B– Before Trigger on Procedure A sets global variable, After Trigger on Procedure A clears global variable– Trigger on Function B checks status of global variable and aborts if not set to true

Capturing Data or Table Reference– Procedure A calls Procedure B which passes temporary table buffer, then it populates the table, then calls

Procedure C, then processes table contents. Want to modify table contents before it is processed.– Before Trigger on Procedure B to capture table buffer reference can store it as a global variable– Trigger on Procedure C then uses table('Table Reference' of globals) to update table contents– After Trigger on Procedure A clears table reference global variable as it is no longer valid

19 OF 25: THE THREE TRIGGER TECHNIQUE

Page 40: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

THREE TRIGGER TECHNIQUE – TYPE 1Trigger Procedure: WDC_Procedure_A_PRE'WDC Function B Flag' of globals = true;

Trigger Function: WDC_Function_B_POSTif not 'WDC Function B Flag' of globals then

abort script;end if;{ Rest of code follows here }

Trigger Procedure: WDC_Procedure_A_POST'WDC Function B Flag' of globals = false;

Page 41: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

THREE TRIGGER TECHNIQUE – TYPE 2Trigger Procedure: WDC_Procedure_B_PREinout table TempTable;assign 'WDC Table Reference' of globals as reference to

table TempTable;

Trigger Function: WDC_Function_C_POSTclear table table('WDC Table Reference' of globals);{ Rest of code follows here }

Trigger Procedure: WDC_Procedure_A_POSTclear 'WDC Table Reference' of globals;

Page 42: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 42

Changing Context of Triggers using default command– Normally a trigger procedure runs in the same context as a global procedure.– Use default form to command to change context to form level (same as FORM_PRE or FORM_POST)– Use default window to command to change context to specific window on a form

Why?– This can make coding of scripts much simpler as there is no need to fully qualify the window and form– By changing context, you can access the form’s table buffers, including scrolling window or temp

tables

Notes– As scripts are now running in the context of the form, you cannot reference tables that are not

associated with the form.– To reference other tables, use global functions to perform any actions on other tables as needed.

20 OF 25: USING DEFAULT FORM / WINDOW TO

Page 43: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

DEFAULT FORM / WINDOW EXAMPLETrigger Procedure: WDC_IV_Item_Maintenance_WIN_PRE

if not 'WDC Alternate IV_Item_Maintenance' of globals thenabort script;

end if;

default form to IV_Item_Maintenance;default window to IV_Item_Maintenance;

hide 'Item Number';show 'New Item Number';

Page 44: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 44

Using Dexterity precompiler directives– Dexterity supports conditional compilation using #if, #elseif, #else and #end precompiler directives– Work with Constants defined in the dictionary, such as WDC_PROD_MAJ or DEBUG

Why?– You can use conditional compilation to maintain a single code base for a product for all current

versions of Microsoft Dynamics GP while still supporting new features. Conditional Compilation prevents compilation errors for missing resources, scripts or new sanScript commands and functions

– You can use conditional compilation based on a DEBUG constant to create “Debug” builds with additional messages which can be disabled by changing the constant to false before final builds

Notes– The Hash (#) must be the first character on the line to be identified as a pre-compiler directive– The lines are not terminated with a semicolon (;)

21 OF 25: USE CONDITIONAL COMPILATION

Page 45: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

CONDITIONAL COMPILATION EXAMPLE#if WDC_PROD_MAJ >= 12 then

{ Code for v12 or later }

#elseif WDC_PROD_MAJ = 11 then{ Code for v11 only }

#else{ Code for v10 or earlier }

#end if

Page 46: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 46

Passthrough SQL commands must be formed correctly– This includes commands executed by SQL_Execute(), where clauses used with range table where as

well as parameters passed to stored procedures

Strings and Maximum Character (missing Z issue)– Use SQL_FormatStrings(<Str>) to add single quotes and double up any single quotes to avoid injection– Use system 9600 command to obtain maximum character for SQL sort order. Fill gives char(255) = ÿ

Date and Time Issues– To avoid issues with date and time formats (both regional and user format) don’t use str() function– Use SQL_FormatStrings(sqlDate(<Date>)) for Dates, this uses format 'YYYYMMDD'– Use SQL_FormatStrings(sqlTime(<Time>)) for Times, this uses 24hr format 'HH:MM:SS'

More Information– http://blogs.msdn.com/b/developingfordynamicsgp/archive/2013/11/04/quick-tip-unusual-behaviou

r-when-working-with-sql-server-from-dexterity.aspx

22 OF 25: AVOID ISSUES WITH PASSTHROUGH SQL

Page 47: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

DEXTERITY WORKAROUND TECHNIQUE

Page 48: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 48

Version 12.0 of Dexterity changed form export format– This affects how pictures are associated with local push button fields in forms– Backward compatible: Versions 12.0 or later can import previous format without issues– However, version 11.0 or earlier will lose images from local pushbutton fields if importing new format

If working with a shared code base across versions– Suggest to always develop new code in v11.0 or earlier and export and import into v12.0 or later

How to fix exported form file to allow import– If you need to take an exported form back from v12.0 to v11.0, you can fix it with Notepad.exe– Find StaticType "Picture" Replace with StaticType "Mixed" but only for Control "PushButton"

Notes– Navigation commands defined on forms have additional options for v12.0 which can be lost if

importing from v11.0, it is best to just remake changes for each version for command forms– Global procedures on v14.0 can have SBA Metadata which will be lost if importing from v11.0

23 OF 25: ISSUE WHEN IMPORTING EXPORTED FORMS

Page 49: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

V11.0 OR EARLIER LOCAL FIELD FORMATDatatype "Export Button"

{Control "PushButton"DefaultDown "00000"DefaultMouseOver "00000"DefaultUp"00001"Prompt "E&xport"PromptDown ""PromptMouseOver ""StaticType "Mixed"~ItemImages{

PictItem "00001"{

Item "WindowToolbar_Transfer_PB_Up"}

}}

Page 50: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

V12.0 OR LATER LOCAL FIELD FORMATDatatype "Export Button"

{Control "PushButton"DefaultDown "00000"DefaultMouseOver "00000"DefaultUp"00001"Prompt "E&xport"PromptDown ""PromptMouseOver ""StaticType "Picture"~ItemImages{

PictItem "00001"{

Item "WindowToolbar_Transfer_PB_Up"}

}}

Page 51: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

DEXTERITY VERY ADVANCED TECHNIQUE

Page 52: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 52

What is the old() issue?– It is very common when writing custom code to need to change a field’s value– Usual method is to set field to the new value and use run script to execute the change script

– old() does not work when using set field, run script field, it returns the same as the current value– Hence no change is detected and diff() returns 0. This means that the code fails to work correctly– For example: Item allocations are not shifted between sites when changing the transaction location

The problem is focus– For old() to work, the field must have focus with the old value before the value is changed– Using the focus command does not actually take effect until all foreground scripts have completed

– Dexterity Help says: This function should not be used in a change script run using the run script or run script delayed statements. Focus must be in the field for which this function is run for it to operate properly.

24 OF 25: SOLVING THE OLD() ISSUE – METHOD 2 PT.1

Page 53: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 53

Solving the old() issue, this is better second method– Leverages functionality of open form return to <field> command and return command– When field is “returned”, the focus is placed on the field, the field is changed, then focus moves to

next field in the tab sequence which causes the change script to run

How it works– Create WDC_Return form with hidden Dummy window. On the hidden window have a local field of

each data type and a Return Pushbutton. Scripts then open form and return to the desired field

Notes– Cannot use ,nofocus option as that stops old() from working– Must use push button with run script to issue the return command– Cannot be used on last field in scrolling window as the tab off the field forces the scrolling window

to a new line, if necessary adjust tab sequence on modified window to workaround.

24 OF 25: SOLVING THE OLD() ISSUE – METHOD 2 PT.2

Page 54: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

SOLVING THE OLD() ISSUE EXAMPLETraditional Method'TRX Location' = '(L) Default Site';run script 'TRX Location';

New Method for which old() workscall WDC_Return, 'TRX Location', '(L) Default Site';

Page 55: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

SOLVING THE OLD() ISSUE CODE – PART 1Global Procedure: WDC_Returninout anonymous field INOUT_Field;in anonymous IN_Value;

if INOUT_Field <> IN_Value thencall Return of form WDC_Return, INOUT_Field, IN_Value;

end if;

Page 56: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

SOLVING THE OLD() ISSUE CODE – PART 2Form Procedure: Return of form WDC_Returninout anonymous field INOUT_Field;in anonymous IN_Value;

open form WDC_Return return to INOUT_Field;if isopen(form WDC_Return) then

case datatype(IN_Value)in [DATATYPE_BOOLEAN, DATATYPE_CHECK_BOX]

'(L) Mode' of window Dummy = DATATYPE_BOOLEAN;'(L) Boolean' of window Dummy = IN_Value;

in [DATATYPE_INTEGER, DATATYPE_PROGRESS_INDICATOR, DATATYPE_RADIO_GROUP, DATATYPE_TINY_INTEGER, DATATYPE_VISUAL_SWITCH]

'(L) Mode' of window Dummy = DATATYPE_INTEGER;'(L) Integer' of window Dummy = IN_Value;

in [DATATYPE_BUTTON_DROP_LIST, DATATYPE_DROP_DOWN_LIST, DATATYPE_HORIZONTAL_LIST_BOX, DATATYPE_LIST_BOX, DATATYPE_NON_NATIVE_LIST_BOX]

'(L) Mode' of window Dummy = DATATYPE_INTEGER;'(L) Integer' of window Dummy = IN_Value;

in [DATATYPE_LONG_INTEGER, DATATYPE_MULTI_SELECT_LIST_BOX]'(L) Mode' of window Dummy = DATATYPE_LONG_INTEGER;'(L) Long' of window Dummy = IN_Value;

Page 57: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

SOLVING THE OLD() ISSUE CODE – PART 3in [DATATYPE_CURRENCY]

'(L) Mode' of window Dummy = DATATYPE_CURRENCY;'(L) Currency' of window Dummy = IN_Value;

in [DATATYPE_VCURRENCY, DATATYPE_REAL]'(L) Mode' of window Dummy = DATATYPE_VCURRENCY;'(L) VCurrency' of window Dummy = IN_Value;

in [DATATYPE_DATE]'(L) Mode' of window Dummy = DATATYPE_DATE;'(L) Date' of window Dummy = IN_Value;

in [DATATYPE_STRING]'(L) Mode' of window Dummy = DATATYPE_STRING;'(L) String' of window Dummy = IN_Value;

in [DATATYPE_TIME]'(L) Mode' of window Dummy = DATATYPE_TIME;'(L) Time' of window Dummy = IN_Value;

elseabort script;

end case;run script '(L) Return' of window Dummy;

end if;

Page 58: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

SOLVING THE OLD() ISSUE CODE – PART 4Field Change Script: Dummy l_Return_CHGcase '(L) Mode'

in [DATATYPE_BOOLEAN]return '(L) Boolean';

in [DATATYPE_INTEGER]return '(L) Integer';

in [DATATYPE_LONG_INTEGER]return '(L) Long';

in [DATATYPE_CURRENCY]return '(L) Currency';

in [DATATYPE_VCURRENCY]return '(L) VCurrency';

in [DATATYPE_DATE]return '(L) Date';

in [DATATYPE_STRING]return '(L) String';

in [DATATYPE_TIME]return '(L) Time';

elseend case;close form WDC_Return;

Page 59: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

VISUAL STUDIO TOOLS

Page 60: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 60

Visual Studio Tools addons without WinForms– A Visual Studio Tools addon that does not have any WinForms, but only uses original or

modified Dexterity forms should be able to work on the Web Client without much additional work

DLL files must be signed– Both Dictionary Assembly and Addon dll files must be signed to work on the web client

Supported Platform must be enabled– The SupportedDexPlatforms property must be set for both DesktopClient (default) and

WebClient– Commands are similar but slightly different for C# and Visual Basic.Net, added above

class GPAddIn

25 OF 25: USING ADDONS WITH THE WEB CLIENT

Page 61: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

ENABLING ADDON FOR WEB CLIENTC#[SupportedDexPlatforms(DexPlatforms.DesktopClient | DexPlatforms.WebClient)]public class GPAddIn : IDexterityAddIn VB<SupportedDexPlatforms(DexPlatforms.DesktopClient Or DexPlatforms.WebClient)>Public Class GPAddIn

Page 62: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

SERVICE BASED ARCHITECTURE

Page 63: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 63

Form ServiceCodeGenerator– Hidden form in the Dynamics.dic dictionary

Create .Net Objects– Create a .Net Object script template from table definitions

Map Fields from Object to window fields– Creates the scripts to be used for a window wrapped service

Set Object from Table– Creates the scripts to be populate the object variable from a table record

26 OF 25: BONUS TIP: SERVICE CODE GENERATOR

Page 64: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 64

Page 65: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

ALMOST DONE

Page 66: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 66

If you liked this session and want more– Make sure you say so in your conference evaluation and feedback

We have more tricks and hacks– While preparing for this session, we created over 60 tricks and hacks– It was difficult to select the first 25 to include in this session

Do you have any cool tricks and hacks?– If you have something cool you have worked out, please let us know

and we might include it in future sessions and give you credit

27 OF 25: WANT MORE, JUST ASK

Page 67: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

WE MADE IT

LINKSQ & A

Page 68: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15 68

David Musgrave’s Winthrop Development Consultants Bloghttp://www.winthropdc.com/blog

The Dynamics GP Blogster blog (by Mariano Gomez)http://dynamicsgpblogster.blogspot.com/

Developing for Microsoft Dynamics GP Blog – retired(by David Musgrave & the Developer Support Team)

http://blogs.msdn.com/DevelopingForDynamicsGP/ or http://aka.ms/Dev4DynGP

LINKS

Page 69: #GPUGSummit | #INreno15 #GPUGSummit 25 DEVELOPMENT TRICKS AND HACKS IN 50 MINUTES David Musgrave MVP Managing Director, Winthrop Development Consultants

#GPUGSummit | #INreno15

Click icon to add picture

CONTACT PRESENTERS

David [email protected]@winthropdc

Mariano [email protected] @dgpblogster