Author Topic: Innosetup: Looping through all versions and verticals and languages ...  (Read 19873 times)

0 Members and 1 Guest are viewing this topic.

BlackBox

  • King Gator
  • Posts: 3745
Re: Innosetup: Looping through all versions and verticals and languages ...
« Reply #15 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:
"How we think determines what we do, and what we do determines what we get."

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Innosetup: Looping through all versions and verticals and languages ...
« Reply #16 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
« Last Edit: August 13, 2013, 01:35:10 AM by irneb »
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

BlackBox

  • King Gator
  • Posts: 3745
Re: Innosetup: Looping through all versions and verticals and languages ...
« Reply #17 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
"How we think determines what we do, and what we do determines what we get."

DanW

  • Mosquito
  • Posts: 16
Re: Innosetup: Looping through all versions and verticals and languages ...
« Reply #18 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.

BlackBox

  • King Gator
  • Posts: 3745
Re: Innosetup: Looping through all versions and verticals and languages ...
« Reply #19 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
« Last Edit: August 14, 2013, 08:50:34 AM by BlackBox »
"How we think determines what we do, and what we do determines what we get."

BlackBox

  • King Gator
  • Posts: 3745
Re: Innosetup: Looping through all versions and verticals and languages ...
« Reply #20 on: August 13, 2013, 10:04:19 AM »
... Might be useful if I included a link to the Autoloader White Paper :thumbsup:
"How we think determines what we do, and what we do determines what we get."

Peter2

  • Swamp Rat
  • Posts: 615
Re: Innosetup: Looping through all versions and verticals and languages ...
« Reply #21 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?
Peter

AutoCAD Map 3D 2018 German (so some technical terms will be badly retranslated to English)
BricsCAD V19

BlackBox

  • King Gator
  • Posts: 3745
Re: Innosetup: Looping through all versions and verticals and languages ...
« Reply #22 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.

Good luck!
"How we think determines what we do, and what we do determines what we get."

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Innosetup: Looping through all versions and verticals and languages ...
« Reply #23 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. 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.
« Last Edit: August 14, 2013, 03:33:01 AM by irneb »
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

DanW

  • Mosquito
  • Posts: 16
Re: Innosetup: Looping through all versions and verticals and languages ...
« Reply #24 on: August 14, 2013, 04:54:45 AM »
Hi Irneb,

Fantastic tutorial! Taught me a lot.  Many thanks for posting.

Peter2

  • Swamp Rat
  • Posts: 615
Re: Innosetup: Looping through all versions and verticals and languages ...
« Reply #25 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?
Peter

AutoCAD Map 3D 2018 German (so some technical terms will be badly retranslated to English)
BricsCAD V19

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Innosetup: Looping through all versions and verticals and languages ...
« Reply #26 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, 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).
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Innosetup: Looping through all versions and verticals and languages ...
« Reply #27 on: August 14, 2013, 05:24:13 AM »
BTW, anyone noticed the errors in my code? Hint, it's usually associated with Lisp  :wink:
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

DW

  • Newt
  • Posts: 22
Re: Innosetup: Looping through all versions and verticals and languages ...
« Reply #28 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;



irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Innosetup: Looping through all versions and verticals and languages ...
« Reply #29 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
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.