1. John Fauss
  2. PowerBuilder
  3. Tuesday, 26 September 2023 19:17 PM UTC

As the Windows O/S and the exploits of virus/ransomware and anti-virus software has evolved, so too has the generally-accepted location(s) where an application can safely write a temporary file (such as a PDF to be included as an email attachment) to disk.

I know I'm dating myself, but a L-O-N-GGGG time ago, the TEMP environment variable typically pointed to C:\Temp. Later, it was acceptable to write to the current user's "My Documents" (now just shortened to "Documents") folder, but this location is targeted by ransomware, so it's common now for only trusted apps to have access to this location. More recently, it looks like the TEMP environment variable now points to the C:\users\username\AppData\Local\Temp folder. 

Question: The need for temporary files has not gone away, so where does your application write temporary files? I'd be very interested to learn what others are doing.

Many thanks in advance!
John

Accepted Answer
Chris Pollach @Appeon Accepted Answer Pending Moderation
  1. Tuesday, 26 September 2023 20:00 PM UTC
  2. PowerBuilder
  3. # Permalink

Hi John;

    FWIW: My STD Framework locates & then uses the AppData (Environment Variable) O/S mapped location. When I run a PB App developed from the framework (as an example) it points the PB App to the "C:\Users\Chris\AppData\Roaming" location for all WIP (work in progress) files. From there, I add an App designator such as "OES". So my OrderEntry App for example would use "C:\Users\Chris\AppData\Roaming\OES" as a fully qualified path for all it's working files. That way, any PB App should have full write permission for that App user.   ;-)

Food for thought.  HTH

Regards ... Chris

  

Comment
  1. John Fauss
  2. Friday, 29 September 2023 19:55 PM UTC
Many thanks to Chris, Miguel, Benjamin, Bruce & Mike for your responses, as ALL were useful in helping me determine the best course to follow for our application. The path described by the APPDATA environment variable will be the primary, preferred location, with an app-specific subdirectory as Chris has described.

If for any reason that value is missing or the path is not valid, a cascading technique as illustrated in Mike's code snippet will be used, checking several paths in the following order: APPDATA, TEMP, TMP, PUBLIC, then USERPROFILE. Even though I don't need it in this particular case, Bruce's use of both the Local and Roaming subdirectories is very interesting and I appreciate him sharing it.
  1. Helpful 1
  1. Chris Pollach @Appeon
  2. Friday, 29 September 2023 20:22 PM UTC
You are most welcome John!
  1. Helpful
There are no comments made yet.
mike S Accepted Answer Pending Moderation
  1. Wednesday, 27 September 2023 15:49 PM UTC
  2. PowerBuilder
  3. # 1
string ls_values[]
ContextKeyword lcx_key
 
GetContextService ('Keyword', lcx_key)

lcx_key.GetContextKeywords ('TMP', ls_values[])
if upperbound(ls_values[]) > 0 then 
	ls_dir = ls_values[1]
ELSE
	lcx_key.GetContextKeywords ('TEMP', ls_values[])
	if upperbound(ls_values[]) > 0 then 
		ls_dir = ls_values[1]
	ELSE 
		lcx_key.GetContextKeywords ('USERPROFILE', ls_values[])
		if upperbound(ls_values[]) > 0 then 
			ls_dir = ls_values[1]
		ELSE
			lcx_key.GetContextKeywords ('WINDIR', ls_values[])
			if upperbound(ls_values[]) > 0 then 
				ls_dir = ls_values[1]
			end if
		end if
	end if
end if
Comment
  1. mike S
  2. Wednesday, 27 September 2023 15:58 PM UTC
list of somewhat standard environment variables that you can get via the contextservice:





ALLUSERSPROFILE Y C:\ProgramData Predefined machine-wide system variable.

APPDATA Y Y C:\Users\{username}\AppData\Roaming

CD Y Y The current directory (string).

ClientName Y Y Terminal servers only - the ComputerName of a remote host.

CMDEXTVERSION Y Y The current Command Processor Extensions version number. (NT = "1", Win2000+ = "2".)

CommonProgramFiles Y C:\Program Files\Common Files

COMMONPROGRAMFILES(x86) Y C:\Program Files (x86)\Common Files

COMPUTERNAME Y {computername}

DATE Y Y The current date using same region specific format as DATE.

ERRORLEVEL Y Y The current ERRORLEVEL value, automatically set when a program exits.

HOMEDRIVE Y Y C:

HOMEPATH Y Y \Users\{username}

HOMESHARE Y Network home folder.

LOCALAPPDATA Y Y C:\Users\{username}\AppData\Local

LOGONSERVER Y Y \\{domain_logon_server}

NUMBER_OF_PROCESSORS Y The Number of processors running on the machine.

OneDrive Y OneDrive synchronisation folder.

OS Y Operating system on the user's workstation.

PATH Y Y C:\Windows\System32\;C:\Windows\;C:\Windows\System32\Wbem;{plus program paths}

PATHEXT Y .COM; .EXE; .BAT; .CMD; .VBS; .VBE; .JS ; .WSF; .WSH; .MSC Determine the default executable file extensions to search for and use, and in which order, left to right. The syntax is like the PATH variable - semicolon separators.

PROCESSOR_ARCHITECTURE Y AMD64/IA64/x86 This doesn’t tell you the architecture of the processor but only of the current process, so it returns "x86" for a 32 bit WOW process running on 64 bit Windows. See detecting OS 32/64 bit

PROCESSOR_ARCHITEW6432 =%PROCESSOR_ARCHITECTURE% (but only available to 64 bit processes)

PROCESSOR_IDENTIFIER Y Processor ID of the user's workstation.

PROCESSOR_LEVEL Y Processor level of the user's workstation.

PROCESSOR_REVISION Y Processor version of the user's workstation.

ProgramData Y C:\ProgramData

ProgramFiles Y C:\Program Files or C:\Program Files (x86)

ProgramFiles(x86) 1 Y C:\Program Files (x86) (but only available when running under a 64 bit OS)

ProgramW6432 =%ProgramFiles%(but only available when running under a 64 bit OS)

PROMPT Y Code for current command prompt format,usually $P$G C:>

PSModulePath Y %SystemRoot%\system32\WindowsPowerShell\v1.0\Modules\

Public Y C:\Users\Public

RANDOM Y A random integer number, anything from 0 to 32,767 (inclusive).

%SessionName% Terminal servers only - for a terminal server session, SessionName is a combination of the connection name, followed by #SessionNumber. For a console session, SessionName returns "Console".

SYSTEMDRIVE Y C:

SYSTEMROOT Y The main Windows system folder. By default, C:\Windows

TEMP and TMP Y Y C:\Users\{Username}\AppData\Local\Temp Under XP this was \{username}\Local Settings\Temp

TIME Y The current time using same format as TIME. In some locales, this will include a comma separator which is also a command delimiter.

UserDnsDomain Y Y Set if a user is a logged on to a domain and returns the fully qualified DNS domain that the currently logged on user's account belongs to.

USERDOMAIN Y Y {userdomain}

USERDOMAIN_roamingprofile Y The user domain for RDS or standard roaming profile paths. Windows 8/10/2012.

USERNAME Y Y Defined as "SYSTEM", resolves as {username}

USERPROFILE Y Y %SystemDrive%\Users\{username} This is equivalent to the $HOME environment variable in Unix/Linux

WINDIR Y Set by default as windir=%SystemRoot% %WinDir% pre-dates Windows NT, its use in many places has been replaced by the system variable: %SystemRoot%

  1. Helpful 1
There are no comments made yet.
Bruce Armstrong Accepted Answer Pending Moderation
  1. Wednesday, 27 September 2023 15:43 PM UTC
  2. PowerBuilder
  3. # 2

We create a folder for our app under the user's APP_DATA/Local and APP_DATA/Roaming folders.  We have a mechanism where we load a PBD file into the database with patches, and the application downloads that to the Local folder and loads it.  That's how we deploy fixes.  The INI file gets stored in the Roaming folder.

Comment
  1. mike S
  2. Wednesday, 27 September 2023 15:55 PM UTC
we use programdata instead of the user's appdata - it should have similar permissions for writing out patch/custom pbds and updating ini file.

it *was* easier to find since it is the same directory rather than have to figure out the user's login, plus it is shared in case more than one user logs into the machine. Now windows hides that directory by default.



I'm a bit on the fence as to whether to change it to user's app data since programdata is now harder to see since you have to know windows hides it. I'm not sure whether some lock down security levels also prevent writing to that directory even though it is supposed to be for the program's data.

  1. Helpful
  1. Bruce Armstrong
  2. Wednesday, 27 September 2023 16:01 PM UTC
App Data is hidden by windows as well. According to this, Program Data is for user agnostic data, so depending on whether or not you store user specific info in the INI file ( we do ) would depend on whether you want to use App Data vs Program Data.



https://stackoverflow.com/questions/27497375/difference-between-program-files-and-programdata#:~:text=Program%20Files%20is%20for%20executables,goes%20in%20the%20AppData%20folder.
  1. Helpful 3
There are no comments made yet.
Benjamin Gaesslein Accepted Answer Pending Moderation
  1. Wednesday, 27 September 2023 06:42 AM UTC
  2. PowerBuilder
  3. # 3

Like Chris, I use %APPDATA% with a subdir for the application. I read the variable using GetContextService+GetContextKeywords. Imho this is the safest bet because it also works when it's run as a remote app.

While unlikely, it's possible that the %APPDATA% environment variable has been deleted or changed by a user. With that in mind, using the SHGetKnownFolderPath function might be better yet.

Comment
There are no comments made yet.
Miguel Leeuwe Accepted Answer Pending Moderation
  1. Tuesday, 26 September 2023 21:12 PM UTC
  2. PowerBuilder
  3. # 4

(ok, connected to the office, away from my linux):

External function declaration:

Function unsignedLong GetTempPath(unsignedLong nBufferLength, REF String lpBuffer) LIBRARY "KERNEL32.DLL" ALIAS FOR "GetTempPathW"

 

Script of some function like of_getTempPath:

String ls_tempPath
ls_tempPath = Space(2048) // 2048, just in case of any future improvements of MS limited filepath lengths :)

IF GetTempPath(2048, ref ls_tempPath) > 0 THEN
    Return(Trim(ls_tempPath))
END IF

Return('')

 

Comment
There are no comments made yet.
Miguel Leeuwe Accepted Answer Pending Moderation
  1. Tuesday, 26 September 2023 21:04 PM UTC
  2. PowerBuilder
  3. # 5

Hi John,

Just do a "cd %temp%" from a command shell.

There's an API function also to figure that out, but I cannot post it until tomorrow when I'm off Linux.

regards.

Comment
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.