Click here to add PLEX WORLD. OBSYFAQ (OBSYDIAN-PLEX FREQUENTLY ASKED QUESTIONS) to your list of favorites
The intended audience for this document is OBSYDIAN (Cool:Plex) developers which have covered the introductory documentation on the tool at least (OBSYDIAN Getting Started/tutorial). Items, terms, and words in italics are concepts that can be found in Windows/OBSYDIAN (Cool:Plex) documentation
If you have questions, don't hesitate to drop me an email. I provide on-demand remote (100% via the internet) hourly consulting for the entire Development and Project Lifecycles at the best cost in the market.
Developed by: Lucio Gayosso, MIS/M, BS, PLEX Expert (1999-2010)
This was encountered with OBSYDIAN 3.1. Apart from the steps above mentioned it is also necessary to add a “TBL defaults SYS Procedural” triple to the table as this property defaults to “Database”
Additional notes from Plex' help
FLD default VAL ...apply SYS
Nominates one of a field's values as its default. The default value is used for fields which are displayed on panels and reports or updated to the database.
The TBL defaults SYS verb controls how the default value processing is implemented.
You can use the ...apply SYS continuation verb to specify more information about when the default value should be applied. The precise effect of this continuation verb depends on your class library. The allowed system values are:
Early
The field is initialized with its default value when it is first displayed on the screen (unless a value already exists).
Late
When a row is created in a table and no value has been specified for the field, the default value is applied at the time the row is created.
Menu Items ARE NOT Version/Level dependent though. If an item (Item 1) is created in BASE and then moved to Menu C in V1 the item "disappears" in all versions, including the ones below (BASE in this case) and just shows up in the Group (and Version/Level) where it was placed .
Note: We had to create new Menu Groups in new Versions of the application to create custom Panels for different users where the same Menu Items would show up in different locations (Menu Groups) according to the logic of how the information was presented for different users. With the limitation of not having Menu Items Version/Level dependent we had to take the following work-around to preserve all Menu Groups/Menu Items configuration for previous Versions/Levels and include the new features:
If we had to present "Menu Item 1" in Menu A for Version 1 (V1) and then on Menu C for V2 we would place "Menu Item 1" on Menu A in V1 then set the Exist and Visible properties to NO for it on V2 where a "Menu Item 2" was created and attached to the same Event on the Panel Designer. "Menu Item 2" was basically a replica of "Menu Item 1".
If Positioner<Date Field> == <Date Field.Null>
Set Positioner<Date Field> = <Date Field.highest
date>
Note: If a Wrapper function is used (to allow multple sort options), each of the individual get sequential functions called will also need this code.
Update on this issue (10/31/03): In the new versions of Plex's patterns (Plex 4.5 and above) a BLANK/NULL value for the Positioner values for Dates is correctly mapped to the HIGH value on the dates fields as long as the "high VAL" and "value VAL" triples are added to such fields (for AS400 Implementations no aditional triple/setting is required). For SQL Implementations the appropriate high values to use might have to be specified on the INI file (for further details check this EDGE thread: "ProcessGroup with Restrictor and Position")
Then make an API Call to the the "OBWIN/Trigger Event" Source Code
Object to perform the desired task. In this case you will have to pass the
value of the operation to perform (Update Grid):
API Call Source code: OBWIN/Trigger event
where the mapping would be :
|
|
|
|
|
|
Notes:
ª+1 Comment Lucio Gayosso. 09/29/99. Example of how to Cpoy blocks
of Code from a Function to another one in a different Version/Level
|1 Input
|2 15 51002c55 Field: CSBASE/RPS Company Code
|3 Grade Master.All attributes.Get one instance/Output
|4 15 51002c55 Field: CSBASE/RPS Company Code
|5 10 57000744 Function: Company Setup.All attributes.Get one instance
// Input<RPS Company Code> Grade Master.All attributes.Get one instance/Output<RPS
Company Code>
ª+1 Call Company Setup.All attributes.Get one instance
ª+1 Substring GL Account Nbr Setup<GL Acct Nbr Prefix Co>,
GL Account Nbr Setup<RPS S2K Company Number>, GL Account Nbr Setup<GL
Acct Nbr Prefix Lenght>, GL Account Nbr Setup<GL Acct Nbr Prefix Position>
ª+1 Substring GL Account Nbr Setup<GL Acct Nbr Prefix Cost
Center>, GL Account Nbr Setup<RPS S2K Company Number>, GL Account Nbr Setup<GL
Acct Nbr Prefix Lenght>, GL Account Nbr Setup<GL Acct Nbr Prefix Position>
|1 <none>
|2 15 ffffffed Field: GL Acct Nbr Prefix Co
|3 GL Account Nbr Setup
|4 15 ffffffed Field: GL Acct Nbr Prefix Co
|5 0 0 <none>
// <GL Acct Nbr Prefix Co> GL Account Nbr Setup<GL Acct Nbr Prefix
Co>
|1 <none>
|2 15 ffffffea Field: GL Acct Nbr Prefix Cost Center
|3 GL Account Nbr Setup
|4 15 ffffffea Field: GL Acct Nbr Prefix Cost Center
|5 0 0 <none>
// <GL Acct Nbr Prefix Cost Center> GL Account Nbr Setup<GL Acct
Nbr Prefix Cost Center>
ª+1 Format Message Message: Grades Received.List attributes.Process
Some Instances - Payment.Format GL Acct Nbr Prefix, GL Account Nbr Setup<GL
Acct Nbr Prefix>
ª+1 Comment set "GLA S2KGL Account Number" with Prefix and GLA
S2KGL Account Number from Purchase Materials to create Items Received
ª+1 Set Work<GLA S2KGL Account Number> = GL Account Nbr Setup<GL
Acct Nbr Prefix> CONCAT Purchase Materials.All attributes.Get one instance/Output<GLA
S2KGL Account Number>
@@
Now you can change your Local Model to the target Configuration (Version/Level). Open the Function where you want to insert the code and Copy all of it from the Text Editor (insert it directly on the AD code not in the Entry Line). OBSYDIAN will format the text to create the corresponding statements/constructs and will validate them.
Event Event: ALTERNATE PROMPT
Get Details<Prompted Field>
***
Process for alternate prompt
Set Details<Prompted Field> = Result from Process
for alternate prompt
Put Details<Prompted Field>
***
If Details<Prompted Field> =! Valid result (i.e.
equals "blank" or "zero")
Go Sub Prompt event (subroutine
that includes metacode for executing regular prompt)
Creating command line "link.exe @C:\TEMP\RSPE5.tmp"
Compiling...
RP2msF.CPP
C:\recpaper_v30\GEN\ODSOURCE\RP2msF.CPP(1240) : error C2039: 'ObOut_OB00001F'
: is not a member of ObDat_RP2msF'
C:\recpaper_v30\GEN\ODSOURCE\RP2msF.CPP(1240) : error C2228: left of '.Set_current_date_and12'
must have class/struct/union type
C:\recpaper_v30\GEN\ODSOURCE\RP2msF.CPP(1240) : error C2228: left of '.Panel_date17'
must have class/struct/union type
Error executing cl.exe.
Function RP2msf retrieves the panel date from the output of inherited call to OBASE/OB00001F.
There are two possible solutions:
1) Make a local call to this object (OBASE/Set current date and time)
and then the output filelds are available
2)Assign the otput from the inherited obkject to a local work field and then
use this for the mapping.
Note: Error "class/struct/union type" also found during compilation of a WinNT Server function (Plex 4.5) that wrapped a single statement to execute a SQL Statement.
(C:\old_F_drive\obbuild\patbuild46\patdevlg\JEcidF.CPP(97) : error C2228: left of '.GetWrapper' must have class/struct/union type)
In this case problem was resolved by adding a USES VIEW (with any view as the target) to the server function.
Solution: It is posible to do a "usage" with the model editor 'scoped' to the entity (View|Usage) and then, for all dependencies (all targets of 'referenced by' or 'owns' triples), locate the views that have to be manually deleted in the AS/400. This approach is rather slow but is based completely on Model Analysis. Another approach (faster) is to use the 'Display Data Base Relations' command in the AS/400: At the command line enter: DSPDBR FILE(LibraryName/TableImplName. This will provide a list of all the dependencies that need to be deleted to allow table's compilation.
Note: To delete go to the command line in the AS/400 and enter: STRPDM, select option 2 (Work with Objects), select the dependencies and use option 4 (delete).
If all dependent views for a table are identified in the Local Model and all
objects are selected (table and dependencies), compilation from the Local Model
can take place (Plex attemps successfully to delete all dependencies, then the
table, then submits the table and finally the dependencies)
Example:
The following SQL Script that does the following
1) Creates a BACKUP version of the current files that will be modified (PJ_jeTicketEntry and PJ_jeTicketEntryHistory)
2) Copies all data from current files to BACKUP files
3) Deletes current files and their views
4) Creates new files and their views. The new files include 7 additional fields at the end of the files.
5) Restores data from the BACKUP files to the new files mapping fields. For the new 7 fields, initialization to BLANK or 0 takes places
6) Deletes the BACKUP files
(due to space limitations file is not hosted. Send me an email to request the file: SampleSQLScriptToModifyDBFileWithDataPreservation.SQL)
+For Each Property Target FNC impl name NME
+++Define Field: Impl_Name_Field
+++Set Value To Current Field: Impl_Name_Field
++Name Defined Field: Impl_Name_Field, Output < Impl_Name_Field >
Where:
Impl_Name_Field IS A Fields/Identifier (suggested)
The output field Impl_Name_Field can then be retrieved in the calling
function and displayed in a message.
Solution: Create a Source Code object that inputs the parameters you want to concatenate and insert the control characters withing the message (space = " ", line feed = "\n", carriage return= "\r"). Finally make an API Call to this object.
Another alternative to formatting is by use of Trigraphs on Format Messages.
When specifying special fields format (Dates, times and timestamps, Numbers with decimal places, Literal values longer than 32 characters, special control characters like carriage return and tabs, etc) TRIGRAPHS can be used. A Trigraph is a special sequence of escape characters that are converted to the required character by the compiler.
Following is a chart with some of the most common Trigraphs to use:
To insert |
Use |
\ |
??/ |
[ |
??( |
] |
??) |
^ |
??' |
{ |
??< |
} |
??> |
| |
??! |
~ |
??- |
# |
??= |
TAB stroke |
??/t |
CARRIAGE RETURN |
??/n |
For additional details look for TRIGRAPHS under Plex's help
Note: Trigraphs cannot be used to print fields and labels on multiple lines (as in the TEXT prpertie for statics on panel). In such cases it is required to set the vertical size of the data or static control so that there is room for multiple lines. At run-time, the text will automatically wrap to a new line as required. Including a caret (^) character in the text of a label forces the text that follows to a new line (to display a carent in the text prefix the caret with a backslash: \^)
A common requirement is for a field value to represent a tab (\t). To insert a tab into a field value type: ??/t. Field's length may have to be increased to allow for the trigraph; for example, the value \t requires a field length of at least 2 but with the trigraph this increases to 4. Occasionally, it is necessary to insert a string that corresponds to one of the trigraphs (thus translation of the string is not desired); so, as an example, to include ??! in a field value precede the trigraph with ??/, in this case: ??/??! at run-time would display as: ??!7
Also for AS400 Implementation, if you are concatenating by using a Format Message (i.e. using &(1:) &(2:) to concatenate and include a space in between two parameters), make sure you generate and compilate the AS400 Message file.
36 a. MESSAGE used in a Format Message statement modified on AS400 variant for a server RPG function is not reflecting changes. No errors/warnings during function recreation.Solution: Re-generated/rebuilt AS400 Message file
Top |
Bottom |
Left |
Right |
Description |
Yes |
Yes |
Yes |
Yes |
Element resizes horizontally and vertically. Typically used for grids. |
Yes |
No |
Yes |
No |
Size is fixed. Position is fixed relative to the top-left corner of the window. Typically used for push buttons. |
Yes |
Yes |
Yes |
No |
Stretches vertically but horizontal size and position are fixed relative to top-left corner. |
Yes |
No |
Yes |
Yes |
Stretches horizontally but vertical size and position are fixed relative to top-left corner (like a toolbar). |
No |
Yes |
Yes |
Yes |
Stretches horizontally but vertical size and position are fixed relative to bottom-left corner (like a status bar). |
Solution: Delete obwafx.pch file. New compilation will create new one. Another possible solution: Copy _OBCORE.obj, obwafx.pch, and vc60.idb from another developer's PC to ...\release\obj folder
Note: Another common error that refers to a precompiled header is: Error during
compilation (Build : warning : failed to (or don't know how to) build 'C:\BuildDir\obj\obrt.pch',
C:\BuildDir\FunctionName.CPP(19) : fatal error C1083: Cannot open precompiled
header file: 'C:\BuildDir\Release/obj/obrt.pch': No such file or directory)
Solution for this case: Install Visual Studio SP5 patch.
Solution: A very simple approach is the creation of a Source Code object
with the following C++ code:
{ remove(&(1:)); }
Where &(1:) represents the file name to delete. Additional validation will be
required to check that the file was actually deleted.
Another simple way is with the following WinC Source Code:
{
DeleteFile( &(1:) );
}
Where
&(1:) = FIELDS/FullPath represents the FullPath+FullFileName
Alternatively you can make use of the following VBScript Source Code that makes use of the File System Object:
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")
fso.DeleteFile(&(1:))
Where:
&(1:) = File Name (OBMAPI/File names)
47B. How can I create a text file?
Solution: A very quick and easy solution is to make use of FileSystemObject on a VBScript Source code:
Dim fso, f1
Set fso = CreateObject("Scripting.FileSystemObject")
Set f1 = fso.CreateTextFile("&(1:)", True)
Where:
&(1:) = File Name (OBMAPI/File names)
For more details on how to create and wite information on text files read the following notes:
CREATING TEXT FILES
There are three ways to create an empty text file (sometimes referred to as a "text stream").
Dim fso, f1
Set fso = CreateObject("Scripting.FileSystemObject")
Set f1 = fso.CreateTextFile("c:\testfile.txt", True)
Dim fso, ts
Const ForWriting = 2
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.OpenTextFile("c:\test.txt", ForWriting, True
Dim fso, f1, ts
Const ForWriting = 2
Set fso = CreateObject("Scripting.FileSystemObject")
fso.CreateTextFile ("c:\test1.txt")
Set f1 = fso.GetFile("c:\test1.txt")
Set ts = f1.OpenAsTextStream(ForWriting, True)
ADDING DATA TO TEXT FILES
Once the text file is created, add data to the file using the following three steps:
- Open the text file.
- Write the data.
- Close the file.
To open an existing file, use either the OpenTextFile method of the FileSystemObject object or the OpenAsTextStream method of the File object.
To write data to the open text file, use the Write, WriteLine, or WriteBlankLines methods of the TextStream object, according to the tasks outlined in the following table.
Task | Method |
Write data to an open text file without a trailing newline character. | Write |
Write data to an open text file with a trailing newline character | WriteLine |
Write one or more blank lines to an open text file. | WriteBlankLines |
To close an open file, use the Close method of the TextStream object.
View this sample code to see how the Close method is used in FileSystemObject.
In Plex, with a Source Code (Write Text Line with Trailing NewLine) that operates with an existing file:
Dim fso
Dim file
' Format object.OpenTextFile (filename [, iomode[, create[, format]]])
' This method is used to open a text file and returns a TextStreamObject that
can then be used to write to, append to, and read from the file.
' The optional iomode argument can have one of the following Constants as its
value: ForReading 1 Opens a file for reading only, ForWriting 2 Opens a file
for writing. If the file already exists, the contents are overwritten. ForAppending
8 Opens a file and starts writing at the end (appends). Contents are not overwritten.
' The optional create argument can be either True, which will create the specified
file if it does not exist, or False, which won't.
' The optional format argument uses one of the following Tristate values to
specify in which format the file is opened. If not set, this defaults to TristateFalse,
and the file will be opened in ASCII format. CONSTANT VALUE DESCRIPTION TristateTrue
-1 Opens the file as Unicode . TristateFalse 0 Opens the file as ASCII. TristateUseDefault
-2 Use default system setting.
Set fso = CreateObject("Scripting.FileSystemObject")
Set file = fso.OpenTextFile("TransmittalFile.txt", 8, False)
file.WriteLine(&(1:))
file.Close
Where:
&(1:) = Record to write (i.e. Ref Character, 250)
--------------------------------------------------------------------------------
Note: The newline character contains a character or characters
(depending on the operating system) to advance the cursor to the beginning of
the next line (carriage return/line feed). Be aware that the end of some strings
may already have such nonprinting characters.
--------------------------------------------------------------------------------
The following VBScript example demonstrates how to open a file, use all three write methods to add data to the file, and then close the file:
Sub CreateFile()
Dim fso, tf
Set fso = CreateObject("Scripting.FileSystemObject")
Set tf = fso.CreateTextFile("c:\testfile.txt", True)
' Write a line with a newline character.
tf.WriteLine("Testing 1, 2, 3.")
' Write three newline characters to the file.
tf.WriteBlankLines(3)
' Write a line.
tf.Write ("This is a test.")
tf.Close
End Sub
UNDERSTANDING MORE ON THE FILESYSTEMOBJECT OBJECT MODEL
This model allows you to add, move, change, create, or delete folders (directories) and files.
The FileSystemObject (FSO) object model contains the following objects and collections:
Object |
Collection Description |
FileSystemObject Main object | Contains methods and properties that allow you to create, delete, gain information about, and generally manipulate drives, folders, and files. Many of the methods associated with this object duplicate those in other FSO objects; they are provided for convenience. |
Drive Object | Contains methods and properties that allow you to gather information about a drive attached to the system, such as its share name and how much room is available. Note that a "drive" isn't necessarily a hard disk, but can be a CD-ROM drive, a RAM disk, and so forth. A drive doesn't need to be physically attached to the system; it can be also be logically connected through a network |
Files Collection | Provides a list of all files contained within a folder. |
Folder Object | Contains methods and properties that allow you to create, delete, or move folders. Also allows you to query the system for folder names, paths, and various other properties |
TextStream Object | Allows you to read and write text files |
Folders Collection | Provides a list of all the folders within a Folder |
Drives Collection | Provides a list of the drives attached to the system, either physically
or logically. The Drives collection includes all drives, regardless of type.
Removable-media drives need not have media inserted for them to appear in
this collection. File Object. Contains methods and properties that allow you to create, delete, or move a file. Also allows you to query the system for a file name, path, and various other properties |
To program with the FileSystemObject (FSO) object model:
Create a VBScript Source Code objects using the following code to create an instance of the FileSystemObject:
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")
For example, to create a text file and write a line in it you can create the following VBScript Source Code
Dim fso
Dim f1
Set fso = CreateObject("Scripting.FileSystemObject")
Set f1 = fso.CreateTextFile("C:\Plexdev\JES\GEN46\Win32\Release\UploadDMV.txt",
True)
f1.WriteLine("Hello World!")
f1.close
Where:
&(1:) = File Name (OBMAPI/File names)
Use this code to get a handle to the GetFolder method in VBScript:
Set fldr = fso.GetFolder("c:\")
For more information check Plex's Help|Reference|Microsoft Scripting Documentation
Important note on running VBScript Source Codes: Plex functions executing VBScripts need to have a panel scoped.
47C How can I copy a file from one destination folder to a target location?
Solution: Create the following "CopyFile" WinC Source Code
{
BOOL RetValue;
RetValue = CopyFile( &(1:), &(2:), FALSE );
if (RetValue == 0)
{
&(3:) = " ";
}
else
{
&(3:) = "ERR";
}
}
Where:
&(1:) = FIELDS/FullPath ...QLF SourceFile (which is a fully qualified path that includes the file name to be copied)
&(2:) = FIELDS/FullPath ...QLF DestinationFile (which is a fully qualified destination path that includes the new file name -can be the original name)
&(3:) = *Returned status
Make an API call to the Source Code which will return ' ' if file was successfully copied or 'ERR' with any other condition
47D. How can I replace some text string on the 1st line of a text file?
Solution: This task was discussed in the following EDGE Thread:
A suggested solution by Phillipe Moschkowitch was based on a Source Code object that used the File System Object:
Const ForReading = 1
Const ForWriting = 2
Set fso = CreateObject("Scripting.FileSystemObject")
'replace &(1:) with your file'
Set xFile = fso.OpenTextFile(&(1:), ForReading, True)
strText = xFile.ReadAll
xFile.Close
Set xFile = Nothing
strNewText = Replace(strText, "TextToFind", "ReplacementText")
Set xFile = fso.OpenTextFile(&(1:), ForWriting, True)
xFile.WriteLine strNewText
xFile.Close
Set xFile = Nothing
Set fso = Nothing
Where &(1:) is the FullPath to the text file (File Name and extension included such as c:\yourfile.xml) where the first line is to be replaced
47E. How can I copy all the files from a Source Directory to a target location?
Solution: Create the following "CopyAllFilesInDirectoryVB" VBSCript code that makes use of the FileSystemObject:
'Lucio Gayosso. Copy all files from a source directory to target location.
Dim ObjFso
Dim StrSourceLocation
Dim StrDestinationLocation
Dim StrSourceFileName
Dim StrDestinationFileName
StrSourceLocation = &(1:)
StrDestinationLocation = &(2:)
'All files will be copied to destination
StrSourceFileName = "*.*"
StrDestinationFileName = ""
'Creating the file system object
Set ObjFso = CreateObject("Scripting.FileSystemObject")
'Copying the files
ObjFso.CopyFile StrSourceLocation & "\" & StrSourceFileName, StrDestinationLocation & "\" & StrDestinationFileName, False
Make an API call passing the source and target directory paths, which should not be ending with '\'
47F. How can I move all the files from a Source Directory to a target location?
Solution: Create the following "MoveAllFilesInDirectoryVB" VBSCript code that makes use of the FileSystemObject:
'Lucio Gayosso 08/03/09 JEMS5108672. Move all files from a source directory to target location.
Dim ObjFso
Dim StrSourceLocation
Dim StrDestinationLocation
Dim StrSourceFileName
Dim StrDestinationFileName
StrSourceLocation = &(1:)
StrDestinationLocation = &(2:)
'All files will be copied to destination
StrSourceFileName = "*.*"
StrDestinationFileName = ""
'Creating the file system object
Set ObjFso = CreateObject("Scripting.FileSystemObject")
'Copying the files
ObjFso.MoveFile StrSourceLocation & "\" & StrSourceFileName, StrDestinationLocation & "\" & StrDestinationFileName
Make an API call passing the source and target directory paths, which should not be ending with '\'
47G. How can I work with file extensios and paths?
Solution: The following Source Code objects can be called as APIs for miscellaneous Extensions and Path tasls:
a) "AddFileExtension" Source Code:
#include <atlpath.h>
{
// Source Code created using ATL Server Library Reference|Utilities
Reference. ATL Server provides code for manipulating paths and URLs in
the form of
CPathT and CUrl. Per MSDN "A thread pool, CThreadPool, is used
in the implementation of the ATL Server ISAPI extension class and can
also
be used
in your own applications.
This code can be found in atlpath.h and atlutil.h"
// Adds a specified file extension to the provided Full Path (Path + File
Name) if one doesn't exist.
CPath WorkPath(&(2:));
&(1:) = WorkPath.AddExtension(&(3:));
&(2:) = WorkPath.m_strPath;
}
Where:
&
(1:)=ReturnStatus (Numeric)
&
(2:)=FullPath (Path + File Name, i.e. Char, 1024)
&
(3:)=FileExtension (Char such as .EXE, .DLL, etc.)
b) "
GetFileExtension" Source Code:
#include <atlpath.h>
{
// Source Code created using ATL Server Library Reference|Utilities Reference.
ATL Server provides code for manipulating paths and URLs in the form of CPathT
and CUrl. Per MSDN "A thread pool, CThreadPool, is used in the implementation
of the ATL Server ISAPI extension class and can also be used in your own
applications. This code can be found in atlpath.h and atlutil.h"
// Retrieve the file extension for a given Full Path (Path + File Name), if
one exists.
CPath WorkPath(&(1:));
&(2:) = WorkPath.GetExtension();
}
Where:
& (1:)=FullPath (Path + File Name, i.e. Char, 1024)
& (2:)=FileExtension (Char such as .EXE, .DLL, etc.)
c) "
GetFileNameFromFullPath" Source Code:
#include <atlpath.h>
{
// Source Code created using ATL Server Library Reference|Utilities Reference.
ATL Server provides code for manipulating paths and URLs in the form of
CPathT and CUrl. Per MSDN "A thread pool, CThreadPool, is used in the
implementation of the ATL Server ISAPI extension class and can also be used
in your own
applications. This code can be found in atlpath.h and atlutil.h"
// Retrieve the File Name from a provided Full Path (Path + File Name)
CPath WorkPath(&(1:));
WorkPath.StripPath();
&(2:) = (CString) WorkPath;
}
Where:
&
(1:)=FullPath (Path + File Name, i.e. Char, 1024)
&
(2:)=FileName (i.e. Char, 1024)
d)"
GetPathFromFullPath" Source Code:
#include <atlpath.h>
{
// Source Code created using ATL Server Library Reference|Utilities Reference.
ATL Server provides code for manipulating paths and URLs in the form of CPathT
and CUrl. Per MSDN "A thread pool, CThreadPool, is used in the implementation
of the ATL Server ISAPI extension class and can also be used in your own applications.
This code can be found in atlpath.h and atlutil.h"
// Retrieve the Path Portion from a provided Full Path (Path + File Name)
CPath
WorkPath(&(2:));
&(1:) = Work.RemoveFileSpec();
&(3:) = (CString) WorkPath;
}
Where:
&
(1:)=ReturnStatus (Numeric)
&
(2:)=InputFullPath (Path + File Name, i.e. Char, 1024)
&
(3:)=OutputPath (Path + File Name, i.e. Char, 1024)
e)"CheckIfPathIsADirectory" Source Code
{
// Checks if the path is a directory or not
&(1:) = PathIsDirectory(&(2:));
}
Where:
&
(1:)=ReturnValue (Boolean)
&
(2:)=InputPath (i.e. Char, 1024)
A related checkup would be whether the Path is formed with Universal Naming Conventions (UNC):
"CheckIfPathIsUNC" Source Code:
{
// Checks if the path is formed with UNC (\\...)
&(1:) = PathIsUNC(&(2:));
}
Where:
&
(1:)=ReturnValue (Boolean)
&
(2:)=InputPath (i.e. Char, 1024)
47H. How can I append the contents of File A into an existing and loaded File B?
Create the following 'Append PC File A to File B' VBScript Source Code and make an API call to it passing Field A (Input File) and Field B (Resulting File):
' Lucio Gayosso 01/08/10.
Const ForReading = 1
' Create FSO Scripting object
Set objFSO = CreateObject("Scripting.FileSystemObject")
' Create an interim output file by concatenating the target merge file name (File B) with suffix MERGE
' This file will be written two times:
' 1) with the existing contents of resulting file found in the BATCH directory
' 2) with the contents of the new input file
Set objOutputFile = objFSO.CreateTextFile(&(2:) + "MERGE")
' Read all the contents of the existing file in the Batch directory (File B)
Set objTextFile = objFSO.OpenTextFile(&(2:), ForReading)
strText = objTextFile.ReadAll
objTextFile.Close
' Write the contents of the existing file in Batch directory (File B) into the interim MERGE file
objOutputFile.WriteLine strText
' Read all the contents of the new input file (File A)
Set objTextFile = objFSO.OpenTextFile(&(1:), ForReading)
strText = objTextFile.ReadAll
objTextFile.Close
' Write the contents of the new input file (File A) into the interim MERGE file
' At this point the interime MERGE file contains File B + File A
objOutputFile.WriteLine strText
objOutputFile.Close
' Delete the target file located in the Batch directory
objfso.DeleteFile(&(2:))
'Rename the combined file (suffix MERGE) into the original target name (original file name in the Batch directory)
objfso.MoveFile &(2:) + "MERGE",&(2:)
Where:
&(1:): Is the Input File A described as Full Path + File Name With Extension (FIELDS/FullPath)
&(1:): Is the Existing File B described as Full Path + File Name With Extension (FIELDS/FullPath)
More details on the following CA FORUMS' thread:
http://caforums.ca.com/ca/board/message?board.id=caplexgeneraldiscussion&message.id=2093&jump=true
#include { // Check if file or directory exists
if ( (_access( &(1:), 0 )) != -1 )
&(2:) = "";
else &(2:) = "INF";}
Where:
&(1:) = File or PC Folder
&(2:) = *Returned status
Look within C++ Documentation more information about the "_access" function
to further specialize this Source Code.
Alternatively Source Code to check if a file exists
GetFileAttributes (&(1:)); &(2:) = GetLastError();
Where:
&(1:) = OBWIN/File to open
&(2:) = File exists return status (Numeric, 1, C Format Integer, Values:
Exist (0)/does not exist (2))
The "error to connect on sockets" can also be produced by the TCP/IP dispatcher not running on the AS/400. Normally, the dispatcher should start automatically but if it failed to do so (or additional dispatchers on additional ports are required) the dispatcher can be manually started by entering on an AS400 command line:
SBMJOB CMD(CALL PGM(PLEX/YOBSYTCP) PARM('35000')) JOB(YOBLISTEN) JOBD(PLEX/PLEX) JOBQ(QGPL/QINTER)
These are the default values that you should modify as needed (for example change 35000 to the port required)
Solution: The application needs to provide NULL support as the NULL value is not the same as an EMPTY value (""). NULL in SQL Implementation is not the same as adding a value triple to the field without a literal value. An easy solution is to check on the collation sequence for BLANKs to identify if a value had been provided or not: IF FIELD >> Field.BLANK then DOSomeProcess.
Notes on Plex handling of NULLS:
Nulls and SQL. Plex null support is designed to correspond closely with the concept of SQL NULL. For an SQL/ODBC database, when a null field in a row is being written to or read from the database, SQL NULL indicators are used to transfer the state to or from the database. When the null value is referenced in the select or omit set of a view, the resulting SQL predicate will use the keywords IS NULL or IS NOT NULL, as appropriate (the SQL query will translate these values as IS NULL or IS NOT NULL).
Plex's implementation of NULL values differs from SQL NULL in that Plex null value is in the collating sequence. SQL NULL is outside the collating sequence. The collating sequence for special field values is:
Null < Low < Normal Values < High (this was the fundamental for the solution offered on this item)
When working with existing data in an SQL database, note that the data may include null values which will fail an If Empty condition (even in the absence of a FLD null VAL triple). To avoid this situation data can be modeled correctly by providing null support in the model or eliminate the null values from the database with a SQL Script.
Nulls and the AS/400
The AS/400 database and the RPG/400 programming language do not support
the concept of a null state. On the AS/400, processing is based on the actual
content of the field concerned.
When a field in a null state is passed from a Windows client to an AS/400 server, the null state is converted to the appropriate default empty value. For example, a null numeric field will be converted to zero. Alternatively, if you explicitly specify a literal value for the large property of the null value, this literal will be used instead of the default. This may be useful when you need to distinguish between the empty and null states of a field.
Note: A simple example for the checking of the collation sequence to avoid nullsIf Variable1<Field1> << <Field1.*Blank>
Set Variable1<Field1> = <Field1.*Blank>
If Variable2<Field2> << <Field2.*Blank>
Set Variable1<Field2> = <Field2.*Blank>
This will eliminate the SQL Server's <NULLS> values and replace by the known empty values.
In addition, you can get more information on Plex validation for NULL in the following EDGE Thread: ++If NOT Empty problem
Source Code:
// Lucio Gayosso 03/20/02.
// This code removes trailing (right) blanks from a character string.
// It uses the TrimRight function inherited from CString.
// It uses long fields (length 1000)
{
&(1:) = &(2:);
&(1:).TrimRight();
}
Where:
&(1:) = Returned string (Character, lenght as required)
&(2:) = Input String (Character, lenght as required)
You can also use the following Source Code to Trim all spaces:
{
&(1:).TrimSpaces();
}
Where:
&(1:) = Parameter string
//This allows a function to run without being displayed in the taskbar.
{
CWnd *pCWndCurrent ;
pCWndCurrent = ObPanelAPI::GetPanelCWndByName("*current") ;
if (pCWndCurrent)
{
pCWndCurrent->ModifyStyleEx(0, WS_EX_TOOLWINDOW, SWP_DRAWFRAME) ;
}
}
&(3:) = &(1:).Find( &(2:) );
Where:
&(1:) = Source String (FIELDS/SourceString)
&(2:) = Search String (FIELDS/SearchString)
&(3:) = Position in String (FIELDS/PostionInString)
// This code returns the number of characters in a string.
// It uses the GetLength() function inherited from CString.
// It may be necessary to remove the trailing blanks first.
{
&(1:) = &(2:).GetLength() ;
}
Where:
&(1:) = Local String Length (Integer)
&(2:) = Local Character String (Character, length 256)
Solution: Create the following Source Code objects passing the String to convert:
To Convert to Upper Case:
{ // UPPER CASE STRING
char cStartStr[256] = "" ;
strncpy( cStartStr, &(1:).GetText(), 255) ;
if (cStartStr)
{
_strupr( cStartStr );
&(1:) = cStartStr;
}
}
To Convert to Lower Case:
{ // lower case string
char cStartStr[256] = "" ;
strncpy( cStartStr, &(1:).GetText(), 255) ;
if (cStartStr)
{
_strlwr( cStartStr );
&(1:) = cStartStr;
}
}
Where the String field is [Char,255]. Finally make an API Call.
Also possible (to convert to lowercase):
// Set all the alpha characters to lower case but the first one
CString szUpdate = &(1:);
szUpdate.MakeLower();
int nLen = szUpdate.GetLength();
BYTE cUpdate = szUpdate.GetAt(0);
if ( isalpha(cUpdate) )
szUpdate.SetAt( 0, toupper( cUpdate ) );
Where:
&(1:) = FIELDS/VaryCharacter
78b. How can I capitalize only the first letter in a given string? (to format person and street names for example).
Solution: Following is a Source Code to capitalize strings considering special cases where second letter is not alphanumeric (like: O'Conner' O'Brian, St. Andrews, etc) and cases where first letter is 'M' and second is 'c' (like McDonald, McBrian, etc)
//Checks for non-alpha characters and capitalizes the next alpha
//rather than searching for specific replacement characters
{
// Eliminate leading and trailing spaces
&(1:).TrimSpaces();
// Set all the alpha characters to lower case except the first one
CString szUpdate = &(1:);
szUpdate.MakeLower();
int nLen = szUpdate.GetLength();
BYTE cUpdate = szUpdate.GetAt(0);
CString sFirstLetter = szUpdate.GetAt(0);
if ( isalpha(cUpdate) )
szUpdate.SetAt( 0, toupper( cUpdate ) );
// Step through the string and capitalize any character following a non-alpha
int nPos = 1;
while ( nPos<=nLen ) {cUpdate = szUpdate.GetAt(nPos++);
// LG 02/25/04. If second letter is not alpha OR first letter is 'm' and second 'c', capitalize 3rd letter
if ( (isalpha(cUpdate)==0) ||((sFirstLetter == 'm') & (nPos == 2))
& (cUpdate == 'c')) {
// Set the next character to upper case if it is alpha
cUpdate = szUpdate.GetAt(nPos);
if ( isalpha(cUpdate) )
szUpdate.SetAt( nPos++, toupper( cUpdate ) );
}
}
szUpdate.TrimLeft();
szUpdate.TrimRight();
if (szUpdate == "Iii" || szUpdate == "Ii" || szUpdate ==
"Iv")
szUpdate.MakeUpper();
&(1:) = szUpdate;
}
Create a Source Code using the vBScript function "Split()"
Split(Expression, Delimiter, Count, Compare)
The Split function separates a string into substrings and creates a one-dimensional
array where each substring is an element. There is only mandatory argument is "Expression"
Source Code:
MyProductArray = Split(&(1:), " ", -1, 1)
&(2:) = UBound(MyProductArray)
Where:
&(1:) = String to split [Char,255]
&(2:) = Subscript of the array [FIELDS/Long]
Note: VBScript UBound Function
Returns the largest available subscript for the indicated dimension of an array. &(2:)
can be used later to acess each one of the array elements.
Example of an implementation based on this concept.
The following ‘SplitNameStringIntoComponents’ VBScript source code inputs a string and breaks into its known fields, in this case a Person’s Last, First, and Middle Names:
' Lucio Gayosso 03/04/10. Created function to split a string that contains
a Person name
' into its component fields
' Function returns the subscript of the array and the following known array
elements
' Last Name (element 0), First Name (element 1), and Middle Name (element 2)
MyStringArray = Split(&(1:), &(3:), -1, 1)
& (2:) = UBound(MyStringArray)
& (4:) = MyStringArray(0)
& (5:) = MyStringArray(1)
& (6:) = MyStringArray(2)
Where:
&(1:) = String to split (FIELDS/VaryCharacter)
&
(2:) = Subscript of the array (FIELDS/Long)
&
(3:) = ElementsSeparator (FIELDS/TargetString). Any separator can be passed
such as ‘~ ‘, ‘,’, ‘$’, etc.
&
(4:) = Person’s Last Name (FIELDS/VaryCharacter)
&
(5:) = Person’s First Name (FIELDS/VaryCharacter)
&
(6:) = Person’s Middle Name (FIELDS/VaryCharacter)
The returned ‘Subscript of the array’ can be used for validation or to process additional array elements not considered by the direct assignment within the Source Code
Note: BLOBS in the AS400. Storing BLOBs in the AS400 represents a problem as several limitations exist (mostly with the size of the files that can be stored). Some suggestions on how to handle these can be found on the following threads (EDGE Forums):
http://neo3.sba.com/forums/Thread.cfm?CFApp=82&&Message_ID=68468&_#Message68468
http://neo3.sba.com/forums/Thread.cfm?CFApp=82&&Message_ID=74519&_#Message74519
http://neo3.sba.com/forums/Thread.cfm?CFApp=82&&Message_ID=57490&_#Message57490
Solution: Look for the detailed instructions on how to create this function under the DOWNLOADS section of PLEX WORLD (Function to replace all BLANKS by UNDERSCORES without using Source Code objects for an Input String)
84 B) How can I replace some character(s) in a String by other ones with a count on the number of replacements?
Solution: Create the following ‘ReplaceCharacterWithReplaceCount‘ VBScript Source Code object and make an API call to it:
' Lucio Gayosso 03/04/10 Created function to replace characters in a string with a replacement count.
&(1:) = Replace(&(1:),&(2:),&(3:),1,&(4:))
Where:
&(1:) = String (FIELDS/VaryCharacter)Note: This Source Code can further be enhanced to input &(3:) = Column Number
{
HWND hGrid=ObPanelAPI::GetControlHandleByName(&(1:));
if (hGrid)
{
PostMessage(hGrid,HGFM_SETNAME,&(3:),(LPARAM)&(2:).GetText());
}
}
If multiple columns are being changed simultaneously, the message type needs to be changed to SendMessage, check for more details EDGE Thread "Changing column headings at run time "
Update: Apparently this is no longer working with Plex 5.0. No work around as of 02/10/03.
87A. Why do combo boxes loaded dynamically cannot display certain values?
-these are displayed as blanks- (Plex 4.5 windows Clients)
Solution: In this particular case, the program that sets the control (on either a combo or edit box) failed for certain values that were located past a limit imposed by Plex on the number of values that can be displayed in a control (128 values). No work around was found and the control was changed to a promptable Edit Box.
Note: The dynamic load of the combo box on this example was accomplished with the following Source Code (AddComboValue)
{
pHComb myCombo;
myCombo = (pHComb) ObPanelAPI::GetControlByName( &(1:) );
if ( myCombo )
myCombo->AddValuePair( ObCharFld(), (LPCSTR)&(3:).strGetText(), (LPCSTR)&(2:).strGetText()
);
Where:
&(1:) = ActiveXControl (this is the Control Name for the combo from Plex's
Panel Designer)
&(2:) = Code (value initially loaded for the control)
&(3:) = Description (value displayed for end-user for the code above)
Solution: You can use the following Source Code in an API Call:
ObAppAPI::SetOption(&(1:), &(2:), &(3:), OB_OPT_USER_DEFINED);
Where:
&(1:) = INI Section
&(2:) = INI Key
&(3:) = INI Value.
This is a variant of OBWIN/Set INI system value Source Code
In addition, if you need to read a given INI value you can make use of the OBWIN/Get INI system value Source Code (read Plex's documentation on SetOption API for more details)
{
char buffer[_MAX_PATH];
GetSystemDirectory( buffer, _MAX_PATH );
&(1:) = buffer;
}
Where:
&(1:) = Current Directory(Char, 256)
Alternatively,
"Get Application Path" Source Code:
{
_getcwd(&(1:).GetBuffer(1024), 1024);
&(1:).ReleaseBuffer();
}
"Set ApplicationPath" Source Code:
{
int nLen = &(1:).GetLength()+1;
_chdir( &(1:).GetBuffer(nLen) );
}
Where:
(&1:) = FIELDS/FullPath (Char, 1024)
Solution: Make use of the following Source Code:
Set Current Windows Caption
{
CWnd *pWnd = ObPanelAPI::GetPanelCWndByName("*Current");
ASSERT(pWnd);
if (pWnd)
{
pWnd -> SetWindowText(&(1:));
}
}
Where:
&(1:) = New Windows Caption (OBWIN/Property Value, 100)
Solution: Make use of the following Source Code:
&(1:)=&(2:).strGetMaskedText((LPCSTR)&(3:).strGetText());
Where:
&(1:) = Formatted output for the field
&(2:) = Value to be formatted
&(3:) = Edit Mask.
{ WritePrivateProfileSection(&(1:), NULL, &(2:)); }
Where:
&(1:) = INI section (OBWIN/INI section)
&(2:) = INI file name (OBWIN/INI file name)
For additional details check:
ERASE Drive:\YourPlexPath\GEN\WIN\Release\obj\*.obj ERASE Drive:\YourPlexPath\GEN\WIN\Release\obj\*.res ERASE Drive:\YourPlexPath\GEN\WIN\Release\obj\*.pch ERASE Drive:\YourPlexPath\GEN\WIN\Release\obj\*.idb ERASE Drive:\YourPlexPath\GEN\WIN\Release\*.exp ERASE Drive:\YourPlexPath\GEN\WIN\Release\*.imp ERASE Drive:\YourPlexPath\GEN\WIN\Release\*.lib ERASE Drive:\YourPlexPath\GEN\WIN\Release\*.lst ERASE Drive:\YourPlexPath\GEN\Project\*.dsp ERASE Drive:\YourPlexPath\GEN\WIN\*.obl ERASE Drive:\YourPlexPath\GEN\*.h ERASE Drive:\YourPlexPath\GEN\*.cpp ERASE Drive:\YourPlexPath\GEN\*.dat ERASE Drive:\YourPlexPath\GEN\*.msg ERASE Drive:\YourPlexPath\GEN\*.rc ERASE Drive:\YourPlexPath\GEN\*.rpg ERASE Drive:\YourPlexPath\GEN\*.def ERASE Drive:\YourPlexPath\GEN\*.rtf ERASE Drive:\YourPlexPath\GEN\*.hpj ERASE Drive:\YourPlexPath\GEN\*.tbl ERASE Drive:\YourPlexPath\GEN\*.txt ERASE Drive:\YourPlexPath\GEN\*.val ERASE Drive:\YourPlexPath\GEN\*.viw ERASE Drive:\YourPlexPath\GEN\*.str ERASE Drive:\YourPlexPath\GEN\*.java ERASE Drive:\YourPlexPath\GEN\*.jbl ERASE Drive:\YourPlexPath\GEN\*.mkj |
Solution: The Palette is out of the visible range thus it is not accessible. To move it to the visible area do the following: Push the Action Diagram Palette button and press ALT + SPACE to activate the palette's menu and then 'M' (move) then move the palette to the visible area using the arrow keys.
Solution: Use the following Source Code "PrinterSetup "
{
#include "commdlg.h"
CPrintDialog thePrinter(TRUE,0);
thePrinter.DoModal();
&(1:) = thePrinter.GetDeviceName();
&(2:) = thePrinter.GetDriverName();
&(3:) = thePrinter.GetPortName();
thePrinter.GetDevMode();
// mode.dmOrientation = 2;
&(5:) = DEVMODE.dmOrientation;
}
// Printer.Orientation = vbPRORLandscape
// Printer.Orientation = vbPRORPortrait
Where:
PrinterSetup ParameterFLD PrinterName (Char, 70, case MIXED)
PrinterSetup ParameterFLD PrinterDriver (Char, 70, case MIXED)
PrinterSetup ParameterFLD PrinterPort (Char, 70, Case Mixed)
PrinterSetup ParameterFLD PrinterPaperSize (Char, 40)
PrinterSetup ParameterFLD Wrk_PrinterOrientation (FIELDS/Number,
1)
Solution: Suppose we have a function in model A (Function A). We want to call this function from Local Model B but Local Model A IS NOT a referenced library thus Function A is not accessible in the current Local Model B (Function A will not show up in the Object Browser).
Define a function (Function B) in Local Model B with the exact File Name, Implementation Name, Language SYS, type SYS as Function A. Set Impl SYS = NO.
Define any Input/Output Dual fields in Function A in the exact same way in Function B (input FLD, dual FLD, output FLD). The implementation names of the fields in Local Model B DO NOT HAVE to match the ones in Local Model A.
Enter the appropriate continuation triples to assign the I/O fields to the same Variable names as Function A (...for VAR). Note: It is important that Function B's I/O Groups and Variables are in the exact same order as the ones in Function A as if differences occur, Function B will be called but the mapping for the fields will be incorrect producing unexpected results.
Define the appropriate variables in Function B (var VAR, ...as SYS)
Example:
Solution: A very simple way to do this is by using a BULK insert SQL statement. This statement inputs a text file location + FileName and the specification on a delimiter for the records to import and then copies the data into a SQL Server table.
The limitations to this approach are:
To use the bulk insert:
bulk insert &(2:).&(3:) from &(1:) WITH ( FIELDTERMINATOR = '~' )
Where:
&(1:) = File Name with Path, all surrounded by Single-quote (FIELDS/FileName, 128)
&(2:) = Table Owner
&(3:) = Table Name
Notes: If the application is NOT RUNNING ON THE SERVER and the path to the text file is through a relative path (with a drive letter like C:\file.txt) the process that performs the BULK insert WILL NOT work. In this case a Universal Naming Convention (UNC) path is required. To get it browse through My Network Places, Entire Network, and then through the folders to find the file. The UNC name for the path will be displayed like \\LocalSystem\C\File.txt The Field Terminator can be any character The last field on each record on the TXT file does not need a Field terminator
- Create a Client Function (WinC) that calls the wrapper function. This Client function should define the Server connection.
A common error during BULK insert operations: Error Server: Msg 4861, Level 16, State 1, Line 1 Could not bulk insert because file '\\FullPath\File.txt' could not be opened. Operating system error code 5(Access is denied.).
Solution: Folder where File.TXT was located did not have the appropriate security settings.
Solution: This message is typically the result of some Metavalidation (through the Call VALIDATE/Meta.ValidateFields in the Validate Detail subroutine) that failed. Make sure all the detail fields (typically on variable DetailP) contain an adequate value.
Note: Meta-validation checks if an optional field (or any of the fields, in a optional composite key) contains a value. If any of the composite or optional fields contains a value (is not NULL or BLANK) validation is triggered as shown in the following in the Metacode block (section of "Post Point Start validate Detail"):
Solution: Known bug. To fix you need the Tweak UI Utility (free download from Microsoft site: Tweak UI 1.33
To install and configure your Plex development PC:
A) Download the zip file and unzip into a local folder.
B) Move the extracted file to a system folder in your path (1.e. C:\WINNT\system32). When you open Control Panel next time a new option will show up: Tweak UI
C) Double-click Tweak UI and go to General tab. Uncheck "List box animation". This should fix the problem.
Additional discussion on this on the following EDGE Forum thread on erratic scrolling in Action Diagrams
For XP systems: An alternative to PowerTools setting exists. Uncheck the option "Smooth-scroll list boxes" found in Control Panel|System Properties|Advanced|Settings
Solutions: Following are the Action Diagram statements to acomplish this task.
Note: This approach was required on a process that had to validate, process, and create an output on the client PC for every record fetched. It is s recommended to accumulate all this logic in a Subroutine or Seq Construct.
Seq ProcessDBRecords
Read and fetch all table records
RowCount is the total nbr of records processed but
could be omitted
Set Control<RowCount> = <RowCount.*Zero>
Control variable fields used for this process. This
is is where fields are initialized.
Set Control<MoreData> = <MoreData.Yes>
Set Control<Position> = <Position.Yes>
Set Control<BufferedRows> = <BufferedRows.*Zero>
While Control<MoreData> == <MoreData.Yes>
OR Control<BufferedRows> >> <BufferedRows.*Zero>
Set Control<UseRow>
= <UseRow.Yes>
If Control<BufferedRows>
>> <BufferedRows.*Zero>
Use
the buffered data
Set
Control<Current> = Control<Current> + <Current.*One>
Set
Control<BufferedRows> = Control<BufferedRows> - <BufferedRows.*One>
Use
Report Files.SLED Disposition Temp.Fetch.BlockFetchDynamicByRPTCde&Usr/FetchedData,
Control<Current>
This is where Processing can be entered for 2nd and remaining records on every call to BlockFetch function.
Set
Control<RowCount> = Control<RowCount> + <RowCount.*One>
Else
If
Control<MoreData> == <MoreData.Yes>
Get
more data from the server
Call
Report Files.SLED Disposition Temp.Fetch.BlockFetchDynamicByRPTCde&Usr
Set
Control<Position> = <Position.No>
Case
When
Environment<*Call status> IS <State: OBJECTS/*Call status.*Abnormal>
Handle
Error Conditions
+++Set
Value Field: OBJECTS/*Message, Message: FIELDS/FunctionCallFailed
+For
Defined Value Field: OBJECTS/*Message
+For
Each Property MSG impl name NME
+++Set
Value To Current Field: OBJECTS/*Message ID, .Target
++Name
Defined Field: OBJECTS/*Message, Environment<*Message ID>
Name
Function: Report Files.SLED Disposition Temp.Fetch.BlockFetchDynamic, Environment<*Object>
Format
Message Message: FIELDS/FunctionCallFailed, Environment<*Message text>
Go
Sub Send message
Set
Control<MoreData> = <MoreData.No>
Set
Control<BufferedRows> = <BufferedRows.*Zero>
Set
Control<UseRow> = <UseRow.No>
Otherwise
If
Environment<*Returned status> IS <State: OBJECTS/*Returned status.*Abnormal>
Set
Control<MoreData> = <MoreData.No>
If
data is sucessfully fetched, process records
If
Control<BufferedRows> != <BufferedRows.*Zero>
Set
Control<Current> = <Current.*One>
Set
Control<BufferedRows> = Control<BufferedRows> - <BufferedRows.*One>
Set
Control<RowCount> = Control<RowCount> + <RowCount.*One>
Use
Report Files.SLED Disposition Temp.Fetch.BlockFetchDynamicByRPTCde&Usr/FetchedData,
Control<Current>
This is where processing takes places for the first record fetched on every call to BlockFetch function.
Else
Set
Control<UseRow> = <UseRow.No>
Else
Set
Control<UseRow> = <UseRow.No>
Field 'BufferedRows' field can be replaced by FIELDS/RowsFetched to provide a meaningful description of the purpose of this control field.
Create the following OpenWordDocument Source Code object (Script Engine SYS VBScript)
'Start Word application
bExit = True
Err.Clear
On Error Resume Next
Set Word = GetObject(, "Word.Application")
If Err.Number <> 0 Then
Err.Clear
Set Word = CreateObject("Word.Application")
Else
bExit = False
End If
'Open WORD in invisible mode
Word.Visible = False
Set WordApp = Word.Application
Set WordDoc = Word.Documents.Open(&(1:))
Where:
&(1:) = FIELDS/FullPath represents the FullPath +FullFile Name
Solution: This is normal behavior. One user (the one extracting) only had a READ LOCK on the Group Model which allowed the second user start his UPDATE process.
Note: Group Model Locks are created whenever a user is logged to read or write data in the Group Model.
COOL:Plex creates two types of locks:
a) READ Lock is created while reading the Group Model. This lock does not stop users from logging in to the Group Model for reading purposes therefore multiple EXTRACTIONS can take place simultaneously
b) WRITE Lock is created when updating the Group model. This lock is EXCLUSIVE and prevents other users from logging in to the Group Model or, if users are already logged in, it stops them from reading the Group Model.
COOL:Plex displays the PARSING dialog box while it is processing action diagram instructions that you have entered. Some instructions may take a long time to process. In these cases, you can cancel the entry and re-specify the instructions in a form that is quicker for the Action Diagrammer to process. The Action Diagrammer assumes that anything contained within the < and > delimiters is complete. When parsing variable-to-variable comparisons, however, it is not possible to use these delimiters, and it is here that performance problems may be encountered. For example, if the variable names in the following instruction appear many times in the Local Model, the instruction should be broken down into nested If statements:
If Var1 = Var2 AND Var1 = Var3 AND Var1 = Var4
As a general rule use < and > delimiters wherever possible. In complex expressions, especially those which cannot use the < and > delimiters, keep the number of operands down by nesting one or more nested expressions such as:
IF Var 1 = Val1 AND Var 1 = Val2 AND Var 1 = Val3
IF Var 2 = Val1 AND Var 2 = Val2 AND Var 2 = Val3
ELSE
To represent Var 1 = Val1 AND Var 1 = Val2 AND Var 1 = Val3 AND Var 2 = Val1 AND Var 2 = Val2 AND Var 2 = Val3
The following list displays what kind or source files are generated out of the primary Plex's model objects for Windows, NT, and AS400 implementations:
For WinC/AS400 Configurations:
FOR NT/Backoffice configurations:
Solution: Create the following 'Create Excel File' Source Code (Script Engine = VBScript) and make an API call to use it:
Dim objFile, objWorkbook, objWorkbookSheet
Path = Trim(&(1:))
set objFile = CreateObject("Excel.Application")
objFile.Visible = False
Set objWorkbook = objFile.Workbooks.Open(Path, 1)
Where:
&(1:) = FIELDS/FullPath
Also, other approach is commented on the following EDGE Forums thread:
http://www.edgeusergroup.org/forums/Thread.cfm?CFApp=82?&&Message_ID=77498&_#Message77498
More examples on how to work with Excel in PLEX are found in:
http://caforums.ca.com/ca/attachments/ca/caplexgeneraldiscussion/1251/1/001.005.DoLoadFromExcel.Sample.JPG
Which is part of the following CA User Forums' Excel to PLEX thread:
http://caforums.ca.com/ca/board/message?board.id=caplexgeneraldiscussion&thread.id=1250
Dim WorksheetNum1
WorksheetNum1 = CInt(&(1:))
Set objWorkbookSheet = objWorkbook.Worksheets(WorksheetNum1)
&(1:) = FIELDS/Number specifying the Spreadsheet's Workbook sheet number to use
NOTE: The following EDGE thread deals with related information: Export a grid result to Excel (97)
Solution: Set the following value on that section Password = NOT_REQUIRED.
This is the additional description of the ODBC Settings parameters:
SAVE DSN. If the DSN or user id in the .INI file is blank, the end user is automatically prompted to enter the required details. If SAVE DSN is set to True, the details entered by the user are written back to the .INI file. If SAVE DSN is set to False (the default), no changes are made to the .INI file.
Data source name (DSN). The ODBC data source name to be used for connection
Userid. Any required user ID for database access
Password. Any required password for database access. If you know that the target DBMS does not require the end-user to logon with a password, enter NOT_REQUIRED for the password value. Otherwise, ODBC will assume that the information was not provided and prompt the end-user for a password during run-time.
Database. Name of the target database
Errorlog. The error log setting. When the Errorlog setting = True, it enables error logging to the file ERROR.LOG, which is found in the directory from which the application is run. If not provided, it defaults to False, and error logging is disabled.
Default Connect. The default setting for this parameter is True. This option allows you to code your own database connections. For example, you may wish to do this in order to use your own encryption routines for passwords and specifying a database to connect to.
If set to false, the COOL:Plex run-time will not connect to the database. Instead, you will need to use the OBODBC/connect source code object to make the connection.
Points to note regarding the Default Connect parameter:
The connection must be executed before the first database access.
The OBDC run-time remembers the first connection made and uses it for all database accesses. Thus, if you execute the OBODBC/connect Source Code more than once in an application, the second and subsequent executions will have no effect.
In addition to those values shown in the above sample [ODBC Settings] section, each DBMS may have their own list of required values. Because these values can vary greatly among products, they cannot be added to the [ODBC Settings] section of the application .INI file. If necessary, the ODBC driver prompts end-users for these values during run-time, each time a Connect statement is encountered.
Getting "compiler limit : terminating line number emission" warning during compilation. Nno generation warnings/errors and function compiles. (Plex 4.5, WinC client)
Solution: This is just an informational message that won't have any repercussion in the compiled object other than not being able to edit source with some tools.
For additional details looks at the following EDGE Forums thread: warning C4049: compiler limit : terminating line number emission.
Full Message text:.
Solution: Two approaches have been found to work around this:
1) Log on the Dispatch service under a named domain account.
2) Enable Null Session Shares on target file server.
For more details on this approach check the following EDGE THREAD: Accessing UNC paths in server functions? .
It is also suggested that you use tools to monitor your system activities such as:
FILEMON for Windows (FREEWARE). Monitors and displays file system activity on a system in real-time.
REGMON for Windows (FREEWARE). A System Registry monitoring utility that shows which applications are accessing Registry, which keys they are accessing, and the Registry data that they are reading and writing, all in real-time.
The short answer is NO. Howerver, for certain conditions where fields in AD's multiple variables' fields contain the desired value, Plex will attemp to provide a list of possible instructions in the Resolve Ambibuous intructions popup.
Note: Is is also a good technique to use the Resolve Ambiguous instruction
popup to accelerate complex statements that take too long to parse into the
Action Diagram
Table of View action diagram statements:
Action Diagam Statement and purpose |
Sets *View Status to: |
Process related |
Insert
Creates a row using the current values in the view variable. |
SCS, ERR |
Creating rows
|
Update
Updates a row using the current values in the view variable. |
SCS, ERR |
Updating rows |
Delete [keyvariable] Deletes the current or specified row. RPG/400: If specified, the keyvariable must contain
the full key of a row and only one row is deleted. |
SCS, ERR |
Deleting rows |
Delete Where variable<character field>RPG/400: Not supported. SQL: Deletes the rows that meet the specified selection criteria. |
SCS, ERR |
Deleting rows |
Select Where variable<character field> RPG/400: Not supported. |
SCS, INF, ERR |
The Select Where statement |
Position EQ keyvariable [, For Update] RPG/400: Moves the file pointer to a specified key value. |
SCS, INF, ILK*, ERR |
Positioning the file pointer in RPG/400 functions (RPG) |
Position GE keyvariable [, For Update] RPG/400: Moves the file pointer to a specified key value or
the next key in sequence. |
SCS, INF, ILK*, ERR |
Positioning the file pointer in RPG/400 functions. (RPG) |
Position GT keyvariable [, For Update] RPG/400: Moves the file pointer after a specified key value. |
SCS, INF, ILK*, ERR |
Fetch GE/GT/LE/LT (in RPG/400. (RPG) |
Fetch EQ keyvariable [, For Update] RPG/400: Reads a record with a specified key. A full key must
be specified. |
SCS, INF, ILK*, ERR |
Fetch EQ in RPG/400. (RPG) |
Fetch GE keyvariable [, For Update] RPG/400: Reads a record with a specified key or the next record. |
SCS, INF, ILK*, EOV, ERR |
Fetch GE/GT/LE/LT in RPG/400. (RPG) |
Fetch GT keyvariable [, For Update] RPG/400: Reads the next record after a specified key. |
SCS, INF, EOV, ILK*, ERR |
Fetch GE/GT/LE/LT in RPG/400. (RPG) |
Fetch LE keyvariable [, For Update] AS/400: Reads a record with a specified key or the first record
before the key. |
SCS, INF, BOV, ILK*, ERR |
Fetch GE/GT/LE/LT in RPG/400. (RPG) |
Fetch LT keyvariable [, For Update] AS/400: Reads the first record before a specified key. |
SCS, INF, BOV, ILK*, ERR |
Fetch GE/GT/LE/LT in RPG/400. (RPG) |
Exec SQL sourcecode [, viewvariable] SQL only: Enables you to use custom SQL SELECT |
|
The Exec SQL statement |
FetchNext [keyvariable] [, For Update] AS/400: Reads the next row after the file pointer and, optionally,
tests whether that row satisfies a partial set of keys. |
SCS, INF, EOV, ILK* or ERR |
FetchPrev and FetchNext in RPG/400. (RPG) |
FetchPrev [keyvariable] [, For Update] AS/400: Reads the first record that satisfies a partial set
of keys or the record before the file pointer. |
SCS, INF, BOV, ILK* or ERR |
FetchPrev and FetchNext in RPG/400. (RPG) |
Release Lock
AS/400: Unlocks the record after the file pointer. |
SCS or ERR |
Row locking in DB2/400 |
Open
AS/400: Opens the view. |
SCS or ERR |
Opening and closing the view |
Close
AS/400: Closes the view once the job ends. |
SCS or ERR |
Opening and closing the view |
Commit
Commits database changes. |
SCS or ERR |
Commitment control |
Rollback
Undoes uncommitted database changes. |
SCS or ERR |
Commitment control |
There are the error codes descriptions: SCS = Successful, ERR = Error, INF = Instance Not Found, ILK = Instance Locked, EOV = End Of View, and BOV = Beginning Of View * ILK status applies within RPG/400 functions only. |
Solution: This is a known error (CA Solution Fix
#QI54937). Problem appears to be related to the incompatibility of the latest
version of IBM API QSYSGETHP. Additional information CA provides: A change was
needed in V5R3 to the QSYGETPH API to close a security gap. This change has
or will hit some customers by surprise. Because of this impact, IBM has a temporary
fix, PTF SI14206 which will allow V5R3 code to run under the "old rules". This
will be for a limited time, to allow Computer Associates to modify the Plex
product to accommodate the new OS changes. If you are experiencing this problem
please contact IBM for PTF SI14206.
After applying IBM PTF SI14206 it is required its 'activation'. This is done
by running the following command as a user with privileges:
CRTMSGQ MSGQ(QSYS/QSYAPI) MSGQFULL(*WRAP)
Also the following could help reduce job logs:
CRTDTAARA DTAARA(QSYS/QSYNOMSG) TYPE(*CHAR) LEN(3)
Solution: Missing GXT file in runtime folder (Plex 5.5 now uses .GXT files –instead of .MAP files- for the ASCII to EBCDIC translations) In addition, also have to comment out the following INI file entry referring to an invalid Code Page value: Code Page=10
Solution: This seems to be a bug due to the drawing sequence on the panel elements. Work arounds: 1) Define the static as type Group or 2) set the Tab Sequence to be last, after the labels (labels need to also include a Tab Sequence). This attachment shows an example
NOTE: If multiple Static Types Frames are contained within another one, the top one needs to be defined with Static Type = GROUP.
Solution: Copied to OBJ folder files obrt.pch, _OBCORE.obj, and vc70.idb from other developer's OBJ folder.
Solution: Attributes are scoped to the field that was qualified to create the Attribute. Lookup up for that field on the browser, expand it and find all Attributes under.
Additional information from Plex’s Help related to Attributes: Attribute (ATR) object type A special type of object that represents those attributes of an entity to which qualifying text has been added (if any). Attribute objects are created and maintained automatically by COOL:Plex. An attribute object is scoped by its field and is named after the qualifier to which it corresponds. If the name of the qualifier changes, the name of the attribute changes automatically. Thus the full name of an attribute object takes the form: field.qualifier If either the field or the qualifier is deleted, the attribute object ceases to exist. Within action diagrams, you utilize attribute objects in exactly the same way as fields. Attributes may be given an implementation name using the ATR impl name NME verb.
Solution: This is due to Local Modifications being displayed in Edit Points (Pre or Post Points) that already include inherited code instead of using points with just local modifications. For example: if a function is a UISTYLE/ShowDetail and if the "Pre Point Subroutines" is used (where the Sub Close, Sub Prompt request, Sub Load Detail, etc. are already defined), local modifications will display the local subroutines plus the inherited ones however, if the "Post Point Subroutines" is used showing local modification (CTRL+SFHT+L) will only display that local code, making the scrolling to read local code easier.
Solution: A WinC function in a WinNT BackOffice application had been compiled with host Model in 400 variant therefore server functions looked were type RPG and when deployed they could not be found. Changed HOST model to Base and recreated. Function called WinNTC server functions successfully
Solution: Create the following "AddFileExtension" Source Code
and make an API CALL to it:
#include <atlpath.h>
{
// Source Code created using ATL Server Library Reference|Utilities Reference.
ATL Server provides code for manipulating paths and URLs in the form of
CPathT and CUrl. Per MSDN "A thread pool, CThreadPool, is used in the
implementation of the ATL Server ISAPI extension class and can also be used
in your own applications. This code can be found in atlpath.h and atlutil.h"
// Adds a specified file extension to the provided Full Path (Path + File
Name) if one doesn't exist.
CPath WorkPath(&(2:));
&(1:) = WorkPath.AddExtension(&(3:));
&(2:) = WorkPath.m_strPath;
}
Where:
&(1:)=ReturnStatus (Numeric)
&(2:)=FullPath (Path + File Name, i.e. Char, 1024)
&(3:)=FileExtension (Char such as .EXE, .DLL, etc.)
Solution: Create the following "GetFileExtension" Source Code
and make an API CALL to it:
#include <atlpath.h>
{
// Source Code created using ATL Server Library Reference|Utilities Reference.
ATL Server provides code for manipulating paths and URLs in the form of
CPathT and CUrl. Per MSDN "A thread pool, CThreadPool, is used in the
implementation of the ATL Server ISAPI extension class and can also be used
in your own applications. This code can be found in atlpath.h and atlutil.h"
// Retrieve the file extension for a given Full Path (Path + File Name),
if one exists.
CPath WorkPath(&(1:));
&(2:) = WorkPath.GetExtension();
}
Where:
&(1:)=FullPath (Path + File Name, i.e. Char, 1024)
&(2:)=FileExtension (Char such as .EXE, .DLL, etc.)
Solution: Create the following "GetFileNameFromFullPath" Source
Code and make an API CALL to it:
#include <atlpath.h>
{
// Source Code created using ATL Server Library Reference|Utilities Reference.
ATL Server provides code for manipulating paths and URLs in the form of
CPathT and CUrl. Per MSDN "A thread pool, CThreadPool, is used in the
implementation of the ATL Server ISAPI extension class and can also be used
in your own applications. This code can be found in atlpath.h and atlutil.h"
// Retrieve the File Name from a provided Full Path (Path + File Name)
CPath WorkPath(&(1:));
WorkPath.StripPath();
&(2:) = (CString) WorkPath;
}
Where:
&(1:)=FullPath (Path + File Name, i.e. Char, 1024)
&(2:)=FileName (i.e. Char, 1024)
Solution: Create the following "GetPathFromFullPath" Source Code
and make an API CALL to it:
#include <atlpath.h>
{
// Source Code created using ATL Server Library Reference|Utilities Reference.
ATL Server provides code for manipulating paths and URLs in the form of CPathT
and CUrl. Per MSDN "A thread pool, CThreadPool, is used in the implementation
of the ATL Server ISAPI extension class and can also be used in your own applications.
This code can be found in atlpath.h and atlutil.h"
// Retrieve the Path Portion from a provided Full Path (Path + File Name)
CPath WorkPath(&(2:));
&(1:) = Work.RemoveFileSpec();
&(3:) = (CString) WorkPath;
}
Where:
&(1:)=ReturnStatus (Numeric)
&(2:)=InputFullPath (Path + File Name, i.e. Char, 1024)
&(3:)=OutputPath (Path + File Name, i.e. Char, 1024)
Solution: Create the following "CheckIfPathIsADirectory" Source
Code and make and API CALL to it:
{
// Checks if the path is a directory or not
&(1:) = PathIsDirectory(&(2:));
}
Where:
&(1:)=ReturnValue (Boolean)
&(2:)=InputPath (i.e. Char, 1024)
A related checkup would be whether the Path is formed with Universal Naming
Conventions (UNC):
"CheckIfPathIsUNC" Source Code:
{
// Checks if the path is formed with UNC (\\...)
&(1:) = PathIsUNC(&(2:));
}
Where:
&(1:)=ReturnValue (Boolean)
&(2:)=InputPath (i.e. Char, 1024)
{
&(1:) = PathIsURL(&(2:).strGetText());
}
Where:
&(1:) = OBWIN/Boolean
&(2:) = FIELDS/URL
Note on PathIsDirectory (10/08/07):
From Microsoft Developer Network (http://msdn2.microsoft.com/en-us/library/ms628575.aspx): "The return value isn't really TRUE (1) when the path is a valid directory but FILE_ATTRIBUTE_DIRECTORY (16). So tests like, if return value is equal to TRUE, wont work" therefore define validation of returned status based on the FALSE value
136B. How can I determine if a windows folder/directory contains any file? How can I check if it contains specific file types?:
Solution: Create the following Source Code object and make an API Call to it specifying the required parameters:
Source Code 'Find Files of Specified Type':
CString szFolder = CString(&(1:));
szFolder.TrimRight();
CString szFilter = CString( &(2:) );
szFilter.TrimRight();
CString szSource = szFolder + CString("\\") + szFilter;
// Check every file in the directory
CFileFind ffSource;
int nRet = ffSource.FindFile( szSource );
if ( nRet == 0 ) {
&(3:) = ObCharFld( "ERR" );
}
else {
&(3:) = ObCharFld( " " );
}
Where:
&(1:) = Source Path (FIELDS/FullPath)
&(2:) = File Filter (FIELDS/FullPath). Possible values: DLL Files = *.DLL, Word Files = *.DOC, XML Files = *.XML, No extension = *., All Files = *.*, or PDF FIles = *.PDF
&(3:) = *Returned Status. Possible values: Successful ( ) if files are found or Error (*ERR) if not found
136C. How can I get a list of all the files found in a Windows Folder/Directory?
Solution: Create the following Source Code object and make an API Call to it specifying the required parameters:
Source Code 'Retrieve File Names In Path'
// Initialize the field that will contain File Name
CString szFile;
// Check for the next file in the specified Path
int nRet = ffSource.FindNextFile();
szFile = ffSource.GetFilePath();
// Assign the full path (Path+FileName+Extension)
&(1:) = ObCharFld( szFile );
// Validate the return info
if ( nRet==0 ) {
if (GetLastError() != ERROR_NO_MORE_FILES)
&(2:) = ObCharFld( "ERR"); // Error retrieving next file
else
&(2:) = ObCharFld( "EOV"); // Last file to be copied
}
else {
&(2:) = ObCharFld( " ");
}
Where:
&(1:) = Source Path (FIELDS/FullPath). Initially pass the source path without a File Name
&(2:) = *Returned Status
136D. How can I add functionality to panel to allow browsing for a PC Folder?
Solution: Send me an email to request the document that includes the process to implement a function with functionality to browse for a PC Folder (PROCEDURE TO IMPLEMENT A DIALOG FOR PC FOLDER BROWSING.zip)
Solution: create the following Source Code (script engine VBScript) and make an API call to it:
'This Source Code utilizes the FileSystemObject
' Create the Windows Folder if necessary
Set fso = CreateObject("Scripting.FileSystemObject")
szNewPath = &(1:)
If (fso.FolderExists( szNewPath )) Then
'Do nothing as the provided path was found
Else
fso.CreateFolder( szNewPath )
End If
Where (1&:) = Fields/FullPath
Alternatively you can create the following Source Code which does not require a client function scoping a panel as it is C++ and not VBScript:
{
CFileFind ffDir;
int nRes = ffDir.FindFile( &(1:) );
if ( nRes==0 ) {
_mkdir( &(1:) );
}
}
Solution: In the 400 Command Line type WRKACTJOB (Work with Active Jobs), look for your job and enter Option 7 (Display Message) next to it. This will display a window where the message is displayed and a command line to enter the reponse.
Solution: The program was attempting a call to a client function. WinNTC server programs cannot call WinC clients. Replaced the client function by a server version.
Solution: NT Configuration|NT ODBC Connection information was incorrect. In this case it was the DB Password.
Solution: A new licensing entry needs to be updated on CA.OLF (entry similar to FEATURE CA_LICENSE CAI_lic_d 1.000 + Code). Contact CA, Licensing Services
Solution: A Plex run-time used by dynamic link library ob550lc.dll had been deployed. Error fixed by ensuring latest Plex runtimes had been deployed.
Solution: Substring the Hour & Minute time components to form a structured time then convert to ISO. See the following document (due to space limitations file is not hosted. Send me an email to request the CONVERT 7-CHAR STRING TIME TO ISO.zip file)
Solution: Error was caused by a second stage of inheritance where the parent function included references to invalid fields. As in this case the grand child function was as close to the grand parent's functionality as the parent's functionality, changed inheritance to defined GrandChild IS A GrandParent and compilation errors were corrected
Solution: Eventhough the Panel object is version dependent not all elements on it are tracked per version therefore certain changes will affect all versions/levels.
From Plex online help on Level considerations: "In general, every change you make to a panel is level-dependent. Certain exceptions are described in Changing the ownership of menu items and other panel elements"
The elements that are not level dependent are those whose ownership is not recorded by triples such as:
Solution: Create a Plex function with an EXEC SQL statement that updates the database with the results of a REPLACE(FieldName, 'SourceString', 'ReplacementString') statement.
Example:
The following script identifies broken records in an iSeries (400) field where a string representing a fully qualified path was created with an incorrect extension PDF instead of TIFF
select * from LIBRARY/FILE where IMGPATH like '%SOURCEPATH%' and IMGPATH like '%.PDF%'
Where:
SOURCEPATH is the beginning portion of the fully qualified path for the broken data such as \\\\Servername\FilesDirectory\Subfolder
IMGPATH is the field that contains the fully qualified path
Once records are identified, modify this script to perform a database UPDATE such as:
UPDATE LIBRARY/FILE SET IMGPATH = replace(IMGPATH, 'PDF', 'TIF')
where IMGPATH like '%SOURCEPATH%' and IMGPATH like '%.PDF%'
Solution: This approach involves Source Codes that are platform independent (NT and iSeries platforms currently supported) and are executed on the server. Send me an email to request the file InstructionsToDefineACaseInsensitiveSingleFetch.zip with details on how to accomplish this.
Solution: Check the following table (retrieved from Plex’s Online Help) to determine what changes are scoped for (only dependent on) the current Versions/Levels/Variants/National Languages:
|
Version/level? |
Variant? |
National language? |
Notes |
Object names, permissions, and flags |
No |
No |
No |
Object names and permissions are the same across all configurations. See also National language-dependent triples. |
Object and large property deletion |
No |
No |
No |
When you delete an object or large property, it is deleted across all configurations. |
Object narrative |
Yes |
Yes |
Yes |
|
Object scope |
No |
No |
No |
When you change the scope of an object, it changes across all configurations. |
Triples |
Yes |
Partial |
Partial |
Only certain verbs are variant and language dependent. When you select a triple in the Model Editor, its configuration is displayed in the Status Bar. |
Triple sequence |
Yes |
No |
No |
Prior to version 3.0 of Advantage Plex, triple sequence was not tracked by level. |
Diagram large property (LP) |
Yes |
Yes |
Yes |
The presence of nodes and links and their layout are configured. |
Action diagrams |
Yes |
See notes |
See notes |
Each individual component is configured by level. Special action diagram processing is required for variant and national language configuration. |
Panel LP |
Yes |
Partial |
Partial |
Each individual element and its properties are configured. Only certain properties are variant and national language dependent. Certain changes are not configuration dependent as described in Changing the ownership of menu items and other panel elements. |
Report LP |
Yes |
Partial |
Partial |
Each individual element and its properties are configured. |
Message LP |
Yes |
Yes |
Yes |
|
Source code LP |
Yes |
Yes |
Yes |
|
Label LP |
Yes |
Yes |
Yes |
|
Value LP |
Yes |
Yes |
No |
|
Help topic LP |
Yes |
Yes |
Yes |
|
Generated source and objects |
Yes |
Yes |
Yes |
You can use different build directories to maintain the source and objects for each configuration. |
Limitations
The configuration control system does not track the existence, name, and
scope of objects. This means that you need to take care when, for example,
deleting
an object that has been used across multiple levels – the object is
removed from all of them.
When you delete an object, all triples pointing to or from the object are also deleted, together with any other objects that it scopes. Advantage Plex performs some validation to determine whether you have authority to the levels in which these triples exist and whether you have permission to the objects. You are prevented from deleting the object if you do not have permission or authority.
Note: This validation does not extend to large properties. For example,
when you delete a function, Advantage Plex does not check whether its action
diagram
contains statements entered at levels to which you do not have authority.
This is because the configuration information about the action diagram is
stored inside the large property and is not available to the deletion mechanism.
This same limitation applies when you delete a large property using the
Delete
Large property command on the Tools menu of the Object Browser.
Solution: Create a VBScript Source Code with the code below an make an API Call to it. For an entire description including an example see the attached document (due to space limitations file is not hosted. Send me an email to request the Launch default browser with URL.zip file)
set oShell = CreateObject("WScript.Shell")
oShell.Run &(1:)
Where:
&(1:) = URL
Solution: Create the following Source Code object (Script Engine = VBScript) where each individual input field is trimmed then added a single space if it contains a value. Finally, the output is returned in one of the input fields for consumption by the calling function. This example forms a Street Name formed by the concatenation of up to 5 fields (street number, street prefix, street name, street type, street suffix) and the returned concatenated string is VL Street Name:
StreetNumber = trim(&(1:))
StreetPrefix = trim(&(2:))
StreetName = trim(&(3:))
StreetType = trim(&(4:))
StreetSuffix = trim(&(5:))
' Append space to non-blank fields
If StreetNumber > " " Then
StreetNumber = StreetNumber + " "
else
StreetNumber = StreetNumber
end if
if StreetPrefix > " " Then
StreetPrefix = StreetPrefix + " "
else
StreetPrefix = StreetPrefix
end if
if StreetName > " " Then
StreetName = StreetName + " "
else
StreetName = StreetName + " "
end if
if StreetType > " " Then
StreetType = StreetType + " "
else
StreetType = StreetType
end if
if StreetSuffix > " " Then
StreetSuffix = StreetSuffix + " "
else
StreetSuffix = StreetSuffix
end if
' Concatenate all fields
ConcatenatedStreetName = StreetNumber + StreetPrefix + StreetName + StreetType + StreetSuffix
&(3:) = ConcatenatedStreetName
Solution: The Model editor entry in the ini file was changed where the Verb Group would not display a value. Following are the incorrect and correct settings to display triples correctly:
Failing PC:
[ModelEditor]
Verb group=-1
Insert=0
ShowLevel=1
ShowStop=1
ShowCont=1
Focus=2,3,15,10,18,4,22,6,32,1,11
Red=ff
Green=8000
Blue=ff0000
show_options=1
header_cent=Model Editor
footer_cent=Page : $P
header_left=Model: $N
footer_left=
header_right=$D
footer_right=
Tabs options=50
Tabs report=70, 110
Pad chars=----
Top=10
Right=15
Bottom=10
Working settings:
[ModelEditor]
Verb group=0
Insert=0
ShowLevel=0
ShowStop=0
ShowCont=1
Focus=2,3,15,10,18,4,22,6,32,1,11
Red=ff
Green=8000
Blue=ff0000
show_options=1
header_cent=Model Editor
footer_cent=Page : $P
header_left=Model: $N
footer_left=
header_right=$D
footer_right=
Tabs options=50
Tabs report=70, 110
Pad chars=----
Top=10
Right=15
Bottom=10
Solution: Stop/start the YOBLISTENER (WRKACTJOB) if its already running as it was the case when this issue was found.
Solution: Create the following two Source Codes:
1) FormatFieldToFixedLengthWLead0
{
CString szOrig;
int nLen = &(2:) - &(3:).GetLength();
szOrig.Format( "%0*s%s", nLen, &(1:).pszGetText() , &(3:).pszGetText());
&(3:) = ObCharFld( szOrig );
}
Where:
&(1:) = WRK_Char 200 (Char, 200)
&(2:) = StringLength (NUmeric, 4, 0)
&(3:) = WRK_Output Char 200 (Char, 200)
%0*s%s = Formatting specification. An integer placed between a '%' sign and the format command 's', in this case nLen, acts as a minimum field width specifier and pads the output with spaces or zeros to make it long enough. To pad with zeros a zero has been placed before the minimum field width specifier
2) Format Field to Fixed Length
{
CString szOrig;
int nLen = &(2:) - &(3:).GetLength() + &(1:).GetLength();
szOrig.Format( "%s%*s", &(3:).pszGetText(), nLen, &(1:).pszGetText() );
&(3:) = ObCharFld( szOrig );
}
Where:
&(1:) = WRK_Char 200 (Char, 200)
&(2:) = StringLength (NUmeric, 4, 0)
&(3:) = WRK_Output Char 200 (Char, 200)
%s%*s = Formatting specification. An integer placed between a '%' sign and the format command 's', in this case nLen, acts as a minimum field width specifier and pads the output with spaces or zeros to make it long enough. To pad with spaces (blanks) only the character '*' is used before the minimum field width specifier
In your Action Diagram, depending on your validation, make an API Call to either the 1st or 2nd Source Code to format and pad the required field which is processed in (&3:). &(2:) is passed the maximum length for the field and &(1:) is a delimiter that is placed between the padding characters and the strings. In the implementation of these Source Codes, the delimiter was set to match either a 0 when padding with 0s or ' ' when padding with spaces.
Solution: Error was caused by a second stage of inheritance where the parent function included references to invalid fields. As in this case the grand child function was as close to the grand parent's functionality as the parent's functionality, changed inheritance to defined GrandChild IS A GrandParent and compilation errors were corrected.
Solution: The Panel’s 'Icon File' property included an icon that was referenced with this incorrect path instead of just including the ICO file name. Removed the path and recompiled successfully as the Gen & Build Options for the Resource Directories is now read.
Solution: A client WinC was calling a server that had been generated with an incorrect WinNT/Backoffice variant, instead of Windows/ODBC, therefore such server looked for a non-existing NT Server
Solution: An event on the Panel Designer had been set to Exist = NO but its associated logic in the Action Diagram was still present. Resolved by leaving the event on the panel (set back to Exist = YES) and disassociating the physical event on the panel elements that triggered such logical event.
truncate table owner.Table1ImplementationName
truncate table owner.Table2ImplementationName
truncate table owner.Table3ImplementationName
truncate table owner.Table4ImplementationName
truncate table owner.Table5ImplementationName
Solution: The problem was caused by a missing file in the list of files accessed by the SQL logic which caused the entire SQL Source Code to fail with the reported *view error. Two solutions:
1) Ensure all tables accessed by the SQL Statements exist before executing this Source Code
2) Split into multiple SQL Source Codes so if one or more tables is not found, the other SQL Source Codes will still execute correctly.
3) TRUNCATE TABLE will fail on files that include a Foreign Key constraint (FK). In such instances transform the statement to use DELETE FROM i.e. delete from owner.Table1ImplementationName
Solution: Resolved issue following CA's recommendation to replace the use of OBAS400/Get AS400 User ID Source Code to the 400 Function AS400/GetJobIdentifierprogram.
The external API AS400/GetJobIdentifier calls the function YOBRTVJOBC in the
PLEX610 library to retrieve the qualified job identifier of a server job. The
function outputs the parameters: Output OBJECTS /*Returned Status, Output OBJECTS/Job
Number, Output OBJECTS/User ID, and Output OBJECTS/Job Name
Solution: Use the Move Object (MOVOBJ) command in the command line. I.E.
MOVOBJ OBJ(A/TEST) OBJTYPE(*PGM) TOLIB(B)
moves the RPG function TEST from Library A to B
Solution: The panel had been updated to include multiple regions and fields and for some unknown reason the DetailP region was not being 'read'. Deleted (removed on the Panel Editor) the fields within the DetailP variable and re-introduced them. After doing this, the GET statement successfully read the values from the panel.
Do you have any problem/solution you would like to share? Send me an email and I'll get it posted.
If you found any information interesting or useful please mention it on the Guestbook on
the main page of Plex world.
If you could contribute to keep this site free, personal checks or paypal
payment are gladly accepted (no matter how small the contribution).
If you need assistance developing or managing your projects don't hesitate to call me. I provide independent hourly consulting at a very competitive cost.
Developed by: Lucio Gayosso, MIS/M, BS, PLEX Expert (1999-2011)
Background music: Tangerine Dream's "Poland" (same album's name)
Use the controls to Stop, Start, Play the music
Listen to: R@DIO
DIMENSION and let your mind fly... |
||
Escucha: R@DIO
DIMENSION y deja a tu mente volar...
|