SAS Enhanced Editor in SAS/AF
The BUILD environment will use the Enhanced Editor (instead of the old Notepad/Source editor) if you change a SAS Registry entry.
Issue the SAS command REGEDIT. Navigate to node PRODUCTS/AF/Design Time/Source Window Set Enhanced Editor (Experimental) to Yes
The problem is that when the EE setting is on, a bug lets you open an SCL entry more than one time in edit mode. In certain situations it is too easy to save changes, and accidentally save over them again from another window, ruining the original changes.
Tech Support might only be able to suggest "don't use enhanced editor to edit your SCL"
If you are running SAS on windows, there is a roundabout solution.
Step 1.
Install rad4sas.dll in your %WINDIR% or any directory in your %PATH%.
This dll has been floating around since June 2001. It's nice to be able to put it to good use.
Step 2.
Place this SASCBTBL code in your autoexec.sas
filename SASCBTBL catalog 'WORK.WINAPI.WINAPI.SOURCE'; data _null_; file SASCBTBL; input ; put _infile_; cards4; routine GetProcessChildWindows module = rad4sas minarg = 2 maxarg = 2 returns = long ; * stackpop = called ; arg 1 update char byaddr format=$char8000. ; arg 2 input num byvalue format=pib4. ; routine GetWindowTextA module = user32 minarg = 3 maxarg = 3 stackpop = called returns = long ; arg 1 num input byvalue format=pib4.; arg 2 char update byaddr format=$CSTR200. ; arg 3 num input byvalue format=pib4.; ;;;;
Step 3.
Compile this SCL as SASUSER.SESSION.OPENSCL.SCL
main: L = envlist ('L'); * call putlist (L,'',0); CMD = getNitemL (L,'_CMDLIST_'); E = getNitemC (CMD,'ENTRY',1,1,''); if E = '' then do; put 'ERROR: ENTRY= was not specified.'; return; end; E = upcase(E); declare char(8000) handles; handles = repeat('.',7999); rccw = modulen ('GetProcessChildWindows', handles, 1000); if rccw eq . then do; put 'ERROR: GetProcessChildWindows was not called. ' 'SASCBTBL may have been deleted or altered.'; return; end; * hWndCount = band (rccw, 0FF00x) / 0100x; enumCount = band (rccw, 000FFx); declare char(200) parentTitle childTitle; addr = addr(handles); do i = 1 to min (enumCount, 1000); parentHWND = peek (addr); childHWND = peek (addr+4); addr+8; parentTitle = repeat('01'x,100); rc = ModuleN ( '*e', 'GetWindowTextA', parentHWND, parentTitle, 200); parentTitle = trim(parentTitle); childTitle = repeat(' ',199); if childHWND ne 0 then rc = ModuleN ( '*e', 'GetWindowTextA', childHWND, childTitle, 200); else childTitle = 'n/a'; childTitle = trim(childTitle); if index (upcase(childTitle), E) gt 0 then do; put 'ERROR:' E 'is already being edited.'; return; end; end; call build (E); return; rc=rc;
Step 4.
Alter the Explore default command for catalog member SCL entry type
- Activate an Explorer window - Menu Tools/Options/Explorer... - Select Entries tab - Select type SCL - Add - action: &Edit - action command: afa c=sasuser.session.openscl.scl entry=%8b.%32b.%32b.%8b - OK - Select Edit - Click Set Default - OK
You can repeat this customization for Source entries as well.
Sasuser.session.openscl.scl will ensure the SAS Explorer Edit action opens an SCL entry only once.
Note: Two build commands (issued in the command box) can still open the an entry twice, both in edit mode.
Development note
If you compare the SCL SASCBTBL definition and MODULEN invocation to the DATA Step examples found on my SASCBTBL page, there will be some differences. It seems that the value returned by addr(array element referenced by variable index) differs between DATA Step and SCL Program.
In DATA Step addr(A[i])
for different i
returns a different address, in SCL each addr(A[i])
for different i
returns the same address.
Compare
74 data _null_; 75 array x[100] _temporary_; 76 77 do i = 1 to 2; 78 ax = addr(x[i]); 79 put i= ax=; 80 end; 81 run; i=1 ax=82869248 i=2 ax=82869256 <— adjacent address, good
To
main: array x[100] ; do i = 1 to 2; ax = addr(x[i]); put i= ax=; end; return; ---log--- NOTE: Compiling RAD.SCL. NOTE: Code generated for RAD.SCL. Code size=3664. i=1 ax=82851656 i=2 ax=82851656 <— same address!, weird
Thus, I chose to use a large character variable and $char8000. to allocate the buffer space whose address is passed to rad4sas::GetProcessChildWindows by modulen().
Developer note
If you want to open subsequent windows in Browse mode (as opposed to not opening another window) you can change the openscl.scl code to do this:
if index (upcase(childTitle), E) gt 0 then do; put 'NOTE: Browsing' E; call build (E, 'browse'); return; end;
To conditionally do this, you could check for an additional command line option that controls Browse or Error. For example:
afa c=sasuser.session.openscl.scl
entry=%8b.%32b.%32b.%8b
browseIfAlreadyOpen=yes
Additional options would have to be parsed out of the _CMDLIST_ sublist of the local environment list.