Accessing LocalApplicationData Equivalent in Delphi - delphi

Using Delphi, how do I access the equivalent of .NET's System.Environment.SpecialFolder.LocalApplicationData variable (which works on any version of Windows)? I assumed I could just do:
dir := GetEnvironmentVariable('LOCALAPPDATA');
This works on Vista but XP doesn't seem to set that environment variable by default at least on my test machine.

In Delphi, the special system folder path constants are defined in ShlObj.DCU, and are referenced in the form of CSIDL_ followed by a symbolic name.
Example:
CSIDL_DESKTOPDIRECTORY returns the
path to the current desktop
CSIDL_PERSONAL is the My Documents directory
CSIDL___LOCAL_APPDATA is the (user name)\Local Settings\Application
Data directory
Here's a quick function that will return the appropriate special folder path when given the symbolic name. Make sure you include the SHLOBJ.DCU unit in your USES statement, and use the following:
function GetSpecialFolderPath(Folder: Integer; CanCreate: Boolean): string;
// Gets path of special system folders
//
// Call this routine as follows:
// GetSpecialFolderPath (CSIDL_PERSONAL, false)
// returns folder as result
//
var
FilePath: array [0..255] of char;
begin
SHGetSpecialFolderPath(0, #FilePath[0], FOLDER, CanCreate);
Result := FilePath;
end;
================================================================
For reference, the constants are as follows:
CSIDL_DESKTOP = $0000; { <desktop> }
CSIDL_INTERNET = $0001; { Internet Explorer (icon on desktop) }
CSIDL_PROGRAMS = $0002; { Start Menu\Programs }
CSIDL_CONTROLS = $0003; { My Computer\Control Panel }
CSIDL_PRINTERS = $0004; { My Computer\Printers }
CSIDL_PERSONAL = $0005; { My Documents. This is equivalent to CSIDL_MYDOCUMENTS in XP and above }
CSIDL_FAVORITES = $0006; { <user name>\Favorites }
CSIDL_STARTUP = $0007; { Start Menu\Programs\Startup }
CSIDL_RECENT = $0008; { <user name>\Recent }
CSIDL_SENDTO = $0009; { <user name>\SendTo }
CSIDL_BITBUCKET = $000a; { <desktop>\Recycle Bin }
CSIDL_STARTMENU = $000b; { <user name>\Start Menu }
CSIDL_MYDOCUMENTS = $000c; { logical "My Documents" desktop icon }
CSIDL_MYMUSIC = $000d; { "My Music" folder }
CSIDL_MYVIDEO = $000e; { "My Video" folder }
CSIDL_DESKTOPDIRECTORY = $0010; { <user name>\Desktop }
CSIDL_DRIVES = $0011; { My Computer }
CSIDL_NETWORK = $0012; { Network Neighborhood (My Network Places) }
CSIDL_NETHOOD = $0013; { <user name>\nethood }
CSIDL_FONTS = $0014; { windows\fonts }
CSIDL_TEMPLATES = $0015;
CSIDL_COMMON_STARTMENU = $0016; { All Users\Start Menu }
CSIDL_COMMON_PROGRAMS = $0017; { All Users\Start Menu\Programs }
CSIDL_COMMON_STARTUP = $0018; { All Users\Startup }
CSIDL_COMMON_DESKTOPDIRECTORY = $0019; { All Users\Desktop }
CSIDL_APPDATA = $001a; { <user name>\Application Data }
CSIDL_PRINTHOOD = $001b; { <user name>\PrintHood }
CSIDL_LOCAL_APPDATA = $001c; { <user name>\Local Settings\Application Data (non roaming) }
CSIDL_ALTSTARTUP = $001d; { non localized startup }
CSIDL_COMMON_ALTSTARTUP = $001e; { non localized common startup }
CSIDL_COMMON_FAVORITES = $001f;
CSIDL_INTERNET_CACHE = $0020;
CSIDL_COOKIES = $0021;
CSIDL_HISTORY = $0022;
CSIDL_COMMON_APPDATA = $0023; { All Users\Application Data }
CSIDL_WINDOWS = $0024; { GetWindowsDirectory() }
CSIDL_SYSTEM = $0025; { GetSystemDirectory() }
CSIDL_PROGRAM_FILES = $0026; { C:\Program Files }
CSIDL_MYPICTURES = $0027; { C:\Program Files\My Pictures }
CSIDL_PROFILE = $0028; { USERPROFILE }
CSIDL_SYSTEMX86 = $0029; { x86 system directory on RISC }
CSIDL_PROGRAM_FILESX86 = $002a; { x86 C:\Program Files on RISC }
CSIDL_PROGRAM_FILES_COMMON = $002b; { C:\Program Files\Common }
CSIDL_PROGRAM_FILES_COMMONX86 = $002c; { x86 C:\Program Files\Common on RISC }
CSIDL_COMMON_TEMPLATES = $002d; { All Users\Templates }
CSIDL_COMMON_DOCUMENTS = $002e; { All Users\Documents }
CSIDL_COMMON_ADMINTOOLS = $002f; { All Users\Start Menu\Programs\Administrative Tools }
CSIDL_ADMINTOOLS = $0030; { <user name>\Start Menu\Programs\Administrative Tools }
CSIDL_CONNECTIONS = $0031; { Network and Dial-up Connections }
CSIDL_COMMON_MUSIC = $0035; { All Users\My Music }
CSIDL_COMMON_PICTURES = $0036; { All Users\My Pictures }
CSIDL_COMMON_VIDEO = $0037; { All Users\My Video }
CSIDL_RESOURCES = $0038; { Resource Directory }
CSIDL_RESOURCES_LOCALIZED = $0039; { Localized Resource Directory }
CSIDL_COMMON_OEM_LINKS = $003a; { Links to All Users OEM specific apps }
CSIDL_CDBURN_AREA = $003b; { USERPROFILE\Local Settings\Application Data\Microsoft\CD Burning }
CSIDL_COMPUTERSNEARME = $003d; { Computers Near Me (computered from Workgroup membership) }
CSIDL_PROFILES = $003e;

See this article.
Edit:
As added in the comment by stukelly there is a lot more information available about the SHGetFolderPath() functionality. The Delphi VCL really should have functionality for getting standard paths, and if Embarcadero is indeed going to have another Delphi-like tool on another OS this will be all the more important. For a multi-platform implementation of system standard paths see also the documentation of wxStandardPaths in wxWidgets. On MSW this uses the various CSIDL_XXX constants.

Assuming you can make WinAPI calls from Delphi (which ISTR you can), you used to be able to do that with an API call (something like GetSystemFolder or GetUserDataFolder). It's been a while since I've had to do that, but I think you can now do it with SHGetFolderPath, by passing in CSIDL_LOCAL_APPDATA.

Related

NativeScript File.readSync() not working if there is space in file name

I am making an app for ios using nativescript angular. I am selecting and converting a file to base64 to send to server easily. Everything works correctly but if a file has space in it eg: 'myFile 1' then the path of that file is read as 'myFile%201' and I think this is the reason that readSync() is not working. Here is my Code.
const files = await openFilePicker({
multipleSelection:true,
// extensions:['application/pdf','application/msword','application/vnd.openxmlformats-officedocument.wordprocessingml.document','png','jpeg']
// extensions:['application/pdf','application/msword','application/vnd.openxmlformats-officedocument.wordprocessingml.document']
// extensions:[]
})
for(let result of files['files'])
{
// extra line to see console easily/
console.log("");
console.log("result is : ",result)
let selectedFile:File;
if(isAndroid)
{
selectedFile = File.fromPath(result);
}
else
{
selectedFile = File.fromPath(result.replace("file://",""));
}
console.log("");
console.log("\n\nselected File : ", selectedFile)
if(this.isExtensionAllowed(selectedFile['_extension']))
{
if(this.maxAttachmentCount <= 0)
{
this.maxAttachmentCount=0;
}
else
{
this.maxAttachmentCount--;
}
let data = selectedFile.readSync();
console.log("")
console.log("data is : ",data)
let base64File = "";
if(isIOS)
{
base64File = data.base64EncodedStringWithOptions(0);
}
else
{
base64File = android.util.Base64.encodeToString(data,android.util.Base64.NO_WRAP);
}
console.log("");
console.log("base64 is : ", base64File)
let attachmentInfo = {name:selectedFile['_name'],extension:'.'+selectedFile['_extension'],
base64:base64File};
if(this.base64Attachments.length == 4)
{
this.base64Attachments.shift();
}
(<any[]>this.base64Attachments).push(attachmentInfo);
}
}
And here is a screenshot of file name without space which is working:
And here is a screenshot of file name with space which is not working:
I finally had to go to ChatGPT for answer. Apparently I had to use decodeURI(path) to get decoded path and then use File.fromPath.
if(isAndroid)
{
selectedFile = File.fromPath(result);
}
else
{
result = decodeURI(result);
selectedFile = File.fromPath(result.replace("file://",""));
}

modify the redirection after confirming the order in prestashop

How I can modify the redirection after confirming the order from history to my account?
I do not know where I can change the code.
I modified the code of the OrderConfirmationController.php page in the overide:
if (Cart::isGuestCartByCartId($this->id_cart)) {
$is_guest = true;
$redirectLink = 'index.php?controller=guest-tracking';
} else {
$redirectLink = 'index.php?controller=history';
}
By:
if (Cart::isGuestCartByCartId($this->id_cart)) {
$is_guest = true;
$redirectLink = 'index.php?controller=guest-tracking';
} else {
$redirectLink = 'index.php?controller=my-account';
}
and I deleted class_index.php located in the cache folder and still I have the same problem the redirection is to the history
You have to override orderConfirmationController.php
Read this document

Xtext project JDT Independence

I created editor with Xtext 2.9.1 and now I want to make it independent of JDT. I followed this guide https://eclipse.org/Xtext/documentation/307_special_languages.html
but it does not seem to work. This is my ErrmsgUiModule.xtend
#FinalFieldsConstructor
class ErrmsgUiModule extends AbstractErrmsgUiModule {
override configure(Binder binder) {
super.configure(binder);
binder.bind(DefaultHighlightingConfiguration).to(ErrMsgHighlightingConfiguration);
binder.bind(DefaultSemanticHighlightingCalculator).to(ErrorSemanticHighlightingCalculator);
}
override bindIResourceForEditorInputFactory() {
return ResourceForIEditorInputFactory
}
override bindIResourceSetProvider() {
return SimpleResourceSetProvider
}
override provideIAllContainersState() {
return Access.getWorkspaceProjectsState()
}
}
I checked every overwritten method with debugger and all 3 methods are called. I did not created my own project wizard so this should be enough.
But still after plugin installating the Java project wizard becomes available...
/Edit:
To provide more information, this is project's mwe2 file
module com.xxx.lang.errmsg.GenerateErrmsg
import org.eclipse.xtext.xtext.generator.*
import org.eclipse.xtext.xtext.generator.model.project.*
import org.eclipse.xtext.ui.generator.*
var rootPath = ".."
Workflow {
component = XtextGenerator {
configuration = {
project = StandardProjectConfig {
baseName = "com.xxx.lang.errmsg"
rootPath = rootPath
runtimeTest = {
enabled = true
}
eclipsePlugin = {
enabled = true
}
eclipsePluginTest = {
enabled = true
}
createEclipseMetaData = true
}
code = {
encoding = "windows-1250"
fileHeader = "/*\n * generated by Xtext \${version}\n */"
}
}
language = StandardLanguage {
name = "com.xxx.lang.errmsg.Errmsg"
fileExtensions = "msg"
fragment = formatting.Formatter2Fragment2 auto-inject {}
serializer = {
generateStub = false
}
validator = {
// composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
}
}
}
}
and this is list of Dependencies from plugin.xml for various projects:
project com.xxx.lang.errmsg
org.eclipse.xtext,
org.eclipse.xtext.xbase,
org.eclipse.equinox.common;bundle-version="3.5.0",
org.eclipse.emf.ecore,
org.eclipse.xtext.xbase.lib,
org.antlr.runtime,
org.eclipse.xtext.util,
org.eclipse.xtend.lib,
org.eclipse.emf.common,
org.objectweb.asm;bundle-version="[5.0.1,6.0.0)";resolution:=optional,
org.eclipse.xtext.ui
project com.xxx.lang.errmsg.ui
com.xxx.lang.errmsg,
com.xxx.lang.errmsg.ide,
org.eclipse.xtext.ui,
org.eclipse.xtext.ui.shared,
org.eclipse.xtext.ui.codetemplates.ui,
org.eclipse.ui.editors;bundle-version="3.5.0",
org.eclipse.ui.ide;bundle-version="3.5.0",
org.eclipse.ui,
org.eclipse.compare,
org.eclipse.xtext.builder,
org.eclipse.xtend.lib;resolution:=optional,
org.eclipse.xtext.xbase.lib,
org.eclipse.xtext.xbase.ui
/Edit2: According to this topic https://bugs.eclipse.org/bugs/show_bug.cgi?id=336217, I also tried to disable all org.eclipse.jdt* plugins in run configuration. This is what i get http://pastebin.com/Wi0gzceM
You have to remove the dependencies on org.eclipse.xtext.xbase and org.eclipse.xtext.xbase.ui from your runtime and UI project.
Make sure if you open the Plug-in Dependencies in the Package Explorer that you do not see org.eclipse.jdt.core in the list. If so, there is another plug-in having a (transitive) dependency. Find out which and remove.

Common way to execute a stored proc from both ColdFusion and Railo

I think I've gotten the most simplest scenario built. I just want to pass it by everyone for a sanity check. Here's the idea:
GetErrorCodes.cfm does the following:
<cfscript>
response = new ErrorCodes().WhereXXX(); // ACF or Railo, doesn't matter
</cfscript>
ErrorCodes.cfc:
function WhereXXX() {
return new sproc().exec('app.GetErrorCodes'); // All my functions will do this instead of executing the sproc themselves.
}
sproc.cfc:
component {
function exec(procedure) {
local.result = {};
if (server.ColdFusion.productname == 'Railo') {
return new Railo().exec(arguments.procedure); // Has to be outside of sproc.cfc because ColdFusion throws a syntax error otherwise.
}
local.svc = new storedProc();
local.svc.setProcedure(arguments.procedure);
local.svc.addProcResult(name='qry');
try {
local.obj = local.svc.execute();
local.result.Prefix = local.obj.getPrefix();
local.result.qry = local.obj.getProcResultSets().qry;
} catch(any Exception) {
request.msg = Exception.Detail;
}
return local.result;
}
Railo.cfc:
component {
function exec(procedure) {
local.result = {};
try {
storedproc procedure=arguments.procedure result="local.result.Prefix" returncode="yes" {
procresult name="local.result.qry";
}
} catch(any Exception) {
request.msg = Exception.Message;
}
return local.result;
}
}
So I've been working on this all day, but tell me, is this a sane way to keep the source code the same if it's to be run on either a ColdFusion server or a Railo server?
Um... just use <cfstoredproc> instead of trying to use two different CFScript approaches that are mutually exclusive to each other of the CFML platforms.

Where's located the declaration of messageSource in Grails?

Background
We have some legacy internationalization for field labels that are stored in the database, so I tried to make a "merged" messageSource. If the code exists in database, return, if not, use PluginAwareResourceBundleMessageSource to look in the i18n.
Problem
For some reason the cachedMergedPluginProperties is caching the wrong file for the locale. For example, if I search for en_US, I receive pt_BR messages (the key of the Map is en_US, but the properties are pt_BR).
I declared my messageSource as follows:
messageSource(DatabaseMessageSource) {
messageBundleMessageSource = { org.codehaus.groovy.grails.context.support.PluginAwareResourceBundleMessageSource m ->
basenames = "WEB-INF/grails-app/i18n/messages"
}
}
The inner bean is beacause of Grails won't let me have two beans of type MessageSource.
Am I declaring PluginAwareResourceBundleMessageSource different from the default of Grails? In which file of Grails I can see this bean declaration?
I found the declaration inside I18nGrailsPlugin, and it's a bit more detailed then mine:
String baseDir = "grails-app/i18n"
String version = GrailsUtil.getGrailsVersion()
String watchedResources = "file:./${baseDir}/**/*.properties".toString()
...
Set baseNames = []
def messageResources
if (application.warDeployed) {
messageResources = parentCtx?.getResources("**/WEB-INF/${baseDir}/**/*.properties")?.toList()
}
else {
messageResources = plugin.watchedResources
}
if (messageResources) {
for (resource in messageResources) {
// Extract the file path of the file's parent directory
// that comes after "grails-app/i18n".
String path
if (resource instanceof ContextResource) {
path = StringUtils.substringAfter(resource.pathWithinContext, baseDir)
}
else {
path = StringUtils.substringAfter(resource.path, baseDir)
}
// look for an underscore in the file name (not the full path)
String fileName = resource.filename
int firstUnderscore = fileName.indexOf('_')
if (firstUnderscore > 0) {
// grab everyting up to but not including
// the first underscore in the file name
int numberOfCharsToRemove = fileName.length() - firstUnderscore
int lastCharacterToRetain = -1 * (numberOfCharsToRemove + 1)
path = path[0..lastCharacterToRetain]
}
else {
// Lop off the extension - the "basenames" property in the
// message source cannot have entries with an extension.
path -= ".properties"
}
baseNames << "WEB-INF/" + baseDir + path
}
}
LOG.debug "Creating messageSource with basenames: $baseNames"
messageSource(PluginAwareResourceBundleMessageSource) {
basenames = baseNames.toArray()
fallbackToSystemLocale = false
pluginManager = manager
if (Environment.current.isReloadEnabled() || GrailsConfigUtils.isConfigTrue(application, GroovyPagesTemplateEngine.CONFIG_PROPERTY_GSP_ENABLE_RELOAD)) {
def cacheSecondsSetting = application?.flatConfig?.get('grails.i18n.cache.seconds')
if (cacheSecondsSetting != null) {
cacheSeconds = cacheSecondsSetting as Integer
} else {
cacheSeconds = 5
}
}
}
Since Grails don't let you have two beans of type MessageSource I had to copy this code and adapt to mine "merged" messageSource.

Resources