{"id":2533,"date":"2006-01-23T17:24:00","date_gmt":"2006-01-23T17:24:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/heaths\/2006\/01\/23\/waiting-to-install\/"},"modified":"2006-01-23T17:24:00","modified_gmt":"2006-01-23T17:24:00","slug":"waiting-to-install","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/setup\/waiting-to-install\/","title":{"rendered":"Waiting to Install"},"content":{"rendered":"<p>If you&#8217;ve ever tried to install a Windows Installer package and had returned <code>ERROR_INSTALL_ALREADY_RUNNING<\/code> (1618) it&#8217;s because the Windows Installer execution server is already processing another install, administrative install, or advertisement action. That is, Windows Installer is processing the <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/msi\/setup\/installexecutesequence_table.asp\">InstallExecuteSequence table<\/a>, the <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/msi\/setup\/adminexecutesequence_table.asp\">AdminExecuteSequence table<\/a>, or the <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/msi\/setup\/advtexecutesequence_table.asp\">AdvtExecuteSequence table<\/a>, respectively. This is because right before the action is run in the server context Windows Installer grabs the <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/msi\/setup\/_msiexecute_mutex.asp\">_MSIExecute mutex<\/a>. Take a look at the log below:<\/p>\n<p style=\"font-family: courier new, monospace\">=== Verbose logging started: 10\/3\/2005  14:26:48  Build type: SHIP UNICODE 3.01.4000.2435  Calling process: C:\\Documents and Settings\\User\\Local Settings\\Temp\\SIT12330.tmp\\setup.exe ===<br \/>\nMSI (c) (80:00) [14:26:48:285]: Resetting cached policy values<br \/>\nMSI (c) (80:00) [14:26:48:285]: Machine policy value &#8216;Debug&#8217; is 0<br \/>\nMSI (c) (80:00) [14:26:48:285]: ******* RunEngine:<br \/>\n           ******* Product: C:\\WINDOWS\\Installer\\3dfeb63f.msi<br \/>\n           ******* Action: <br \/>\n           ******* CommandLine: **********<br \/>\nMSI (c) (80:00) [14:26:48:285]: Client-side and UI is none or basic: Running entire install on the server.<br \/>\n<span style=\"color: red\">MSI (c) (80:00) [14:26:48:285]: Grabbed execution mutex.<\/span><br \/>\nMSI (c) (80:00) [14:26:48:295]: Cloaking enabled.<br \/>\nMSI (c) (80:00) [14:26:48:295]: Attempting to enable all disabled priveleges before calling Install on Server<br \/>\nMSI (c) (80:00) [14:26:48:295]: Incrementing counter to disable shutdown. Counter after increment: 0<br \/>\nMSI (s) (3C:1C) [14:26:48:315]: Grabbed execution mutex.<br \/>\nMSI (s) (3C:0C) [14:26:48:315]: Resetting cached policy values<br \/>\nMSI (s) (3C:0C) [14:26:48:315]: Machine policy value &#8216;Debug&#8217; is 0<br \/>\nMSI (s) (3C:0C) [14:26:48:315]: ******* RunEngine:<br \/>\n           ******* Product: C:\\WINDOWS\\Installer\\3dfeb63f.msi<br \/>\n           ******* Action: <br \/>\n           ******* CommandLine: **********<br \/>\nMSI (s) (3C:0C) [14:26:48:315]: Machine policy value &#8216;DisableUserInstalls&#8217; is 0<br \/>\n&#8230;<\/p>\n<p>Multiple installer sessions can run in the client context concurrently but only one can enter the server context. If a concurrent installer session attempts to grab the execution mutex when another thread owns it, <code>ERROR_INSTALL_ALREADY_RUNNING<\/code> is returned. This isn&#8217;t always desirable in automated testing. SMS could be installing something at the time, for example, and the install you&#8217;re intending to test will fail.<\/p>\n<p>Since mutexes are owned by a single thread, we can wait to own the mutex and then kick off an install successfully since the client will grab the execution mutex on the same thread if we&#8217;re making calls to Windows Installer APIs like the <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/msi\/setup\/msiinstallproduct.asp\"><code>MsiInstallProduct<\/code> function<\/a>. Let&#8217;s take a look at some sample code that waits on the mutex and calls <code>MsiInstallProduct<\/code> which can do just about everything you need from installing a new package to patching, and administrative installs to advertised installs.<\/p>\n<pre><span style=\"color: blue\">#define<\/span> WIN32_LEAN_AND_MEAN\n<span style=\"color: blue\">#include<\/span> <span style=\"color: maroon\">&lt;stdio.h&gt;<\/span>\n<span style=\"color: blue\">#include<\/span> <span style=\"color: maroon\">&lt;tchar.h&gt;\n<\/span><span style=\"color: #0000ff\">#include<\/span> <span style=\"color: maroon\">&lt;windows.h&gt;\n<\/span><span style=\"color: #0000ff\">#include<\/span> <span style=\"color: maroon\">&lt;msi.h&gt;\n<\/span><span style=\"color: #0000ff\">#include<\/span> <span style=\"color: maroon\">&lt;string&gt;\n<\/span>\n<span style=\"color: blue\">typedef<\/span> std::basic_string&lt;TCHAR&gt; tstring;\n<span style=\"color: blue\">#pragma comment<\/span>(<span style=\"color: blue\">lib<\/span>, <span style=\"color: maroon\">\"msi.lib\"<\/span>)\n<span style=\"color: blue\">int<\/span> _tmain(<span style=\"color: blue\">int<\/span> argc, _TCHAR* argv[])\n{\n  DWORD dwError = NOERROR;\n  LPTSTR pszPackage = NULL;\n  tstring strArgs;\n  HANDLE hMutex = NULL;\n  SECURITY_ATTRIBUTES sa = { <span style=\"color: blue\">sizeof<\/span>(SECURITY_ATTRIBUTES) };\n  <span style=\"color: green\">\/\/ Make sure at least a package was specified.\n<\/span>  <span style=\"color: blue\">if<\/span> (2 &gt; argc)\n  {\n    _ftprintf(stderr,\n      TEXT(<span style=\"color: maroon\">\"Error: you must provide the path to a Windows Installer package.\\n\"<\/span>));\n    _ftprintf(stderr, TEXT(<span style=\"color: maroon\">\"Usage: %s &lt;package&gt; [Windows Installer options]\\n\"<\/span>),\n      argv[0]);\n    <span style=\"color: blue\">return<\/span> ERROR_INVALID_PARAMETER;\n  }\n  <span style=\"color: green\">\/\/ Get the path the specified package.\n<\/span>  pszPackage = argv[1];\n  <span style=\"color: green\">\/\/ Build up remaining options as a single string.\n<\/span>  <span style=\"color: blue\">for<\/span> (<span style=\"color: blue\">int<\/span> i = 2; i &lt; argc; i++)\n  {\n    strArgs += argv[i];\n    strArgs += TEXT(<span style=\"color: maroon\">\" \"<\/span>);\n  }\n  <span style=\"color: green\">\/\/ Grab the execution mutex when made available.\n<\/span>  hMutex = CreateMutex(&amp;sa, FALSE, TEXT(<span style=\"color: maroon\">\"_MSIExecute\"<\/span>));\n  <span style=\"color: blue\">if<\/span> (!hMutex)\n  {\n    dwError = GetLastError();\n    _ftprintf(stderr,\n      TEXT(<span style=\"color: maroon\">\"Error: failed to grab execution mutex. GetLastError() = %d\\n\"<\/span>),\n      dwError);\n    <span style=\"color: blue\">return<\/span> dwError;\n  }\n  <span style=\"color: green\">\/\/ Wait to grab ownership of the execution mutex.\n<\/span>  _tprintf(TEXT(<span style=\"color: maroon\">\"Waiting for execution mutex...\\n\"<\/span>));\n  dwError = WaitForSingleObject(hMutex, INFINITE);\n  <span style=\"color: blue\">if<\/span> (WAIT_OBJECT_0 == dwError)\n  {\n    <span style=\"color: green\">\/\/ Install the package on the current thread owning the execution mutex.\n<\/span>    _tprintf(TEXT(<span style=\"color: maroon\">\"Installing the specified package...\"<\/span>));\n    dwError = MsiInstallProduct(pszPackage, strArgs.c_str());\n    _tprintf(TEXT(<span style=\"color: maroon\">\"done.\\n\"<\/span>));\n  }\n  if (ERROR_SUCCESS != dwError)\n  {\n    _ftprintf(stderr, TEXT(<span style=\"color: maroon\">\"Error: an error has occured. GetLastError() = %d\\n\"<\/span>),\n      dwError);\n  }\n  CloseHandle(hMutex);\n  <span style=\"color: blue\">return static_cast<\/span>&lt;<span style=\"color: blue\">int<\/span>&gt;(dwError);\n}<\/pre>\n<p>Now even if another installation is being processed in the server context we can wait to install whatever product we specify by using a command similar to the following. Assume the code was compiled to <i>MsiWait.exe<\/i>.<\/p>\n<p style=\"font-family: Courier new, Monospace\">MsiWait.exe Package.msi ACTION=INSTALL<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you&#8217;ve ever tried to install a Windows Installer package and had returned ERROR_INSTALL_ALREADY_RUNNING (1618) it&#8217;s because the Windows Installer execution server is already processing another install, administrative install, or advertisement action. That is, Windows Installer is processing the InstallExecuteSequence table, the AdminExecuteSequence table, or the AdvtExecuteSequence table, respectively. This is because right before the [&hellip;]<\/p>\n","protected":false},"author":389,"featured_media":3843,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[20],"class_list":["post-2533","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-installation"],"acf":[],"blog_post_summary":"<p>If you&#8217;ve ever tried to install a Windows Installer package and had returned ERROR_INSTALL_ALREADY_RUNNING (1618) it&#8217;s because the Windows Installer execution server is already processing another install, administrative install, or advertisement action. That is, Windows Installer is processing the InstallExecuteSequence table, the AdminExecuteSequence table, or the AdvtExecuteSequence table, respectively. This is because right before the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/posts\/2533","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/users\/389"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/comments?post=2533"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/posts\/2533\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/media\/3843"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/media?parent=2533"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/categories?post=2533"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/tags?post=2533"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}