{"id":51,"date":"2015-07-17T11:58:00","date_gmt":"2015-07-17T11:58:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/davidrickard\/2015\/07\/17\/installing-net-framework-4-5-automatically-with-inno-setup\/"},"modified":"2018-09-24T04:43:38","modified_gmt":"2018-09-24T04:43:38","slug":"installing-net-framework-4-5-automatically-with-inno-setup","status":"publish","type":"post","link":"https:\/\/engy.us\/blog\/2015\/07\/17\/installing-net-framework-4-5-automatically-with-inno-setup\/","title":{"rendered":"Installing .NET Framework 4.7 automatically with Inno Setup"},"content":{"rendered":"<p>In this guide I will walk through how to get the .NET framework to download and install on-the-fly in an Inno Setup installer.<\/p>\n<p>It works in 3 steps:<\/p>\n<ol>\n<li>Detect if the desired .NET framework is installed<\/li>\n<li>Download the .NET Framework bootstrap installer with Inno Download Plugin<\/li>\n<li>Run the bootstrap installer in quiet mode, which will download and install the .NET Framework. This is better than downloading the full installer since it only downloads the files it needs for your platform.<\/li>\n<\/ol>\n<p>Here&#8217;s the full code:<\/p>\n<pre>#include &lt;idp.iss&gt;\r\n\r\n\/\/ Other parts of installer file go here\r\n\r\n[CustomMessages]\r\nIDP_DownloadFailed=Download of .NET Framework 4.7.2 failed. .NET Framework 4.7 is required to run VidCoder.\r\nIDP_RetryCancel=Click 'Retry' to try downloading the files again, or click 'Cancel' to terminate setup.\r\nInstallingDotNetFramework=Installing .NET Framework 4.7.2. This might take a few minutes...\r\nDotNetFrameworkFailedToLaunch=Failed to launch .NET Framework Installer with error \"%1\". Please fix the error then run this installer again.\r\nDotNetFrameworkFailed1602=.NET Framework installation was cancelled. This installation can continue, but be aware that this application may not run unless the .NET Framework installation is completed successfully.\r\nDotNetFrameworkFailed1603=A fatal error occurred while installing the .NET Framework. Please fix the error, then run the installer again.\r\nDotNetFrameworkFailed5100=Your computer does not meet the requirements of the .NET Framework. Please consult the documentation.\r\nDotNetFrameworkFailedOther=The .NET Framework installer exited with an unexpected status code \"%1\". Please review any other messages shown by the installer to determine whether the installation completed successfully, and abort this installation and fix the problem if it did not.\r\n\r\n[Code]\r\n\r\nvar\r\n  requiresRestart: boolean;\r\n\r\nfunction NetFrameworkIsMissing(): Boolean;\r\nvar\r\n  bSuccess: Boolean;\r\n  regVersion: Cardinal;\r\nbegin\r\n  Result := True;\r\n\r\n  bSuccess := RegQueryDWordValue(HKLM, 'Software\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full', 'Release', regVersion);\r\n  if (True = bSuccess) and (regVersion &gt;= 461308) then begin\r\n    Result := False;\r\n  end;\r\nend;\r\n\r\nprocedure InitializeWizard;\r\nbegin\r\n  if NetFrameworkIsMissing() then\r\n  begin\r\n    idpAddFile('http:\/\/go.microsoft.com\/fwlink\/?LinkId=863262', ExpandConstant('{tmp}\\NetFrameworkInstaller.exe'));\r\n    idpDownloadAfter(wpReady);\r\n  end;\r\nend;\r\n\r\nfunction InstallFramework(): String;\r\nvar\r\n  StatusText: string;\r\n  ResultCode: Integer;\r\nbegin\r\n  StatusText := WizardForm.StatusLabel.Caption;\r\n  WizardForm.StatusLabel.Caption := CustomMessage('InstallingDotNetFramework');\r\n  WizardForm.ProgressGauge.Style := npbstMarquee;\r\n  try\r\n    if not Exec(ExpandConstant('{tmp}\\NetFrameworkInstaller.exe'), '\/passive \/norestart \/showrmui \/showfinalerror', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then\r\n    begin\r\n      Result := FmtMessage(CustomMessage('DotNetFrameworkFailedToLaunch'), [SysErrorMessage(resultCode)]);\r\n    end\r\n    else\r\n    begin\r\n      \/\/ See https:\/\/msdn.microsoft.com\/en-us\/library\/ee942965(v=vs.110).aspx#return_codes\r\n      case resultCode of\r\n        0: begin\r\n          \/\/ Successful\r\n        end;\r\n        1602 : begin\r\n          MsgBox(CustomMessage('DotNetFrameworkFailed1602'), mbInformation, MB_OK);\r\n        end;\r\n        1603: begin\r\n          Result := CustomMessage('DotNetFrameworkFailed1603');\r\n        end;\r\n        1641: begin\r\n          requiresRestart := True;\r\n        end;\r\n        3010: begin\r\n          requiresRestart := True;\r\n        end;\r\n        5100: begin\r\n          Result := CustomMessage('DotNetFrameworkFailed5100');\r\n        end;\r\n        else begin\r\n          MsgBox(FmtMessage(CustomMessage('DotNetFrameworkFailedOther'), [IntToStr(resultCode)]), mbError, MB_OK);\r\n        end;\r\n      end;\r\n    end;\r\n  finally\r\n    WizardForm.StatusLabel.Caption := StatusText;\r\n    WizardForm.ProgressGauge.Style := npbstNormal;\r\n    \r\n    DeleteFile(ExpandConstant('{tmp}\\NetFrameworkInstaller.exe'));\r\n  end;\r\nend;\r\n\r\nfunction PrepareToInstall(var NeedsRestart: Boolean): String;\r\nbegin\r\n  \/\/ 'NeedsRestart' only has an effect if we return a non-empty string, thus aborting the installation.\r\n  \/\/ If the installers indicate that they want a restart, this should be done at the end of installation.\r\n  \/\/ Therefore we set the global 'restartRequired' if a restart is needed, and return this from NeedRestart()\r\n\r\n  if NetFrameworkIsMissing() then\r\n  begin\r\n    Result := InstallFramework();\r\n  end;\r\nend;\r\n\r\nfunction NeedRestart(): Boolean;\r\nbegin\r\n  Result := requiresRestart;\r\nend;\r\n<\/pre>\n<h2>Detecting if the desired .NET Framework is installed<\/h2>\n<p>First you need to determine what registry key to check to see if your .NET version is installed. There is a good <a href=\"http:\/\/stackoverflow.com\/questions\/199080\/how-to-detect-what-net-framework-versions-and-service-packs-are-installed\">Stack Overflow answer that covers this<\/a>, though the <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/framework\/migration-guide\/how-to-determine-which-versions-are-installed\">Microsoft docs page<\/a> is more likely to be up to date. There is also a good <a href=\"http:\/\/kynosarges.org\/DotNetVersion.html\">article on how to apply that in Inno Setup&#8217;s Pascal scripting language<\/a>.<\/p>\n<p>I wrote mine to check for .NET 4.7. (See the NetFrameworkIsMissing method)<\/p>\n<h2>Downloading the bootstrapper<\/h2>\n<p>Next we need to find out where to download the installer from. <a href=\"https:\/\/msdn.microsoft.com\/en-US\/library\/ee942965%28v=vs.110%29.aspx?f=255&amp;MSPPError=-2147217396#redist\">The .NET Framework Deployment Guide for Developers<\/a> has a great list of stable download links for the bootstrapper (web) installers. I picked 4.7.2, as it still supports code targeting .NET 4.7, and we might as well give the users the latest we can. This link should prompt you to download an .exe file directly; if it&#8217;s bringing you to a download webpage, it won&#8217;t work.<\/p>\n<p>Now install <a href=\"https:\/\/code.google.com\/p\/inno-download-plugin\/\">Inno Download Plugin<\/a>. This will make the idpAddFile and idpDownloadAfter calls inside InitializeWizard work.<\/p>\n<p>This &#8220;InitializeWizard&#8221; method is a special one that InnoSetup calls when first setting up its wizard pages. We call our helper function to detect if the framework is installed, then schedule a download step after the &#8220;Ready to install&#8221; page. We include our direct download link determined earlier, and save it in a temp folder, with a file name of &#8220;NetFrameworkInstaller.exe&#8221;. This name I picked arbitrarily; we just need to refer to it later when we&#8217;re installing and cleaning up.<\/p>\n<h2>Installing the bootstrapper<\/h2>\n<p>Our code is activated on PrepareToInstall. When this function returns a string, that string is shown as an error message that stops the install from happening. We call into InstallFramework and return its result.<\/p>\n<p>Inside InstallFramework we&#8217;re running the bootstrapper we downloaded earlier, with a flag to make the install passive (non interactive). The \/showrmui option prompts the user to close applications to avoid a system restart. \/showfinalerror tells the installer to show an error message if the install fails. Our main installer will show this screen while the framework is getting downloaded and installed:\u00a0<a href=\"https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2015\/07\/8424.InstallingFramework-1.png?ssl=1\"><img data-attachment-id=\"55\" data-permalink=\"https:\/\/engy.us\/blog\/2015\/07\/17\/installing-net-framework-4-5-automatically-with-inno-setup\/8424-installingframework-2\/\" data-orig-file=\"https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2015\/07\/8424.InstallingFramework-1.png?fit=503%2C388&amp;ssl=1\" data-orig-size=\"503,388\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"8424.InstallingFramework\" data-image-description=\"\" data-medium-file=\"https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2015\/07\/8424.InstallingFramework-1.png?fit=300%2C231&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2015\/07\/8424.InstallingFramework-1.png?fit=503%2C388&amp;ssl=1\" loading=\"lazy\" class=\"alignnone wp-image-55 size-full\" src=\"https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2015\/07\/8424.InstallingFramework-1.png?resize=503%2C388&#038;ssl=1\" alt=\"\" width=\"503\" height=\"388\" srcset=\"https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2015\/07\/8424.InstallingFramework-1.png?w=503&amp;ssl=1 503w, https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2015\/07\/8424.InstallingFramework-1.png?resize=300%2C231&amp;ssl=1 300w\" sizes=\"(max-width: 503px) 100vw, 503px\" data-recalc-dims=\"1\" \/><\/a><\/p>\n<p>Then the .NET installer UI will show alongside the first window:<a href=\"https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2015\/07\/7028.InstallingFramework2-1.png?ssl=1\"><img data-attachment-id=\"65\" data-permalink=\"https:\/\/engy.us\/blog\/2015\/07\/17\/installing-net-framework-4-5-automatically-with-inno-setup\/7028-installingframework2-2\/\" data-orig-file=\"https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2015\/07\/7028.InstallingFramework2-1.png?fit=503%2C470&amp;ssl=1\" data-orig-size=\"503,470\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"7028.InstallingFramework2\" data-image-description=\"\" data-medium-file=\"https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2015\/07\/7028.InstallingFramework2-1.png?fit=300%2C280&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2015\/07\/7028.InstallingFramework2-1.png?fit=503%2C470&amp;ssl=1\" loading=\"lazy\" class=\"alignnone size-full wp-image-65\" src=\"https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2015\/07\/7028.InstallingFramework2-1.png?resize=503%2C470&#038;ssl=1\" alt=\"\" width=\"503\" height=\"470\" srcset=\"https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2015\/07\/7028.InstallingFramework2-1.png?w=503&amp;ssl=1 503w, https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2015\/07\/7028.InstallingFramework2-1.png?resize=300%2C280&amp;ssl=1 300w\" sizes=\"(max-width: 503px) 100vw, 503px\" data-recalc-dims=\"1\" \/><\/a><\/p>\n<p>If you&#8217;d like to keep it &#8220;cleaner&#8221; and just show the first screen you can swap out the \/passive argument for \/q. However I like showing the user the .NET install progress since it can take a long time and it reassures them that work is still really happening.<\/p>\n<p>After running the installer, the bootstrapper is deleted (whether or not the install succeeded).<\/p>\n<p>And now your installer is done!<\/p>\n<h2>Testing the installer<\/h2>\n<p>To test a .NET 4 or 4.7 install, I&#8217;d recommend setting up a Windows 7 virtual machine in Hyper-V. Windows 7 comes with .NET 2, 3 and 3.5 out of the box, but not .NET 4 or 4.7. After it installs the framework you can go to Programs and Features to cleanly remove it and test it all over again.<\/p>\n<p>To test an earlier .NET version you should just be able to use a modern OS like Windows 8.1 or 10.<\/p>\n<p>Thanks to <a href=\"http:\/\/antonymale.co.uk\/\">Antony Male<\/a> for suggesting updates to the error handling code.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this guide I will walk through how to get the .NET framework to download and install on-the-fly in an Inno Setup installer. It works in 3 steps: Detect if the desired .NET framework is installed Download the .NET Framework bootstrap installer with Inno Download Plugin Run the bootstrap installer in quiet mode, which will &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/engy.us\/blog\/2015\/07\/17\/installing-net-framework-4-5-automatically-with-inno-setup\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Installing .NET Framework 4.7 automatically with Inno Setup&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"spay_email":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false},"categories":[1],"tags":[3],"jetpack_featured_media_url":"","jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pahBcK-P","jetpack-related-posts":[{"id":146,"url":"https:\/\/engy.us\/blog\/2021\/02\/28\/installing-net-5-runtime-automatically-with-inno-setup\/","url_meta":{"origin":51,"position":0},"title":"Installing .NET 5 Runtime Automatically with Inno Setup","date":"February 28, 2021","format":false,"excerpt":"In this guide I will walk through how to get the .NET 5 runtime to download and install on-the-fly in an Inno Setup installer. It works in 3 steps: Detect if the desired .NET runtime is installedDownload the .NET Runtime bootstrap installer with Inno Download PluginRun the bootstrap installer in\u2026","rel":"","context":"With 2 comments","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2021\/02\/image.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":25,"url":"https:\/\/engy.us\/blog\/2012\/04\/06\/datetime-and-datetimeoffset-in-net-good-practices-and-common-pitfalls\/","url_meta":{"origin":51,"position":1},"title":"DateTime and DateTimeOffset in .NET: Good practices and common pitfalls","date":"April 6, 2012","format":false,"excerpt":"It becomes necessary to deal with dates and times in most .NET programs. A lot of programs use DateTime but that structure is frought with potential issues when you start serializing, parsing, comparing\u00a0and displaying dates from\u00a0different time zones and cultures. In this post I will go over these issues and\u00a0the\u2026","rel":"","context":"In \".net\"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":174,"url":"https:\/\/engy.us\/blog\/2021\/12\/11\/aws-cognito-authentication-in-electron\/","url_meta":{"origin":51,"position":2},"title":"AWS Cognito Authentication in Electron","date":"December 11, 2021","format":false,"excerpt":"The AWS Cognito authentication service as of this writing does not officially support the Electron platform. But there is a Javascript SDK for Cognito, as part of AWS Amplify. Others have tried using it on Electron but have run into issues. I ran into several more than what are described\u2026","rel":"","context":"Similar post","img":{"alt_text":"","src":"https:\/\/i2.wp.com\/engy.us\/blog\/wp-content\/uploads\/2021\/12\/image.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":165,"url":"https:\/\/engy.us\/blog\/2021\/10\/03\/efficient-svg-icons-in-web-components-with-webpack-and-svgo\/","url_meta":{"origin":51,"position":3},"title":"Efficient SVG icons in Web Components with Webpack and SVGO","date":"October 3, 2021","format":false,"excerpt":"So many ways to load them There are a lot of different ways to show an SVG on a webpage: <img>, <embed>, <object>, <iframe>, <canvas> and <svg> among them. I think for any halfway modern browser there are really only two serious contenders here. Referencing an SVG file: <img src=\"image.svg\"\u2026","rel":"","context":"Similar post","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":159,"url":"https:\/\/engy.us\/blog\/2021\/05\/25\/how-to-use-individual-code-signing-certificates-to-get-rid-of-smartscreen-warnings\/","url_meta":{"origin":51,"position":4},"title":"How to Use Individual Code Signing Certificates to get rid of SmartScreen warnings","date":"May 25, 2021","format":false,"excerpt":"The problem Windows SmartScreen has for a while been trying to keep malware at bay. One of the ways of doing that is putting up a big scary warning when you try to run anything they haven't validated as safe: You have to click \"More info\" then \"Run anyway\" to\u2026","rel":"","context":"With 5 comments","img":{"alt_text":"","src":"https:\/\/i2.wp.com\/engy.us\/blog\/wp-content\/uploads\/2021\/05\/image.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":120,"url":"https:\/\/engy.us\/blog\/2020\/01\/01\/implementing-a-custom-window-title-bar-in-wpf\/","url_meta":{"origin":51,"position":5},"title":"Implementing a Custom Window Title Bar in WPF","date":"January 1, 2020","format":false,"excerpt":"There are several good reasons for wanting custom window chrome in WPF, such as fitting in additional UI or implementing a Dark theme. However the actual implementation is kind of tricky, since it is now your job to provide a bunch of features that you used to get for free.\u2026","rel":"","context":"With 12 comments","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/posts\/51"}],"collection":[{"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/comments?post=51"}],"version-history":[{"count":7,"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/posts\/51\/revisions"}],"predecessor-version":[{"id":147,"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/posts\/51\/revisions\/147"}],"wp:attachment":[{"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/media?parent=51"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/categories?post=51"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/tags?post=51"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}