TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: Peter2 on August 07, 2013, 06:48:58 AM

Title: Innosetup: Looping through all versions and verticals and languages ...
Post by: Peter2 on August 07, 2013, 06:48:58 AM
I saw some Innosetup postings here, maybe somebody can help...

Using Innosetup I (want to) query the registry to find the installed versions of AutoCAD. The problem (for me, not for a Pascal expert) is the great number of possible versions:

- a lot of basic version (e.g. 2007 - 2014)
- a lot of languages
- a lot of verticals ....

Who has the perfect idea (better: the perfect solution :-D) handle this complexity ?

a) IS searches and displays all installed versions
b) User selects the versions he needs (IS Components?)
c-1) IS installs to all existing languages of all selected components..
c-2) IS installs to all selected  languages of all selected components.. (Maybe a little bit crazy idea and not necessary ..)

Thanks and regards
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: huiz on August 07, 2013, 10:11:55 AM
What do you want to install? If you have your own application you can install it in the plugin directory. In your package xml you can do the stuff for the different versions.

This will only work from 2012 versions I guess. I don't know much about Pascal, I've spent a few hours searching for this too, but finally I gave up and wrote my own registry tool (exe) which can be start by IS. In that tool I do a search for the installed versions and create new registry keys.

That I only use for the BricsCAD software, for AutoCAD I moved to the plugin system.

Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: Peter2 on August 07, 2013, 10:26:26 AM
What do you want to install? ...
Actually one VLX, compiled from Lisp.
But I use also OpenDCL and Doslib and LspLoader, and this is why I'm experimenting with "Loader" and "LoadCTRLS", which are placed in

"HKCU\Software\Autodesk\AutoCAD\R19.1\ACAD-D001:407\Applications\MyAPP"

where all red entries can be different.

...If you have your own application you can install it in the plugin directory. ....
Where? What? How?
As said above I'm try to use the autoload-feature via LOADER.

...In your package xml you can do the stuff for the different versions. This will only work from 2012 versions I guess. .....
Right. But I have to consider it also for (at least) 2011.

.......and wrote my own registry tool (exe) which can be start by IS. In that tool I do a search for the installed versions and create new registry keys.....
I hoped to avoid this.
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: Lee Mac on August 07, 2013, 10:42:02 AM
"HKCU\Software\Autodesk\AutoCAD\R19.1\ACAD-D001:407\Applications\MyAPP"

where all red entries can be different.

The red entries can be determined using the vlax-product-key function.
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: Peter2 on August 07, 2013, 10:54:10 AM
...The red entries can be determined using the vlax-product-key function.
Inside the installation with Innosetup?
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: owenwengerd on August 07, 2013, 11:00:14 AM
In my opinion, the best solution is to simply iterate every supported version of AutoCAD and automatically install your autoload key in every flavor and language of those supported versions. I have written UI for selecting specific instances to install to, but it's very complicated and almost never useful (95% of end users have only one installed version of AutoCAD, and 99% of the remaining users want the app on all of their installations.)
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: Peter2 on August 07, 2013, 11:03:22 AM
... to simply iterate every supported version of AutoCAD and automatically install your autoload key in every flavor and language of those supported versions. ...
Do you have an example for this iteration in Pascal / Innosetup?
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: owenwengerd on August 07, 2013, 11:19:49 AM
Do you have an example for this iteration in Pascal / Innosetup?

No, sorry. I'm somewhat familiar with InnoSetup, but I've never used it myself.
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: BlackBox on August 07, 2013, 03:55:59 PM
"HKCU\Software\Autodesk\AutoCAD\R19.1\ACAD-D001:407\Applications\MyAPP"

where all red entries can be different.

The red entries can be determined using the vlax-product-key function.

As I understand it, newer products (2013+) use vlax-User-Product-Key... More info at the bottom of this post (http://www.theswamp.org/index.php?topic=42257.msg474024#msg474024).

Accessing the product key was changed in .NET API as well, as shown here (http://forums.autodesk.com/t5/NET/productkey-replacement-in-dot-net-4/td-p/3532628).

Cheers
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: Lee Mac on August 07, 2013, 04:51:15 PM
Thanks for the info BB, I need to get with the times  :-)
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: dgorsman on August 07, 2013, 05:20:16 PM
Stupid question time: is this installation set-up intended for internal distribution (ie. known application targets) or external distribution (ie. sharing with the world)?
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: Peter2 on August 07, 2013, 05:36:27 PM
Stupid question time: is this installation set-up intended for internal distribution (ie. known application targets) or external distribution (ie. sharing with the world)?
No, no - stupid questions are my speciality  :-D

At first step, I know the testers and their configs, but later on, I hope the entire world (or a part of it) will use it.
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: irneb on August 08, 2013, 01:46:58 AM
There's quite a few examples of doing this on StackOverflow. IMO Pascal's not a hard language to understand, it's just a lot more verbose than Lisp. Actually I found it a lot easier to understand than C/C++ (about similar to VB/C#).

Some differences from Pascal over Lisp: All local variables has to be declared between the header and the body of the function in a var section, you also need to specify the type (as this is a static typed language). It is possible to send arguments by reference in Pascal, simialr like quoting an argument in Lisp - only in Pascal you define the function that way instead of modifying the call statement.

Here's a few samples after doing a google:
The official InnoSetup's Pascal Script does have help on the functions which might be of use. Scroll down to the Registry Functions section on this page: http://www.jrsoftware.org/ishelp/index.php?topic=scriptfunctions


You might find the RegGetSubkeyNames (http://www.jrsoftware.org/ishelp/index.php?topic=isxfunc_reggetsubkeynames) function of use. Note the use of the var prefix for the Names argument. That means it's a by-reference argument. So your function needs to have a local variable of type TArrayOfString and add this is the argument in that position. If the RegGetSubkeyNames returns true then your local variable will contain the names.


So the principle is this: You'll look for subkeys under HKLU\Software\Autodesk\AutoCAD\. That would list all installed versions. Under each of those, there might be subkeys as well (e.g. Vanilla / C3D / Mech / ACA / etc. all have their own codes in here). Then under the Profiles of that folder, you might have several profiles which the user might have saved. Thus you'd probably have to do a nested iteration for the different levels.
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: irneb on August 08, 2013, 02:07:16 AM
Another alternative way of going about it through IS's built-in Pascal Script would be to use IS in conjunction with AcadInst. Here's a good tut on how to use them: http://www.afralisp.net/archive/lisp/install1.htm

Just note, the free version of AcadInst forces you to use their built-in dialogs, it's like an add-ware app. If you pay for it you can get rid of these.
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: Peter2 on August 08, 2013, 01:43:46 PM
...Just note, the free version of AcadInst forces you to use their built-in dialogs, it's like an add-ware app. If you pay for it you can get rid of these.
Hi irneb

which version of AcadInstall are you talking about? Byron has suspended his development (I have some products of Cadwerx), and the version which can be found in the web is rather old. And I don't know a current version to purchase. And the Afra-Lisp site talks of version 2004.

Peter
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: BlackBox on August 08, 2013, 01:59:36 PM
Thanks for the info BB, I need to get with the times  :-)

Hardly the case, my friend :-D ... More likely a monumental accomplishment for me to know one, albeit unimportant detail.



... Years of geek reading #WorthIt... #DontJudgeMe :beer:
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: irneb on August 13, 2013, 01:29:56 AM
Hi irneb

which version of AcadInstall are you talking about? Byron has suspended his development (I have some products of Cadwerx), and the version which can be found in the web is rather old. And I don't know a current version to purchase. And the Afra-Lisp site talks of version 2004.

Peter
Sorry, that's something I used very long ago. Didn't realize it was suspended  :oops:. So ignore my previous post.

I think for an installer, your most comprehensive bet would be to use the Pascal Script to modify registry as you originally intended. Note the vlax-*-product-key is a Lisp function - for it to run you needed to have ACad already open with your LSP loaded (not usually the case when you install your addon).

And as Huiz has explained since 2012 there's a plugin folder which is the official plugin install folder. Though you still might need to edit registry is something special is needed.

Edit: You might even be able to get what you're after using the bundle idea: http://through-the-interface.typepad.com/through_the_interface/2011/09/autodesk-exchange-preparing-your-autocad-application-for-posting.html
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: BlackBox on August 13, 2013, 02:14:53 AM
FWIW - I'm doing a lot of Autoloader .bundles these days, and would be happy to help.

Cheers
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: DanW on August 13, 2013, 07:22:16 AM
... to simply iterate every supported version of AutoCAD and automatically install your autoload key in every flavor and language of those supported versions. ...
Do you have an example for this iteration in Pascal / Innosetup?

Hi Peter,

In my opinion - Owen's LspLoad is a far more elegant and flexible solution than AcadInstall (even before it was depreciated).

Below is a Innosetup/Pascal code example of how to loop through AutoCAD versions and create the relevant LspLoad registry entries for an imaginary application called "MyCADApp".  It is purely to demonstrate the mechanism.  It is stripped down to just do 64bit ACAD on 64bit Windows to demonstrate the principle. 

Once you've got a handle on the pascal scripting, it should be relatively straight forward to modify/expand it to add tests for 32bit CAD on 64bit Windows and 32bit CAD on 32bit Windows and of course do similar for Bricscad.  All the additional functions you may require eg "IsWin64" can be found in the "Support Function Reference" in the Innosetup Help files.


Code: [Select]
procedure AddACADRegKey (Release: String); {eg 'R19.0 for ACAD 2013'}
var
  RunTimeNum: String; {eg '19'}
  AllProductID: TArrayOfString;
  ProductID: String; {eg 'ACAD-9001:409'}
  KeyPathShort: String;{eg 'SOFTWARE\Autodesk\AutoCAD\'}
  KeyPathLong: String; {eg 'SOFTWARE\Autodesk\AutoCAD\R18.1\ACAD-9001:409\Applications\MyCADApp'}
  KeyStringShort: String; {eg c:\Program Files\MyCADApp\LspLoad.'}
  KeyStringLong: String; {eg 'c:\Program Files\MyCADApp\LspLoad.19.x64.arx'}   
  I: Integer;
begin
  RunTimeNum := Copy (Release, 2, 2);
  KeyStringShort := ExpandConstant('{pf}\MyCADApp\LspLoad.');
  KeyPathShort := 'SOFTWARE\Autodesk\AutoCAD\';
  if RegGetSubkeyNames(HKLM64, KeyPathShort + Release, AllProductID)
    then begin
      for I := 1 to GetArrayLength(AllProductID) do begin
        ProductID := AllProductID[I-1];
        KeyPathLong := KeyPathShort + Release + '\' + ProductID + '\Applications\MyCADApp';
        KeyStringLong := KeyStringShort + RunTimeNum + '.x64.arx';
        RegWriteDWordValue (HKLM64, KeyPathLong,'LOADCTRLS', 2);
        RegWriteStringValue (HKLM64, KeyPathLong,'LOADER',KeyStringLong);
      end;
    end;
end;

An example of its useage - to test for ACAD 2012 and ACAD 2013 and add the registry entries triggered by an end installation event you would add the following code:

Code: [Select]
procedure CurStepChanged(CurStep: TSetupStep);
begin
  if CurStep=ssPostInstall
    then begin
        AddAcadRegKey ('R18.2');{ACAD 2012}
        AddAcadRegKey ('R19.0');{ACAD 2013}
   end;
end;

I think you will find that its time well spent getting a handle on this.  Good luck with it.
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: BlackBox on August 13, 2013, 09:56:51 AM
I cannot speak for BricsCAD, but regarding Autodesk-based products, Autoloader is really quite simple... Using the "MyCADApp" example noted above (for comparison), here's all that is needed to load the proper ObjectARX assembly (R18/R19, 32/64-Bit) into the appropriate product (as supported by Autoloader)...



PackageContents.xml:

Code - XML: [Select]
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <ApplicationPackage AppVersion="1.0.0" Author="YourNameHere" Description="MyCADApp for AutoCAD®"        HelpFile="./Contents/Resources/MyCADAppHelp.chm" Name="MyCADApp for AutoCAD®" ProductCode="{2EA4A60C-362E-4801-B930-DEA74C82669E}" ProductType="Application" SchemaVersion="1.0" UpgradeCode="{6CCFC2A5-2268-404d-9616-26D5DAF495F6}"   >
  3.         <CompanyDetails Email="YourNameHere@SomePlace.com" Name="YourNameHere" Phone="911-123-4567 " Url="https://www.SomePlace.com" />
  4.         <Components>
  5.                 <RuntimeRequirements OS="Win32|Win64" Platform="AutoCAD|Civil3D|Map|AIS|ADT|ACADM|MEP|ACADE|PNID|Plant3D|Civil|LDT" SeriesMin="R18.2" SeriesMax="R18.2" />       
  6.                 <ComponentEntry AppName="MyCADApp for AutoCAD®" AppDescription="MyCADApp for AutoCAD® does a bunch of useful stuff." ModuleNameWin32="./Contents/Windows/2010/MyCADApp18.arx" ModuleNameWin64="./Contents/Windows/2010/MyCADApp18x64.arx" Version="1.0.0" />                   
  7.         </Components>
  8.         <Components>
  9.                 <RuntimeRequirements OS="Win32|Win64" Platform="AutoCAD*" SeriesMin="R19.0" SeriesMax="R19.2" />         
  10.                 <ComponentEntry AppName="MyCADApp for AutoCAD®" AppDescription="MyCADApp for AutoCAD® does a bunch of useful stuff." ModuleNameWin32="./Contents/Windows/2013/MyCADApp19.arx" ModuleNameWin64="./Contents/Windows/2013/MyCADApp19x64.arx" Version="1.0.0" />   
  11.         </Components>
  12. </ApplicationPackage>
  13.  



Attached is a pseudo-code Autoloader .bundle where you could replace the MyCADApp*.arx files (which are really just empty text files with an .arx extension) with your code as needed... Again, this is for demonstration purposes only, and will not actually load... Once you have modified both the .bundle, and its contents to go 'live' simply move to the following directory:

Code - Text: [Select]
  1. %AppData%\Autodesk\ApplicationPlugins\SomePlace-MyCADApp.bundle


... No registry calls to install for each-and-every-single product, just drop it in the folder... And when you don't want it anymore, simple rename the .bundle (i.e., SomePlace-MyCADApp.bundle.void, etc.), or delete it. Lemon squeezy.

Cheers
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: BlackBox on August 13, 2013, 10:04:19 AM
... Might be useful if I included a link to the Autoloader White Paper (http://adndevblog.typepad.com/autocad/2013/01/autodesk-autoloader-white-paper.html) :thumbsup:
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: Peter2 on August 13, 2013, 06:12:14 PM
@BlackBox:
Autoloader is fine, but I have to serve also version beneath 2012 - so Autoloader can not serve these old versions.

@DanW:
Thanks for the code. The problem is multiplied with languages and versions. So maybe this pseudo-code would help (pseudo-code because my Pascal-knowledge is too low for real code).

Code: [Select]
// define what should be supported

myversions := array ("18.0" "18. 1" "18.2" "19.0")
mylanguages := array ("401" "407" "410" "804")
myproducts := array ("9000" "9001" "A000" "A001" "A007")

// combine all arrays and test what exists in registry
foreach value "myversions"
    do all entries
        foreach value "mylanguages"
            do all entries
                foreach value "myproducts"
                    do all entries
                       KeyToCheck := HKLM + versionValue + languageValue + productValue
                      Ifexist KeyToCeck
                          then
                             write something to registry
I think this would handle all supported (= defined) software which exists.
Any ideas to handle it in Pascal?
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: BlackBox on August 13, 2013, 06:31:21 PM
@BlackBox:
Autoloader is fine, but I have to serve also version beneath 2012 - so Autoloader can not serve these old versions.

Understandable... I too suffer this at my work... For those unsupported versions I simply NETLOAD the appropriate assembly from the network via Acad.lsp file (one for each product), with LoadFromRemoteSources enabled within Acad.Exe.Config file as Kean demonstrates here (http://through-the-interface.typepad.com/through_the_interface/2011/07/loading-blocked-and-network-hosted-assemblies-with-net-4.html).

Good luck!
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: irneb on August 14, 2013, 03:29:24 AM
The problem is multiplied with languages and versions. So maybe this pseudo-code would help (pseudo-code because my Pascal-knowledge is too low for real code).
First, there are many ways of going about this.

Second, I'd avoid going with normal arrays in Pascal. They need to be declared as static (i.e. you need to state their sizes beforehand), even FreePascal's dynamic arrays need to be adjusted using SetLength (don't know if PascalScript even has this), so any modifications later would mean you'd need to change at least 2 pieces of code. Next you either need to save the array lengths somewhere, or use the Low & High functions to get the start and end indexes.

I'd rather go with a built-in collection of strings, something like TStringList (http://www.jrsoftware.org/ishelp/index.php?topic=scriptclasses&anchor=TStringList). Because it allows to simply add to it, it's always a 0 based index, and it contains a Count property.

Then to initialize the variables you'd need something much more verbose than you're used to:
Code - Pascal: [Select]
  1. { Define what should be supported }
  2. var myVersions  : TStringList;
  3.     myLanguages : TStringList;
  4.     myProducts  : TStringList;
  5.  
  6. { Procedure called by InnoSetup when it starts }
  7. procedure InitializeWizard();
  8. begin
  9.     { Initialize the values of supported versions }
  10.     myVersions := TStringList.Create; // Make a new TStringList object reference
  11.     myVersions.Add('18.0'); // Add a string into the StringList object
  12.     myVersions.Add('18.1');
  13.     myVersions.Add('18.2');
  14.     myVersions.Add('19.0');
  15.     myLanguages := myLanguages.Create;
  16.     myLanguages.Add('401');
  17.     myLanguages.Add('407');
  18.     myLanguages.Add('410');
  19.     myLanguages.Add('804');
  20.     myProducts := myProducts.Create;
  21.     myProducts.Add('9000');
  22.     myProducts.Add('9001');
  23.     myProducts.Add('A000');
  24.     myProducts.Add('A001');
  25.     myProducts.Add('A007');
  26. end;
  27.  
  28. { Procedure called by InnoSetup when it's closing }
  29. procedure DeinitializeSetup();
  30. begin
  31.     myVersions.Free;
  32.     myLanguages.Free;
  33.     myProducts.Free;
  34. end;
Notice that the object is instantiated through the Create constructor. But this means that you need to release it using the Free destructor. The procedures I've used are standard names called by InnoSetup at specific points during the installer's run, others can be found here: http://www.jrsoftware.org/ishelp/index.php?topic=scriptevents

Next, you'd need to step through those in a similar idea as DanW's code.
Code - Pascal: [Select]
  1. procedure AddRegistry();
  2. var v, l, p, root : Integer;
  3.     path1, path2 : String;
  4. begin
  5.     if IsWin64 then root := HKLM64
  6.     else root := HKLM32;
  7.     path1 := 'SOFTWARE\Autodesk\AutoCAD\';
  8.     path2 := '\Applications\MyCADApp\';
  9.     for v := 0 to (myVersions.Count - 1) do
  10.         if RegKeyExists(root, path1 + myVersions[v]) then
  11.             for l := 0 to (myLanguages.Count - 1) do
  12.                 for p := 0 to (myProducts.Count - 1) do
  13.                     if RegKeyExists(root, path1 + myVersions[v] + '\ACAD-' + myProducts[p] + ':' + myLanguages[l]) then begin
  14.                         RegWriteStringValue(root, path1 + myVersions[v] + '\ACAD-' + myProducts[p] + ':' + myLanguages[l] + path2,
  15.                                             'InstallPath', ExpandConstant('{app}');
  16.                     end;
  17. end;

Simpler Alternative
Rather than save all versions to arrays / collections and then step through all that. do the same principle as DanW's code:
Code - Pascal: [Select]
  1. procedure AddACADRegKey (const Version, Language, Product : String);
  2. var root : Integer;
  3.     path1, path2 : String;
  4. begin
  5.     if IsWin64 then root := HKLM64
  6.     else root := HKLM32;
  7.     path1 := 'SOFTWARE\Autodesk\AutoCAD\';
  8.     path2 := '\Applications\MyCADApp\';
  9.     if RegKeyExists(root, path1 + Version + '\ACAD-' + Product + ':' + Language) then begin
  10.         RegWriteStringValue(root, path1 + Version + '\ACAD-' + Product + ':' + Language + path2,
  11.                             'InstallPath', ExpandConstant('{app}');
  12.     end;
  13. end;
  14.  
  15. procedure CurStepChanged(CurStep: TSetupStep);
  16. begin
  17.   if CurStep=ssPostInstall
  18.     then begin
  19.         AddAcadRegKey ('R18.2', '401', '9000');
  20.         AddAcadRegKey ('R19.0', '804', 'A000');
  21.    end;
  22. end;

No Code Alternative
You could simply add these things into your Registry section and have a Check parameter for each. E.g.
Code: [Select]
[Registry]
Root: HKLM; Subkey: "SOFTWARE\Autodesk\AutoCAD\18.0\ACAD-A000:401\Applications\MyCADApp\"; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}"; Flags: uninsdeletekey; Check: RegKeyExists(HKLM, 'SOFTWARE\Autodesk\AutoCAD\18.0\ACAD-A000:401')
Root: HKLM; Subkey: "SOFTWARE\Autodesk\AutoCAD\18.1\ACAD-9000:407\Applications\MyCADApp\"; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}"; Flags: uninsdeletekey; Check: RegKeyExists(HKLM, 'SOFTWARE\Autodesk\AutoCAD\18.1\ACAD-9000:407')
Root: HKLM; Subkey: "SOFTWARE\Autodesk\AutoCAD\19.0\ACAD-A007:804\Applications\MyCADApp\"; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}"; Flags: uninsdeletekey; Check: RegKeyExists(HKLM, 'SOFTWARE\Autodesk\AutoCAD\19.0\ACAD-A007:804')
No need to "code", just call the built-in function. Though now you add the registry path twice. And you might need to do something for the 32/64 bit issue.
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: DanW on August 14, 2013, 04:54:45 AM
Hi Irneb,

Fantastic tutorial! Taught me a lot.  Many thanks for posting.
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: Peter2 on August 14, 2013, 04:59:35 AM
:-D :-D :-D
Wonderful, thanks. I think this should be added to the IS Knowledge base (ISXKB ..??)

Quote
Notice that the object is instantiated through the Create constructor. But this means that you need to release it using the Free destructor.
:-o
I hope I don't need to understand it?
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: irneb on August 14, 2013, 05:16:24 AM
I hope I don't need to understand it?
Nope, you need not "understand" it, just remember to do it (otherwise you end up with memory leaks).

It's just that Pascal is not using a garbage collector like Lisp/C# does. In that way it's much more like C/C++ (Pascal & C share a common ancestor - Algol (http://en.wikipedia.org/wiki/ALGOL_W), actually Pascal is closer to Algol than C is). That means that any variable allocated in RAM needs to be released explicitly, most normal variables (i.e. strings, integers, reals) are handled direct by the compiler which adds the allocation & release for you. But when it comes to special data types, the compiler doesn't "know" what to do, thus you need to both make and clear them yourself. This is where GC makes life a lot easier and safer (as you need not worry about these things causing memory leaks), but using explicit memory management means your program needs much less RAM (usually around 1/5th to get the same speed of execution).

Hi Irneb,

Fantastic tutorial! Taught me a lot.  Many thanks for posting.
Glad to. I had to try and remember some of the basics as I originally learned Borland TurboPascal in 1993. Have used variants of Pascal (Delphi & Lazarus) over the years, but it certainly isn't the language I use constantly. I haven't done much using Pascal Script, but the language is quite standard across the board - only need to search documentation (which isn't as comprehensive for PS as for other Pascals).
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: irneb on August 14, 2013, 05:24:13 AM
BTW, anyone noticed the errors in my code? Hint, it's usually associated with Lisp  :wink:
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: DW on August 18, 2013, 10:36:48 PM
Autoloader is fine, but I have to serve also version beneath 2012 - so Autoloader can not serve these old versions.

Thought I'd share the bones of an approach I use with Inno Setup and Owen's fantastic LspLoad functions for setting up with all versions of AutoCAD and BricsCAD.  This takes a relatively simple approach by querying the last used AutoCAD version (assuming there are multiple versions installed) and setting up for that. 

The Inno Setup script below assumes packaging all the LspLoad.* files for each platform and version together and a single .lsp file 'Myapp.Lsp'  which might do something like this:

Code - Auto/Visual Lisp: [Select]
  1. (defun c:testapp()
  2. (alert (strcat "Path to Application: "(GetPathOfMyApp)));see readme for LspLoad about included function GetPathOf.....
  3. )
  4.  
  5. (princ "LspLoad App Loaded\nCommand \"TestApp\" defined")


Code below is an Inno Setup file (.iss)

Code: [Select]
;
; Demonstrates setup of demand loading code for LspLoad application - thanks to Owen Wengerd
; Download LspLoad.zip from: http://www.manusoft.com/software/freebies/arx.html
; Download Inno Setup: http://www.jrsoftware.org/isinfo.php/
;

[Setup]
AppName=MyApp
AppVersion=1.0
VersionInfoVersion=1.0
DefaultDirName={pf}\MyApp
DefaultGroupName=MyApp
DisableProgramGroupPage=true
AlwaysUsePersonalGroup=true
PrivilegesRequired=none
ArchitecturesInstallIn64BitMode=x64

WindowShowCaption=true

Uninstallable=yes

[Messages]
DiskSpaceMBLabel=The program requires at least [kb] KB of disk space.

[Dirs]
Name: {app}; Permissions: users-modify

[Files]
Source: MyApp.lsp; DestDir: {app}; Flags: touch

;; include OpenDCL runtime for your app if required
;; Source: OpenDCL.Runtime.7.0.0.13.msi; DestDir: {app}; Flags: ignoreversion

;; LspLoad file is renamed when copied to the installation directory to match the application name
;; Boolean functions GetVer and Is64Bit check appropriate file to install for the installation

Source: LspLoad.9.brx; DestDir: {app}; DestName: MyApp.9.brx; Check: GetVer(9)
Source: LspLoad.10.brx; DestDir: {app}; DestName: MyApp.10.brx; Check: GetVer(10)
Source: LspLoad.11.brx; DestDir: {app}; DestName: MyApp.11.brx; Check: GetVer(11)
Source: LspLoad.12.brx; DestDir: {app}; DestName: MyApp.12.brx; Check: GetVer(12)
Source: LspLoad.15.arx; DestDir: {app}; DestName: MyApp.15.arx; Check: GetVer(15)
Source: LspLoad.16.arx; DestDir: {app}; DestName: MyApp.16.arx; Check: GetVer(16)
Source: LspLoad.17.arx; DestDir: {app}; DestName: MyApp.17.arx; Check: not Is64Bit and GetVer(17)
Source: LspLoad.17.x64.arx; DestDir: {app}; DestName: MyApp.17.x64.arx; Check: Is64Bit and GetVer(17)
Source: LspLoad.18.arx; DestDir: {app}; DestName: MyApp.18.arx; Check: not Is64Bit and GetVer(18)
Source: LspLoad.18.x64.arx; DestDir: {app}; DestName: MyApp.18.x64.arx; Check: Is64Bit and GetVer(18)
Source: LspLoad.19.arx; DestDir: {app}; DestName: MyApp.19.arx; Check: not Is64Bit and GetVer(19)
Source: LspLoad.19.x64.arx; DestDir: {app}; DestName: MyApp.19.x64.arx; Check: Is64Bit and GetVer(19)

[Icons]
Name: {group}\Uninstall MyApp; Filename: {uninstallexe}; WorkingDir: {app};

[INI]

[InstallDelete]

[Registry]
;; Include path of installation in registry if required
;; Root: HKCU; Subkey: Software\MyAppCo\MyApp; ValueType: string; ValueName: InstallPath; ValueData: {app}; Flags: uninsdeletekey;

;; Insert demand loader entry for LspLoad.xx.arx
;; GetFilenm function retreives file name string
;; GetAcadAppReg gets registry path for HKCU 

;; For HKLM (all users) you will need to Create a page in the setup wizard to select setup option -
;; either everyone or current user and create a function similar to GetAcadAppReg 

;; Set LoadCtrls key to 12 for demand loading using command specified in Commands key (TestMyApp)
;; Set LoadCtrls key to 2 for load at AutoCAD startup

Root: HKCU; Subkey: {code:GetAcadAppReg}\Applications\MyApp; ValueType: string; ValueName: Description; ValueData: MyApp; Flags: uninsdeletekey;
Root: HKCU; Subkey: {code:GetAcadAppReg}\Applications\MyApp; ValueType: dword; ValueName: LoadCtrls; ValueData: 12; Flags: uninsdeletekey;
Root: HKCU; Subkey: {code:GetAcadAppReg}\Applications\MyApp; ValueType: string; ValueName: Loader; ValueData: {app}\{code:GetFilenm}; Flags: uninsdeletekey;
Root: HKCU; Subkey: {code:GetAcadAppReg}\Applications\MyApp\Commands; ValueType: string; ValueName: MyApp; ValueData: TestMyApp;

;;include OpenDCL runtime for your app if required
[Run]
;; Filename: msiexec.exe; Parameters: "/i ""{app}\OpenDCL.Runtime.7.0.0.13.msi"""

[UninstallRun]
;; Filename: msiexec.exe; Parameters: "/x ""{app}\OpenDCL.Runtime.7.0.0.13.msi"""

[Code]
// The following InitializeSetup function is a basic check for installation of AutoCAD or Bricscad.
// It doesn't allow for a choice if there are multiple installations on the same system and hasn't been tested extensively 
// so may not work for products other than vanilla AutoCAD

var
App, Version, Product, Ver, Wow, AcadLocn: String;
       
function InitializeSetup (): Boolean;
  begin //check for apps including AutoCAD, AutoCAD LT, Bricscad
     if RegKeyExists(HKEY_CLASSES_ROOT, 'AutoCAD.Application') or RegKeyExists(HKEY_CLASSES_ROOT, 'AutoCADLT.Drawing') then
       begin
          RegQueryStringValue(HKEY_CLASSES_ROOT, 'AutoCAD.Application\CurVer','', Version)
          if (Version = '') or RegKeyExists(HKEY_CLASSES_ROOT, 'AutoCADLT.Drawing\CurVer') then
             begin
               if RegValueExists(HKEY_CURRENT_USER, 'Software\Autodesk\AutoCAD LT','CurVer') then
               MsgBox('AutoCAD LT is not supported, exiting install...', mbInformation, MB_OK) else
               MsgBox('Can''t locate AutoCAD or Bricscad on this system, exiting install...', mbInformation, MB_OK)
               Result := False;
             end
             else
                if Version = 'BricscadApp.AcadApplication' then
                   begin     
                      App := 'Bricscad'
                      RegQueryStringValue(HKEY_CURRENT_USER, 'Software\Bricsys\Bricscad','CURVER', Version)//Reassign variable Version
                      RegQueryStringValue(HKEY_CURRENT_USER, ('Software\Bricsys\Bricscad\' + Version),'CURVER', Product)//Assign the variable Product
                      RegQueryStringValue(HKEY_LOCAL_MACHINE, ('Software\Bricsys\Bricscad\' + Version + '\' + Product),'AcadLocation', AcadLocn)//AcadLocn
                      Wow := '0' //Flag
                      Ver := Version
                      Delete (Ver, 1, 1)//remove leading V
                      Result := True;
                   end
                   else
                     if Version = 'AutoCAD.Drawing.15' then
                        begin
                           App := 'AutoCAD'
                           RegQueryStringValue(HKEY_LOCAL_MACHINE, 'Software\Autodesk\AutoCAD','CurVer', Version)
                           RegQueryStringValue(HKEY_LOCAL_MACHINE, ('Software\Autodesk\AutoCAD\' + Version),'CurVer', Product)
                           //Create a registry string as global 'Wow' to check later
                           if RegValueExists(HKEY_LOCAL_MACHINE, ('Software\Autodesk\AutoCAD\' + Version + '\' + Product), 'AcadLocation') then
                                    begin
                                      RegQueryStringValue(HKEY_LOCAL_MACHINE, ('SOFTWARE\Autodesk\AutoCAD\' + Version + '\' + Product),'AcadLocation', AcadLocn)
                                      Wow := '0'
                                    end
                                    else
                                      if RegValueExists(HKEY_LOCAL_MACHINE, ('SOFTWARE\Wow6432Node\Autodesk\AutoCAD\' + Version + '\' + Product), 'AcadLocation') then
                                        begin
                                           RegQueryStringValue(HKEY_LOCAL_MACHINE, ('SOFTWARE\Wow6432Node\Autodesk\AutoCAD\' + Version + '\' + Product),'AcadLocation', AcadLocn)
                                           Wow := '1'
                                        end
                           Ver := Version //create global
                           Delete (Ver, 4, 2)//remove trailing period and integer
                           Delete (Ver, 1, 1)//remove leading R
                           Result := True;
                        end
                        else             
                           if RegValueExists(HKEY_CURRENT_USER, 'Software\Autodesk\AutoCAD','CurVer') then
                              begin
                                 App := 'AutoCAD'
                                 RegQueryStringValue(HKEY_CURRENT_USER, 'Software\Autodesk\AutoCAD','CurVer', Version)//get most recent accessed version regardless of installations
                                 RegQueryStringValue(HKEY_CURRENT_USER, ('Software\Autodesk\AutoCAD\' + Version),'CurVer', Product)
                                //Check where registry entries are found to determine whether installation is 32 bit or 64 bit
                                 if RegValueExists(HKEY_LOCAL_MACHINE, ('Software\Autodesk\AutoCAD\' + Version + '\' + Product), 'AcadLocation') then
                                    begin
                                      RegQueryStringValue(HKEY_LOCAL_MACHINE, ('SOFTWARE\Autodesk\AutoCAD\' + Version + '\' + Product),'AcadLocation', AcadLocn)
                                      Wow := '0'
                                    end
                                    else
                                      if RegValueExists(HKEY_LOCAL_MACHINE, ('SOFTWARE\Wow6432Node\Autodesk\AutoCAD\' + Version + '\' + Product), 'AcadLocation') then
                                        begin
                                           RegQueryStringValue(HKEY_LOCAL_MACHINE, ('SOFTWARE\Wow6432Node\Autodesk\AutoCAD\' + Version + '\' + Product),'AcadLocation', AcadLocn)
                                           Wow := '1'
                                        end
                                 Ver := Version //create global
                                 Delete (Ver, 4, 2)//remove trailing period and integer
                                 Delete (Ver, 1, 1)//remove leading R
                                 Result := True; //flag install to continue
                              end
                              else
                                begin
                                   MsgBox('Can''t locate AutoCAD or Bricscad on this system, exiting install...', mbInformation, MB_OK)
                                   Result := False;
                                end
       end
       else
         begin
           MsgBox('Can''t locate AutoCAD or Bricscad on this system, exiting install...', mbInformation, MB_OK)
           Result := False;
         end
  end;


function GetFileNm(FileNm: String): String;
  begin
    if 'AutoCAD' = App then
      begin
        case Ver of
          '15' : FileNm := 'MyApp.15.arx';
          '16' : FileNm := 'MyApp.16.arx';
          //check if the 'Wow' flag is set to '1' if so the installation is a 32bit version on a 64bit OS
          '17' : if Wow = '1' then
                   FileNm := 'MyApp.17.arx' else
                   //installation is under a 64bit or 32bit OS
                   if isWin64 then
                   FileNm := 'MyApp.17.x64.arx' else
                   FileNm := 'MyApp.17.arx';
          '18' : if Wow = '1' then
                   FileNm := 'MyApp.18.arx' else
                   if isWin64 then
                   FileNm := 'MyApp.18.x64.arx' else
                   FileNm := 'MyApp.18.arx';
          '19' :  if Wow = '1' then
                   FileNm := 'MyApp.19.arx' else
                   if isWin64 then
                   FileNm := 'MyApp.19.x64.arx' else
                   FileNm := 'MyApp.19.arx';
        end;
          Result := FileNm
      end
    else
      begin
          //Bricscad ...
          case Ver of
            '12' : FileNm := 'MyApp.12.brx';
            '11' : FileNm := 'MyApp.11.brx';
            '10' : FileNm := 'MyApp.10.brx';
            '9' : FileNm := 'MyApp.9.brx';
          end;
         Result := FileNm
      end
  end;

function GetAcadAppReg (RegPath: String): String;
  begin
    if 'AutoCAD' = App then
      begin
        RegPath := ('Software\Autodesk\AutoCAD\' + Version + '\' + Product)
        Result := RegPath
      end
      else
      begin
        //Must be Bricscad
        RegPath := ('Software\Bricsys\Bricscad\' + Version + '\' + Product)
        Result := RegPath
      end
  end;
 
function GetVer (Param: Integer): Boolean;
  begin
     if Param = StrToInt(Ver) then
        Result := True  else
        Result := False
  end;

function Is64Bit (): Boolean;
   begin
      if Wow = '1' then
         Result := False else
      if isWin64 then
         Result := True else
         Result := False
   end;


Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: irneb on August 19, 2013, 02:00:32 AM
DW, that's quite comprehensive!

BTW, it's sad that Pascal doesn't have a cond statement. Otherwise that bunch of nested ifs could have been a lot simpler. It does have a case statement, but is only allowed for ordinal types (not strings) ... unless it uses FreePascal as its underlying language (they've added string options to the case statement in FP) : http://freepascalanswers.wordpress.com/2013/01/26/language-additions/

Otherwise you could go this route to make yours a bit simpler: http://stackoverflow.com/questions/14515492/using-case-statement-with-string
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: cadplayer on September 14, 2013, 09:22:11 AM
Sorry for my comment, I´m trying to do the old way and inno-setup to build a install-it-self-package of all my programs. I´ve looked in archive.org to can get acadInst.exe, where I need to can install menus, supportpath and profile. Have somebody a idea where I can get it :?

PS.:http://www.cadwerx.net not available!

Found it http://www.freecadapps.com/swdetails.php?value=ACG-MSC&orgvalue=ACG&review=5626&rowcolor=fce08d
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: exmachina on September 14, 2013, 12:00:22 PM
acadInst.exe & AcadInst_x64.exe v1.7.0.48 (cuix files are not supported):
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: exmachina on September 14, 2013, 12:30:04 PM
Inno setup script to do the following:

-Checks whether a particular version (or any version) is installed
-Add support paths (and optionally delete them when uninstalling).
-Add code to acaddoc.lsp (and optionally delete them when uninstalling).

Copy InnoAcInstall.iss to C:\Program Files\Inno Setup and take a look at one of the examples
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: Peter2 on September 14, 2013, 12:36:17 PM
...PS.:http://www.cadwerx.net not available!...
Yes. Regrettably Byron stopped his developments.

...Found it http://www.freecadapps.com/swdetails.php?value=ACG-MSC&orgvalue=ACG&review=5626&rowcolor=fce08d
The problem is that this version is 1.2 from 2002. A lot has changed since then in Acad environment.

acadInst.exe & AcadInst_x64.exe v1.7.0.48 (cuix files are not supported):
Wonderful. Thanks a lot.
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: cadplayer on September 14, 2013, 02:13:50 PM
 :-o oh I not realy understand what I do
Simple question: what should do actually acadinst.exe and .ini. If I compile iss I get this message. I did change shortcut to example "C:\Programme\AutoCAD 2002\AcadInst.exe" "Infrastructure" (that create a new supportpath with named Infrastructure)
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: Peter2 on September 14, 2013, 03:03:17 PM
I don't know the details, but

a) it seems that you use the old version of Acadinstall
b) I believe that the CHM of the new version will give you a lot of info
c) maybe your test command is missing some information: Write "Infrastructure" to which profile of which version? There is also an INI which has to be used by Acadinstall ..
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: exmachina on September 14, 2013, 04:03:48 PM
:-o oh I not realy understand what I do
Simple question: what should do actually acadinst.exe and .ini. If I compile iss I get this message. I did change shortcut to example "C:\Programme\AutoCAD 2002\AcadInst.exe" "Infrastructure" (that create a new supportpath with named Infrastructure)

Example:
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: cadplayer on September 16, 2013, 01:13:18 AM
Jar: can I get newest acadinst.exe or where I can find them?
...I have same message again
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: Peter2 on September 16, 2013, 01:33:20 AM
Jar: can I get newest acadinst.exe or where I can find them?
...I have same message again
Did you take the download from his posting
"Reply #31 on: 14 September 2013, 18:00:22 »"?
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: cadplayer on September 16, 2013, 03:06:33 AM
okay done!

Maybe a nother problem I have, in acadinst.ini are R15 or 16 version. I work with 2013 so it doesn´t run on this version or?
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: Peter2 on September 16, 2013, 10:43:59 AM
...Maybe a nother problem I have, in acadinst.ini are R15 or 16 version. I work with 2013 so it doesn´t run on this version or?
I don't know, but ..

a) The INI from JAR has the line
Versions=R17.0,R17.1,R17.2

Have you modified it for 2013?

b) As already mentioned not all features will work in "modern" versions - e.g. the MNU-features are outdated (or you will find a Workaround)
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: cadplayer on September 17, 2013, 10:17:25 AM
Thanks Peter!
Yes I did as 19.0 version but same result.
When I find out inno-ss compiler I was very happy to can do installpackage very easy and comfortable.
It´s a little difficult to know what should do acadinst-program so I believe I do not use this tool - strange. The second is to go back to my mainproblem install a Autolisp library in diffrent maps an maby modify support searchpath in Autocad so all collegues can easy setup my tools.
I think that is possible to do with iss.
Otherwise thanks again.
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: VVeli on June 16, 2015, 07:49:28 AM
Hi,
there is an example how to find all installed AutoCAD versions at computer.
Just making a new installation package for AutoCAD Add-In with Inno Setup.
Code is not a final version and could have bugs. So use it wisely. =)

Cheers
Veli V.

Code: [Select]
[Icons]
Name: "{group}\AddIn"; Filename: "{code:GetAutoCADExe}\acad.exe"; Parameters: "{code:CheckCivil3DAecBaseDbxExists|{code:GetAutoCADExe}}/p ""AddIn"""; WorkingDir: "{app}"; IconFilename: "{app}\Bp.ico"

type
  AUTOCADINFO = record
    location: AnsiString;
    productname: AnsiString;
    productid: AnsiString;
    serialnumber: AnsiString;
  end;
  AcadInfoArray = array of AUTOCADINFO;

// Global variables
var
  AcadVerNames, AcadVerKeys, AcadExes, AcadProductNames: TArrayOfString;
  AcadInfos: AcadInfoArray;

function GetInstalledAutoCADVersions(): Boolean;
var
  S, V, AcadRegKey, sAcadExeLocation, sProductName, sProductId, sSerialNumber: String;
  RootKey, I, J, iCountAcadExeLocations: Integer;
  AcadVerKeysTemp: TArrayOfString;
  AcadInfo: AUTOCADINFO;
begin
  if IsWin64 then
  begin
    RootKey := HKLM64;
  end
  else
  begin
    RootKey := HKEY_LOCAL_MACHINE;
  end;

  iCountAcadExeLocations := 0; 
  AcadRegKey := 'SOFTWARE\Autodesk\AutoCAD';
  if RegGetSubkeyNames(RootKey, AcadRegKey, AcadVerNames) then
  begin
    S := '';
    for I := 0 to GetArrayLength(AcadVerNames)-1 do
    begin
      //MsgBox(AcadRegKey + '\' + AcadVerNames[I], mbInformation, MB_OK);
      if RegGetSubkeyNames(RootKey, AcadRegKey + '\' + AcadVerNames[I], AcadVerKeysTemp) then
      begin
        for J := 0 to GetArrayLength(AcadVerKeysTemp)-1 do
        begin
          //SOFTWARE\Autodesk\AutoCAD\R17.2\ACAD-7000:409
          //MsgBox(AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J], mbInformation, MB_OK);
          sAcadExeLocation := '';
          if RegQueryStringValue(RootKey, AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J], 'Location', sAcadExeLocation) then
          begin
            SetArrayLength(AcadExes, iCountAcadExeLocations + 1);
            AcadExes[iCountAcadExeLocations] := sAcadExeLocation;
            SetArrayLength(AcadVerKeys, iCountAcadExeLocations + 1);
            AcadVerKeys[iCountAcadExeLocations] := AcadVerKeysTemp[J];
            //S := S + AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeys[J] + ' = ' + AcadExes[I] + #13#10;
            SetArrayLength(AcadProductNames, iCountAcadExeLocations+1);
            AcadProductNames[iCountAcadExeLocations] := GetAutoCADProductName(AcadVerKeysTemp[J]);

            //---- Test of own array ----
            sProductName := '';
            sProductId := '';
            sSerialNumber := '';
            SetArrayLength(AcadInfos, iCountAcadExeLocations + 1);
            AcadInfo.location := sAcadExeLocation;
            if RegQueryStringValue(RootKey, AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J], 'ProductName', sProductName) then
            begin
              AcadInfo.productname := sProductName;
            end;
            if RegQueryStringValue(RootKey, AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J], 'ProductId', sProductId) then
            begin
              AcadInfo.productid := sProductId;
            end;
            if RegQueryStringValue(RootKey, AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J], 'SerialNumber', sSerialNumber) then
            begin
              AcadInfo.serialnumber := sSerialNumber;
            end;
            AcadInfos[iCountAcadExeLocations] := AcadInfo;
            //MsgBox('Location = ' + AcadInfo.location + #13#10 + 'ProductName = ' + AcadInfo.productname + #13#10 + 'ProductId = ' + AcadInfo.productid + #13#10 + 'SerialNumber = ' + AcadInfo.serialnumber + #13#10, mbInformation, MB_OK);
            //---- Test of own array ----

            iCountAcadExeLocations := iCountAcadExeLocations + 1;
          end;
        end;
      end;
    end;
    //MsgBox('Founded AutoCAD registry keys:'#13#10#13#10 + S, mbInformation, MB_OK);
  end;
end;

// Function implementations
function GetAutoCADExe(Param: String): String;
begin
  Result := AcadInfos[SelectAutoCADPage.SelectedValueIndex].location;
end;

procedure InitializeWizard;
var
  iCountAcadProductNames, I: Integer;
  button : TButton;
begin

  // AutoCAD version selection dialog
  SelectAutoCADPage := CreateInputOptionPage(wpWelcome,
    'Choose AutoCAD version', 'Upon which version of AutoCAD do you install addin?',
    'Choose AutoCAD version and click Next.',
    True, False);
  iCountAcadProductNames := GetArrayLength(AcadProductNames);
  for I := 0 to iCountAcadProductNames-1 do
  begin
    //SelectAutoCADPage.Add(AcadProductNames[I]);
    SelectAutoCADPage.Add(AcadInfos[I].productname);
  end;
end;

function InitializeSetup(): Boolean;
begin;
  GetInstalledAutoCADVersions();
  Result := True;
end;

Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: Peter2 on June 16, 2015, 09:24:59 AM
...Code is not a final version and could have bugs. ...
Thanks. We are looking forward at the final version.  ;-)
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: VVeli on August 10, 2015, 04:26:31 AM
Hi,
I have almost finished my installation project with Inno Setup. Setup package is in 32bit mode because it has 32bit dlls to register in Windows environment. Original idea was to detect AutoCAD version and install 3rd addin upon selected version. It also creates AutoCAD profiles and configures them. I don´t know is this a right way to do it but it is a one way. Have a good coding! =)

This is only a part of code because of 20000 characters limit. If someone need rest of it I can put it in .iss file.
Code: [Select]
[Icons]
Name: "{group}\KHK"; Filename: "{code:GetAutoCADExe}\acad.exe"; WorkingDir: "{app}"; IconFilename: "{app}\Bp.ico"; Parameters: "{code:CheckAutoCADStartupParameters}/p ""KHK"""

[Run]
Filename: "{app}\CopyRegKey.bat"; Parameters: """HKEY_CURRENT_USER\{code:GetTemplateProfileRegKey}"""; WorkingDir: "{app}"; Flags: waituntilterminated; StatusMsg: "Kopioi ja luo AutoCAD profiilit..."; AfterInstall: ModifyKHKProfileRegFile
Filename: "{app}\ImportRegKey.bat"; Parameters: "KHK"; WorkingDir: "{app}"; Flags: waituntilterminated; StatusMsg: "Palauttaa ja muokkaa AutoCAD profiileja..."; AfterInstall: ModifyKHKProfile

[Code]
// Global type definitions
type

  AUTOCADINFO = record
    location: AnsiString;
    productname: AnsiString;
    productid: AnsiString;
    serialnumber: AnsiString;
    registrykey: AnsiString;
  end;
  AcadInfoArray = array of AUTOCADINFO;

// Global variables
var
  SelectAutoCADPage: TInputOptionWizardPage;
  AcadInfos: AcadInfoArray;
  RootKey: Integer;

// Function declarations
function GetInstalledAutoCADVersions(): Boolean; forward;
function GetAutoCADProductName(Param: String): String; forward;

// Function implementations
function InitializeSetup(): Boolean;
var
  bRes: Boolean;
begin;
  bRes := False;
  Log('InitializeSetup() called');
  bRes := GetInstalledAutoCADVersions();
  if bRes = False then begin
    MsgBox('Koneelta ei löytynyt asennettua AutoCAD -ohjelmaa.' + #13#10 + 'Asennus lopetetaan.', mbInformation, MB_OK);
  end;
  Result := bRes;
end;

procedure InitializeWizard;
var
  iCountAcadProductNames, I: Integer;
  button : TButton;
begin
  Log('InitializeWizard() called');

  // AutoCAD version selection dialog
  SelectAutoCADPage := CreateInputOptionPage(wpWelcome, 'AutoCAD version valinta', 'Minkä AutoCAD:n päälle ohjelmisto asennetaan?',
    'Valitse AutoCAD versio ja paina Seuraava.', True, False);
  iCountAcadProductNames := GetArrayLength(AcadInfos);
  for I := 0 to iCountAcadProductNames - 1 do
  begin
    SelectAutoCADPage.Add(AcadInfos[I].productname);
  end;

function GetInstalledAutoCADVersions(): Boolean;
var
  S, V, AcadRegKey, sAcadExeLocation, sProductName, sProductId, sSerialNumber, sRegistryKey: String;
  I, J, iCountAcadExeLocations: Integer;
  AcadVerNames, AcadVerKeysTemp: TArrayOfString;
  AcadInfo: AUTOCADINFO;
begin
  if IsWin64 then begin
    RootKey := HKLM64;
  end else begin
    RootKey := HKEY_LOCAL_MACHINE;
  end;

  iCountAcadExeLocations := 0; 
  AcadRegKey := 'SOFTWARE\Autodesk\AutoCAD';
  if RegGetSubkeyNames(RootKey, AcadRegKey, AcadVerNames) then
  begin
    S := '';
    for I := 0 to GetArrayLength(AcadVerNames) - 1 do
    begin
      //MsgBox(AcadRegKey + '\' + AcadVerNames[I], mbInformation, MB_OK);
      if RegGetSubkeyNames(RootKey, AcadRegKey + '\' + AcadVerNames[I], AcadVerKeysTemp) then
      begin
        for J := 0 to GetArrayLength(AcadVerKeysTemp)-1 do
        begin
          //SOFTWARE\Autodesk\AutoCAD\R17.2\ACAD-7000:409
          //MsgBox(AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J], mbInformation, MB_OK);
          sAcadExeLocation := '';
          sRegistryKey := AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J];
          if RegQueryStringValue(RootKey, AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J], 'Location', sAcadExeLocation) then
          begin
            sProductName := '';
            sProductId := '';
            sSerialNumber := '';
            SetArrayLength(AcadInfos, iCountAcadExeLocations + 1);
            AcadInfo.location := sAcadExeLocation;
            if RegQueryStringValue(RootKey, AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J], 'ProductName', sProductName) then begin
              AcadInfo.productname := sProductName;
            end;
            if RegQueryStringValue(RootKey, AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J], 'ProductId', sProductId) then begin
              AcadInfo.productid := sProductId;
            end;
            if RegQueryStringValue(RootKey, AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J], 'SerialNumber', sSerialNumber) then begin
              AcadInfo.serialnumber := sSerialNumber;
            end;
            AcadInfo.registrykey := sRegistryKey;
            AcadInfos[iCountAcadExeLocations] := AcadInfo;
            //MsgBox('Location = ' + AcadInfo.location + #13#10 + 'ProductName = ' + AcadInfo.productname + #13#10 + 'ProductId = ' + AcadInfo.productid + #13#10 + 'SerialNumber = ' + AcadInfo.serialnumber + #13#10, mbInformation, MB_OK);
           
            iCountAcadExeLocations := iCountAcadExeLocations + 1;
          end;
        end;
      end;
    end;
    //MsgBox('Founded AutoCAD registry keys:'#13#10#13#10 + S, mbInformation, MB_OK);
  end;
  if iCountAcadExeLocations > 0 then begin
    Result := True;
  end else begin
    Result := False;
  end;
end;

function GetAutoCADProductName(Param: String): String;
var
  sRet: String;
begin
  // AutoCAD 2012
  if Param = 'ACAD-A000:409' then begin
    sRet := 'Autodesk Civil 3D 2012';
  end else if Param = 'ACAD-A001:409' then begin
    sRet := 'AutoCAD 2012';
  end else if Param = 'ACAD-A002:409' then begin
    sRet := 'Autodesk Map 3D 2012';

  // AutoCAD 2013
  end else if Param = 'ACAD-B000:409' then begin
    sRet := 'Autodesk Civil 3D 2013';
  end else if Param = 'ACAD-B001:409' then begin
    sRet := 'AutoCAD 2013';
  end else if Param = 'ACAD-B002:409' then begin
    sRet := 'Autodesk Map 3D 2013';

  // AutoCAD 2009
  end else if Param = 'ACAD-7000:409' then begin
    sRet := 'Autodesk Civil 3D 2009';
  end else if Param = 'ACAD-7001:409' then begin
    sRet := 'AutoCAD 2009';
  end else if Param = 'ACAD-7002:409' then begin
    sRet := 'Autodesk Map 3D 2009';

  // AutoCAD 2010
  end else if Param = 'ACAD-8000:409' then begin
    sRet := 'Autodesk Civil 3D 2010';
  end else if Param = 'ACAD-8001:409' then begin
    sRet := 'AutoCAD 2010';
  end else if Param = 'ACAD-8002:409' then begin
    sRet := 'Autodesk Map 3D 2010';

  // AutoCAD 2011
  end else if Param = 'ACAD-9000:409' then begin
    sRet := 'Autodesk Civil 3D 2011';
  end else if Param = 'ACAD-9001:409' then begin
    sRet := 'AutoCAD 2011';
  end else if Param = 'ACAD-9002:409' then begin
    sRet := 'Autodesk Map 3D 2011';

  // AutoCAD 2014
  end else if Param = 'ACAD-D000:409' then begin
    sRet := 'Autodesk Civil 3D 2014';
  end else if Param = 'ACAD-D001:409' then begin
    sRet := 'AutoCAD 2014';
  end else if Param = 'ACAD-D002:409' then begin
    sRet := 'Autodesk Map 3D 2014';

  // AutoCAD 2015
  end else if Param = 'ACAD-E000:409' then begin
    sRet := 'Autodesk Civil 3D 2015';
  end else if Param = 'ACAD-E001:409' then begin
    sRet := 'AutoCAD 2015';
  end else if Param = 'ACAD-E002:409' then begin
    sRet := 'Autodesk Map 3D 2015';

  // AutoCAD 2016
  end else if Param = 'ACAD-F000:409' then begin
    sRet := 'Autodesk Civil 3D 2016';
  end else if Param = 'ACAD-F001:409' then begin
    sRet := 'AutoCAD 2016';
  end else if Param = 'ACAD-F002:409' then begin
    sRet := 'Autodesk Map 3D 2016';

  // Something other AutoCAD version
  end else begin
    sRet := 'Tuntematon AutoCAD versio: ' + Param;
  end;
  //MsgBox('GetAutoCADProductName(' + Param + ') = ' + sRet, mbInformation, MB_OK);
  Result := sRet; 
end;

function GetAutoCADExe(Param: String): String;
begin
  Result := AcadInfos[SelectAutoCADPage.SelectedValueIndex].location;
end;

function GetTemplateProfileRegKey(Param: String): String;
var
  prodId, regkey: String;
begin
  prodId := AcadInfos[SelectAutoCADPage.SelectedValueIndex].productid;
  regkey := AcadInfos[SelectAutoCADPage.SelectedValueIndex].registrykey;
  Log('CheckAutoCADStartupParameters prodId: ' + prodId);
  if prodId = 'F000' then begin // Civil 3D 2016
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else if prodId = 'E000' then begin // Civil 3D 2015
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else if prodId = 'D000' then begin // Civil 3D 2014
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else if prodId = 'B000' then begin // Civil 3D 2013
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else if prodId = 'A000' then begin // Civil 3D 2012
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else if prodId = '9000' then begin // Civil 3D 2011
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else if prodId = '8000' then begin // Civil 3D 2010
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else if prodId = '7000' then begin // Civil 3D 2009
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else begin
    Result := regkey + '\Profiles\<<Unnamed Profile>>';
  end;
end;

function CheckAutoCADStartupParameters(Param: String): String;
var
  prodId, path: String;
begin
  prodId := AcadInfos[SelectAutoCADPage.SelectedValueIndex].productid;
  path := AcadInfos[SelectAutoCADPage.SelectedValueIndex].location;
  Log('CheckAutoCADStartupParameters prodId: ' + prodId);
  Log('CheckAutoCADStartupParameters location: ' + path);
  if prodId = 'F000' then begin // Civil 3D 2016
    Result := '/ld "' + path + '\AecBase.dbx" /product "C3D" ';
  end else if prodId = 'F002' then begin // Map 3D 2016
    Result := '/product MAP /language "en-US" ';
  end else if prodId = 'E000' then begin // Civil 3D 2015
    Result := '/ld "' + path + '\AecBase.dbx" /product "C3D" ';
  end else if prodId = 'D000' then begin // Civil 3D 2014
    Result := '/ld "' + path + '\AecBase.dbx" ';
  end else if prodId = 'B000' then begin // Civil 3D 2013
    Result := '/ld "' + path + '\AecBase.dbx" ';
  end else if prodId = 'A000' then begin // Civil 3D 2012
    Result := '/ld "' + path + '\AecBase.dbx" ';
  end else if prodId = '9000' then begin // Civil 3D 2011
    Result := '/ld "' + path + '\AecBase.dbx" ';
  end else if prodId = '8000' then begin // Civil 3D 2010
    Result := '/ld "' + path + '\AecBase.dbx" ';
  end else if prodId = '7000' then begin // Civil 3D 2009
    Result := '/ld "' + path + '\AecBase.dbx" ';
  end else begin
    Result := '';
  end;
end;

Cheers
Veli
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: civil.eng on November 14, 2020, 12:57:26 PM

Hi,
I have almost finished my installation project with Inno Setup. Setup package is in 32bit mode because it has 32bit dlls to register in Windows environment. Original idea was to detect AutoCAD version and install 3rd addin upon selected version. It also creates AutoCAD profiles and configures them. I don´t know is this a right way to do it but it is a one way. Have a good coding! =)

This is only a part of code because of 20000 characters limit. If someone need rest of it I can put it in .iss file.
Code: [Select]
[Icons]
Name: "{group}\KHK"; Filename: "{code:GetAutoCADExe}\acad.exe"; WorkingDir: "{app}"; IconFilename: "{app}\Bp.ico"; Parameters: "{code:CheckAutoCADStartupParameters}/p ""KHK"""

[Run]
Filename: "{app}\CopyRegKey.bat"; Parameters: """HKEY_CURRENT_USER\{code:GetTemplateProfileRegKey}"""; WorkingDir: "{app}"; Flags: waituntilterminated; StatusMsg: "Kopioi ja luo AutoCAD profiilit..."; AfterInstall: ModifyKHKProfileRegFile
Filename: "{app}\ImportRegKey.bat"; Parameters: "KHK"; WorkingDir: "{app}"; Flags: waituntilterminated; StatusMsg: "Palauttaa ja muokkaa AutoCAD profiileja..."; AfterInstall: ModifyKHKProfile

[Code]
// Global type definitions
type

  AUTOCADINFO = record
    location: AnsiString;
    productname: AnsiString;
    productid: AnsiString;
    serialnumber: AnsiString;
    registrykey: AnsiString;
  end;
  AcadInfoArray = array of AUTOCADINFO;

// Global variables
var
  SelectAutoCADPage: TInputOptionWizardPage;
  AcadInfos: AcadInfoArray;
  RootKey: Integer;

// Function declarations
function GetInstalledAutoCADVersions(): Boolean; forward;
function GetAutoCADProductName(Param: String): String; forward;

// Function implementations
function InitializeSetup(): Boolean;
var
  bRes: Boolean;
begin;
  bRes := False;
  Log('InitializeSetup() called');
  bRes := GetInstalledAutoCADVersions();
  if bRes = False then begin
    MsgBox('Koneelta ei löytynyt asennettua AutoCAD -ohjelmaa.' + #13#10 + 'Asennus lopetetaan.', mbInformation, MB_OK);
  end;
  Result := bRes;
end;

procedure InitializeWizard;
var
  iCountAcadProductNames, I: Integer;
  button : TButton;
begin
  Log('InitializeWizard() called');

  // AutoCAD version selection dialog
  SelectAutoCADPage := CreateInputOptionPage(wpWelcome, 'AutoCAD version valinta', 'Minkä AutoCAD:n päälle ohjelmisto asennetaan?',
    'Valitse AutoCAD versio ja paina Seuraava.', True, False);
  iCountAcadProductNames := GetArrayLength(AcadInfos);
  for I := 0 to iCountAcadProductNames - 1 do
  begin
    SelectAutoCADPage.Add(AcadInfos[I].productname);
  end;

function GetInstalledAutoCADVersions(): Boolean;
var
  S, V, AcadRegKey, sAcadExeLocation, sProductName, sProductId, sSerialNumber, sRegistryKey: String;
  I, J, iCountAcadExeLocations: Integer;
  AcadVerNames, AcadVerKeysTemp: TArrayOfString;
  AcadInfo: AUTOCADINFO;
begin
  if IsWin64 then begin
    RootKey := HKLM64;
  end else begin
    RootKey := HKEY_LOCAL_MACHINE;
  end;

  iCountAcadExeLocations := 0; 
  AcadRegKey := 'SOFTWARE\Autodesk\AutoCAD';
  if RegGetSubkeyNames(RootKey, AcadRegKey, AcadVerNames) then
  begin
    S := '';
    for I := 0 to GetArrayLength(AcadVerNames) - 1 do
    begin
      //MsgBox(AcadRegKey + '\' + AcadVerNames[I], mbInformation, MB_OK);
      if RegGetSubkeyNames(RootKey, AcadRegKey + '\' + AcadVerNames[I], AcadVerKeysTemp) then
      begin
        for J := 0 to GetArrayLength(AcadVerKeysTemp)-1 do
        begin
          //SOFTWARE\Autodesk\AutoCAD\R17.2\ACAD-7000:409
          //MsgBox(AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J], mbInformation, MB_OK);
          sAcadExeLocation := '';
          sRegistryKey := AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J];
          if RegQueryStringValue(RootKey, AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J], 'Location', sAcadExeLocation) then
          begin
            sProductName := '';
            sProductId := '';
            sSerialNumber := '';
            SetArrayLength(AcadInfos, iCountAcadExeLocations + 1);
            AcadInfo.location := sAcadExeLocation;
            if RegQueryStringValue(RootKey, AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J], 'ProductName', sProductName) then begin
              AcadInfo.productname := sProductName;
            end;
            if RegQueryStringValue(RootKey, AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J], 'ProductId', sProductId) then begin
              AcadInfo.productid := sProductId;
            end;
            if RegQueryStringValue(RootKey, AcadRegKey + '\' + AcadVerNames[I] + '\' + AcadVerKeysTemp[J], 'SerialNumber', sSerialNumber) then begin
              AcadInfo.serialnumber := sSerialNumber;
            end;
            AcadInfo.registrykey := sRegistryKey;
            AcadInfos[iCountAcadExeLocations] := AcadInfo;
            //MsgBox('Location = ' + AcadInfo.location + #13#10 + 'ProductName = ' + AcadInfo.productname + #13#10 + 'ProductId = ' + AcadInfo.productid + #13#10 + 'SerialNumber = ' + AcadInfo.serialnumber + #13#10, mbInformation, MB_OK);
           
            iCountAcadExeLocations := iCountAcadExeLocations + 1;
          end;
        end;
      end;
    end;
    //MsgBox('Founded AutoCAD registry keys:'#13#10#13#10 + S, mbInformation, MB_OK);
  end;
  if iCountAcadExeLocations > 0 then begin
    Result := True;
  end else begin
    Result := False;
  end;
end;

function GetAutoCADProductName(Param: String): String;
var
  sRet: String;
begin
  // AutoCAD 2012
  if Param = 'ACAD-A000:409' then begin
    sRet := 'Autodesk Civil 3D 2012';
  end else if Param = 'ACAD-A001:409' then begin
    sRet := 'AutoCAD 2012';
  end else if Param = 'ACAD-A002:409' then begin
    sRet := 'Autodesk Map 3D 2012';

  // AutoCAD 2013
  end else if Param = 'ACAD-B000:409' then begin
    sRet := 'Autodesk Civil 3D 2013';
  end else if Param = 'ACAD-B001:409' then begin
    sRet := 'AutoCAD 2013';
  end else if Param = 'ACAD-B002:409' then begin
    sRet := 'Autodesk Map 3D 2013';

  // AutoCAD 2009
  end else if Param = 'ACAD-7000:409' then begin
    sRet := 'Autodesk Civil 3D 2009';
  end else if Param = 'ACAD-7001:409' then begin
    sRet := 'AutoCAD 2009';
  end else if Param = 'ACAD-7002:409' then begin
    sRet := 'Autodesk Map 3D 2009';

  // AutoCAD 2010
  end else if Param = 'ACAD-8000:409' then begin
    sRet := 'Autodesk Civil 3D 2010';
  end else if Param = 'ACAD-8001:409' then begin
    sRet := 'AutoCAD 2010';
  end else if Param = 'ACAD-8002:409' then begin
    sRet := 'Autodesk Map 3D 2010';

  // AutoCAD 2011
  end else if Param = 'ACAD-9000:409' then begin
    sRet := 'Autodesk Civil 3D 2011';
  end else if Param = 'ACAD-9001:409' then begin
    sRet := 'AutoCAD 2011';
  end else if Param = 'ACAD-9002:409' then begin
    sRet := 'Autodesk Map 3D 2011';

  // AutoCAD 2014
  end else if Param = 'ACAD-D000:409' then begin
    sRet := 'Autodesk Civil 3D 2014';
  end else if Param = 'ACAD-D001:409' then begin
    sRet := 'AutoCAD 2014';
  end else if Param = 'ACAD-D002:409' then begin
    sRet := 'Autodesk Map 3D 2014';

  // AutoCAD 2015
  end else if Param = 'ACAD-E000:409' then begin
    sRet := 'Autodesk Civil 3D 2015';
  end else if Param = 'ACAD-E001:409' then begin
    sRet := 'AutoCAD 2015';
  end else if Param = 'ACAD-E002:409' then begin
    sRet := 'Autodesk Map 3D 2015';

  // AutoCAD 2016
  end else if Param = 'ACAD-F000:409' then begin
    sRet := 'Autodesk Civil 3D 2016';
  end else if Param = 'ACAD-F001:409' then begin
    sRet := 'AutoCAD 2016';
  end else if Param = 'ACAD-F002:409' then begin
    sRet := 'Autodesk Map 3D 2016';

  // Something other AutoCAD version
  end else begin
    sRet := 'Tuntematon AutoCAD versio: ' + Param;
  end;
  //MsgBox('GetAutoCADProductName(' + Param + ') = ' + sRet, mbInformation, MB_OK);
  Result := sRet; 
end;

function GetAutoCADExe(Param: String): String;
begin
  Result := AcadInfos[SelectAutoCADPage.SelectedValueIndex].location;
end;

function GetTemplateProfileRegKey(Param: String): String;
var
  prodId, regkey: String;
begin
  prodId := AcadInfos[SelectAutoCADPage.SelectedValueIndex].productid;
  regkey := AcadInfos[SelectAutoCADPage.SelectedValueIndex].registrykey;
  Log('CheckAutoCADStartupParameters prodId: ' + prodId);
  if prodId = 'F000' then begin // Civil 3D 2016
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else if prodId = 'E000' then begin // Civil 3D 2015
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else if prodId = 'D000' then begin // Civil 3D 2014
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else if prodId = 'B000' then begin // Civil 3D 2013
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else if prodId = 'A000' then begin // Civil 3D 2012
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else if prodId = '9000' then begin // Civil 3D 2011
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else if prodId = '8000' then begin // Civil 3D 2010
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else if prodId = '7000' then begin // Civil 3D 2009
    Result := regkey + '\Profiles\<<C3D_Metric>>';
  end else begin
    Result := regkey + '\Profiles\<<Unnamed Profile>>';
  end;
end;

function CheckAutoCADStartupParameters(Param: String): String;
var
  prodId, path: String;
begin
  prodId := AcadInfos[SelectAutoCADPage.SelectedValueIndex].productid;
  path := AcadInfos[SelectAutoCADPage.SelectedValueIndex].location;
  Log('CheckAutoCADStartupParameters prodId: ' + prodId);
  Log('CheckAutoCADStartupParameters location: ' + path);
  if prodId = 'F000' then begin // Civil 3D 2016
    Result := '/ld "' + path + '\AecBase.dbx" /product "C3D" ';
  end else if prodId = 'F002' then begin // Map 3D 2016
    Result := '/product MAP /language "en-US" ';
  end else if prodId = 'E000' then begin // Civil 3D 2015
    Result := '/ld "' + path + '\AecBase.dbx" /product "C3D" ';
  end else if prodId = 'D000' then begin // Civil 3D 2014
    Result := '/ld "' + path + '\AecBase.dbx" ';
  end else if prodId = 'B000' then begin // Civil 3D 2013
    Result := '/ld "' + path + '\AecBase.dbx" ';
  end else if prodId = 'A000' then begin // Civil 3D 2012
    Result := '/ld "' + path + '\AecBase.dbx" ';
  end else if prodId = '9000' then begin // Civil 3D 2011
    Result := '/ld "' + path + '\AecBase.dbx" ';
  end else if prodId = '8000' then begin // Civil 3D 2010
    Result := '/ld "' + path + '\AecBase.dbx" ';
  end else if prodId = '7000' then begin // Civil 3D 2009
    Result := '/ld "' + path + '\AecBase.dbx" ';
  end else begin
    Result := '';
  end;
end;

Cheers
Veli
Hi Veli, this topic is old and I hope you see my post. thank you for your great project of Inno Setup, I could perform a project in inno setup with your functions. now I extremely need to copy a single file like a font to all Locations of Autocad. is it possible?
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: VVeli on January 04, 2021, 04:11:40 AM
Hi,
I think you can add font to right location to use function GetInstalledAutoCADVersions(): Boolean;
It finds all installed AutoCAD versions on your computer. Just get location and add Fonts folder to copy your file there.
There is a global list (AcadInfos: AcadInfoArray;) where founded AutoCAD versions are readed.
Br. Veli
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: civil.eng on March 06, 2021, 08:48:23 AM
Thank you for replying, I could do the first part of that, so that now I have an array of all installed Autocad locations, but how can I copy fonts to each location of Autocad?
In another words I have one "Source" and several "DestDir", as far as I know we can use only one destination in "DestDir, while we have multiple location.
Title: Re: Innosetup: Looping through all versions and verticals and languages ...
Post by: d2010 on March 13, 2021, 01:49:53 AM
InnoSetup. is very good. The setup-installer.exe develope by InnoSetup5, work fine
inside Reactos, but the windows32application does not work.
 :idea:
Thank you for replying, I could do the first part of that, so that now I have an array of all installed Autocad locations, but how can I copy fonts to each location of Autocad?