2

I have KnownFolderPath IDs declared as consts:

const
  FOLDERID_LocalAppData  : TGUID = '{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}';
  FOLDERID_RoamingAppData: TGUID = '{3EB685DB-65F9-4CF6-A03A-E3EF65729F3D}';
  FOLDERID_Documents     : TGUID = '{FDD39AD0-238F-46AF-ADB4-6C85480369C7}';
  {...}

I want to define an ordered list of folder ids at compile time. I know I can do the following:

const
  settings_roots: array[0..2] of TGuid = (
    '{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}',
    '{3EB685DB-65F9-4CF6-A03A-E3EF65729F3D}',
    '{FDD39AD0-238F-46AF-ADB4-6C85480369C7}'
  );

But this is not convenient maintainable code so I would like to rather use the names defined before. But this gives me compiler errors in Delphi XE3 (const expression expected):

const
  settings_roots: array[0..2] of TGuid = (
    FOLDERID_LocalAppData, FOLDERID_RoamingAppData, FOLDERID_Documents
  );

I could define the FOLDERIDs as const strings like

const
  FOLDERID_LocalAppData   = '{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}';
  FOLDERID_RoamingAppData = '{3EB685DB-65F9-4CF6-A03A-E3EF65729F3D}';
  FOLDERID_Documents      = '{FDD39AD0-238F-46AF-ADB4-6C85480369C7}';
  {...}

but than I would have to convert the ids with StringToGUID() everywehere in the code. Isn't it somehow possible to define an ordered static / const list of const objects before runtime in Delphi?

Pascal Rosin
  • 1,498
  • 16
  • 27
  • I disagree that it is an exact duplicate. The asker specifically wants to be able to define the original constants as a TGUID (rather than a string) so that he can use them elsewhere in his program directly, as he states. This additional specification renders the answers given in the original invalid IMHO. – Dsm Jan 31 '17 at 16:25
  • A simple edit to Ondrej's answer would resolve that. Akin to the addition I just made to Remy's. – David Heffernan Jan 31 '17 at 16:27

2 Answers2

4

In order to use the ID constants by name in the array declaration, you need to remove the TGuid type from the ID constant declarations, making them "True constants" instead of "Typed constants":

const
  FOLDERID_LocalAppData = '{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}';
  FOLDERID_RoamingAppData = '{3EB685DB-65F9-4CF6-A03A-E3EF65729F3D}';
  FOLDERID_Documents = '{FDD39AD0-238F-46AF-ADB4-6C85480369C7}';
  {...}

This is covered in Embarcadero's documentation:

Declared Constants

True Constants

A true constant is a declared identifier whose value cannot change. For example:

const MaxValue = 237;

declares a constant called MaxValue that returns the integer 237. The syntax for declaring a true constant is:

const identifier = constantExpression

where identifier is any valid identifier and constantExpression is an expression that the compiler can evaluate without executing your program.

...

Constant Expressions

A constant expression is an expression that the compiler can evaluate without executing the program in which it occurs. Constant expressions include numerals; character strings; true constants; values of enumerated types; the special constants True, False, and nil; and expressions built exclusively from these elements with operators, typecasts, and set constructors.

...

Typed Constants

Typed constants, unlike true constants, can hold values of array, record, procedural, and pointer types. Typed constants cannot occur in constant expressions.

...

Array Constants

To declare an array constant, enclose the values of the elements of the array, separated by commas, in parentheses at the end of the declaration. These values must be represented by constant expressions.

It is often useful to declare typed constants as well, which you can do without repeating the values, eg:

const
  FOLDERID_LocalAppData = '{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}';
  FOLDERID_RoamingAppData = '{3EB685DB-65F9-4CF6-A03A-E3EF65729F3D}';
  FOLDERID_Documents = '{FDD39AD0-238F-46AF-ADB4-6C85480369C7}';
  {...}

  FOLDERID_LocalAppData_GUID: TGUID = FOLDERID_LocalAppData;
  FOLDERID_RoamingAppData_GUID: TGUID = FOLDERID_RoamingAppData;
  FOLDERID_Documents_GUID: TGUID = FOLDERID_Documents;
  {...}

  settings_roots: array[0..2] of TGuid = (
    FOLDERID_LocalAppData, FOLDERID_RoamingAppData, FOLDERID_Documents
  );

Alternatively, so the TGuid typed constants can match the Win32 API naming scheme:

const
  FOLDERID_LocalAppData_STR = '{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}';
  FOLDERID_RoamingAppData_STR = '{3EB685DB-65F9-4CF6-A03A-E3EF65729F3D}';
  FOLDERID_Documents_STR = '{FDD39AD0-238F-46AF-ADB4-6C85480369C7}';
  {...}

  FOLDERID_LocalAppData: TGUID = FOLDERID_LocalAppData_STR;
  FOLDERID_RoamingAppData: TGUID = FOLDERID_RoamingAppData_STR;
  FOLDERID_Documents: TGUID = FOLDERID_Documents_STR;
  {...}

  settings_roots: array[0..2] of TGuid = (
    FOLDERID_LocalAppData_STR, FOLDERID_RoamingAppData_STR, FOLDERID_Documents_STR
  );
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
-1

Sadly the answer appears to be no. You an do the following

const
  FOLDERID_LocalAppData   : TGUID = '{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}';
  FOLDERID_RoamingAppData : TGUID = '{3EB685DB-65F9-4CF6-A03A-E3EF65729F3D}';
  FOLDERID_Documents      : TGUID = '{FDD39AD0-238F-46AF-ADB4-6C85480369C7}';

  const
  settings_roots: array[0..2] of ^TGuid = (
    @FOLDERID_LocalAppData, @FOLDERID_RoamingAppData, @FOLDERID_Documents
  );

but then you would need to assign like this

  iGUID := settings_roots[ i ]^;

Not sure if that is acceptable. You could put a class wrapper around it if you wish.

Dsm
  • 5,870
  • 20
  • 24