{"id":56043,"date":"2008-03-08T00:00:00","date_gmt":"2008-03-08T00:00:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2008\/03\/08\/hey-scripting-guy-how-can-i-get-an-hta-to-remember-its-previous-position-onscreen\/"},"modified":"2008-03-08T00:00:00","modified_gmt":"2008-03-08T00:00:00","slug":"hey-scripting-guy-how-can-i-get-an-hta-to-remember-its-previous-position-onscreen","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-get-an-hta-to-remember-its-previous-position-onscreen\/","title":{"rendered":"Hey, Scripting Guy! How Can I Get an HTA to Remember Its Previous Position Onscreen?"},"content":{"rendered":"<p><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" height=\"34\" alt=\"Hey, Scripting Guy! Question\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\" \/> <\/p>\n<p>Hey, Scripting Guy! Is there any way to get an HTA to remember its previous position onscreen? Some of my users are very particular about moving an HTA to a specific spot on the screen, then wanting it to reappear at that same spot the next time they run the application.<\/p>\n<p>&#8212; DF<\/p>\n<p><img decoding=\"async\" height=\"5\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" border=\"0\" \/><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" height=\"34\" alt=\"Hey, Scripting Guy! Answer\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\" \/><a href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><img decoding=\"async\" class=\"farGraphic\" title=\"Script Center\" height=\"288\" alt=\"Script Center\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" width=\"120\" align=\"right\" border=\"0\" \/><\/a> <\/p>\n<p>Hey, DF. You know, in the past few weeks there has been a spate of alleged memoirs that turned out to be hoaxes: the events described never really happened, at least not to the people who wrote the books. Sadly, we must confess that the Scripting Guys have been guilty of embellishing the account of our lives as well. With that in mind, and with the utmost contrition, we decided to set the record straight. Contrary to popular belief:<\/p>\n<table class=\"\" cellSpacing=\"0\" cellPadding=\"0\" border=\"0\">\n<tbody>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>Scripting Guy Peter Costantini did not invent the light bulb, the sewing machine, or the personal computer. However, Peter insists that he <i>did<\/i> invent the wheel, the internal combustion engine, and the banana split. <\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>Scripting Guy Dean Tsaltas was not sent to the guillotine during the French revolution; instead, he was burned at the stake during the Salem Witch trials of 1692. No one ever accused Dean of being a witch; the people of Salem just didn\u2019t like him all that much.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>Scripting Guy Greg Stemp did not bat cleanup for the 1927 New York Yankees; Lou Gehrig was the cleanup hitter that season. Greg instead hit seventh in the order, just ahead of catcher Joe Grabowski. In addition, Greg did not win the 1973 Miss Hawaii beauty pageant; the truth is, he was eliminated after the talent competition. (In retrospect, writing a Windows PowerShell script that retrieved events from an event log was not the crowd-pleasing act he assumed it would be. He should have stuck with tap-dancing.)<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Interestingly enough, however, Scripting Guy Jean Ross really <i>did<\/i> crack her head open while attending the 2007 MMS conference in San Diego. Sometimes truth really <i>is<\/i> stranger than fiction.<\/p>\n<p>We realize that it was a mistake to make up these stories and attempt to pass them off as true, and we promise never to do this again. You say you find that hard to believe? Well, then consider <i>this:<\/i> at lunch yesterday Scripting Guy Greg Stemp made a personal promise to the Queen of England that everything written in this column will be 100% true. <\/p>\n<p>So there.<\/p>\n<p>So does that mean we\u2019re telling the truth when we say that it\u2019s easy to get an HTML Application (HTA) to remember its previous position onscreen? Don\u2019t just take our word for it; take a look at the following piece of code:<\/p>\n<pre class=\"codeSample\">&lt;SCRIPT Language=\"VBScript\"&gt;\n    Dim intLeft\n    Dim intTop\n\n    Sub Window_onLoad\n        window.offscreenBuffering = True\n\n        Const ForReading = 1\n        Set objFSO = CreateObject(\"Scripting.FileSystemObject\")\n        Set objFile = objFSO.OpenTextFile(\"HTA.ini\", ForReading)\n        strContents = objFile.ReadAll\n        objFile.Close\n\n        arrContents = Split(strContents, \",\")\n        window.moveTo arrContents(0), arrContents(1)\n    End Sub\n\n    Sub Window_onBeforeUnLoad\n        intLeft = window.screenLeft\n        intTop = window.screenTop\n\n        Const ForWriting = 2\n        Set objFSO = CreateObject(\"Scripting.FileSystemObject\")\n        Set objFile = objFSO.OpenTextFile(\"HTA.ini\", ForWriting)\n        objFile.WriteLine intLeft &amp; \",\" &amp; intTop\n        objFile.Close\n    End Sub\n&lt;\/SCRIPT&gt;\n\n&lt;BODY&gt;\n&lt;\/BODY&gt;\n<\/pre>\n<p>As you can see, there\u2019s not a lot to this HTA; as a matter of fact, it\u2019s totally blank. (Rather than create an HTA body from scratch we simply copied the Scripting Guys\u2019 list of actual accomplishments for the past few years. In retrospect, that might have been a mistake, too.) What we <i>do<\/i> have is a pair of subroutines: <b>Window_onLoad<\/b>, a subroutine that automatically runs each time our HTA is loaded or refreshed, and <b>Window_onBeforeUnload<\/b>, a subroutine that automatically runs right before the HTA is closed. Why do we need these two \u201cauto-run\u201d subroutines? By astonishing coincidence, we were just about to tell you that.<\/p>\n<p>Let\u2019s start with the Window_onLoad subroutine. As you can see, we start off with this intriguing line of code:<\/p>\n<pre class=\"codeSample\">window.offscreenBuffering = True\n<\/pre>\n<p>What we\u2019re doing here is setting the <b>offscreenBuffering<\/b> property to True. <\/p>\n<p>Oh, right; we suppose you probably <i>could<\/i> figure that out for yourselves, couldn\u2019t you? OK, in that case, what we\u2019re <i>really<\/i> doing is telling the HTA that we want it to draw the window (and any items to be contained in that window) off-screen; we don\u2019t want to see the HTA onscreen until it\u2019s ready to be seen. Why do we do that? Well, by default the HTA is going to load in the same spot every time; it\u2019s only after it\u2019s loaded \u2013 and visible \u2013 that the HTA window will move to its last-known coordinates. (We\u2019ll explain all that in a minute.) If this happens on screen, you\u2019ll see the HTA load up, then see it \u201cjump\u201d to a new location. If the HTA loads up off-screen, however, you won\u2019t see the jump; instead, the HTA will simply appear, when ready, at the desired location.<\/p>\n<p>That will all make more sense after you finish reading the column.<\/p>\n<p>That\u2019s right: we <i>did <\/i>promise to tell the truth from now on, didn\u2019t we? Well, we <i>hope<\/i> that will all make more sense after you finish reading the column.<\/p>\n<table class=\"dataTable\" id=\"E1E\" cellSpacing=\"0\" cellPadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" vAlign=\"top\">\n<td class=\"\">\n<p class=\"lastInCell\"><b>Note<\/b>. Good point: we should also mention that we defined a pair of variables, intLeft and intTop. These are global variables; that is, variables available to any subroutine in the HTA. How do we <i>know<\/i> that they\u2019re global variables? That\u2019s easy: they were not defined within a subroutine. Instead, they simply exist as code inside the &lt;SCRIPT&gt; tag.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>So what is exactly <i>is<\/i> happening off-screen? Well, for starters, we define a constant named ForReading and set the value to 1; we\u2019ll use this constant when we open our .INI file for reading.<\/p>\n<table class=\"dataTable\" id=\"ENF\" cellSpacing=\"0\" cellPadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" vAlign=\"top\">\n<td class=\"\">\n<p class=\"lastInCell\"><b>Note<\/b>. Well, that\u2019s another good point: yes, we <i>are<\/i> using a .INI file to tackle this problem. Each time our HTA loads it will read its starting coordinates from the .INI file; each time the HTA unloads it will save its current coordinates to that same .INI file. That\u2019s how the HTA can re-start in the exact same screen position at which it ended.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>After defining the constant, we create an instance of the <b>Scripting.FileSystemObject<\/b> object, then use the <b>OpenTextFile<\/b> method to open the file HTA.ini for reading (we\u2019re assuming that the .INI file is in the same folder as the HTA itself):<\/p>\n<pre class=\"codeSample\">Set objFile = objFSO.OpenTextFile(\"HTA.ini\", ForReading)\n<\/pre>\n<p>Our .INI file consists of a single line, a line that looks something like this:<\/p>\n<pre class=\"codeSample\">0,0\n<\/pre>\n<p>What\u2019s the <b>0,0<\/b> for? Well, the first 0 represents the left-hand edge of our HTA window; in other words, we want the HTA to start out butted-up against the left side of the screen (indented 0 pixels from the left). The second 0 represents the top edge of the HTA window; that means that we want the HTA to start out 0 pixels from the top of the screen. The net effect? By default, the HTA starts off in the upper left-hand corner of the screen. But it doesn\u2019t always <i>have<\/i> to start at 0,0, as you\u2019ll soon see.<\/p>\n<p>In order to set those starting coordinates we use the <b>ReadAll<\/b> method to read the contents of the .INI file, storing that single line in a variable named strContents:<\/p>\n<pre class=\"codeSample\">strContents = objFile.ReadAll\n<\/pre>\n<p>After we close the file, we then use the <b>Split<\/b> function to split the contents on the comma; that gives us an array named arrContents, an array containing the following two elements:<\/p>\n<table class=\"\" cellSpacing=\"0\" cellPadding=\"0\" border=\"0\">\n<tbody>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>0<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>0<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>And now comes the fun part: we use the <b>moveTo<\/b> method to move the HTA window to the specified coordinates, using the value of the first item in the array (index number 0) to represent the left side of the window, and the value of the second item in the array (index number 1) to represent the top of the window: <\/p>\n<pre class=\"codeSample\">window.moveTo arrContents(0), arrContents(1)\n<\/pre>\n<p>We <i>told<\/i> you that would be fun, didn\u2019t we?<\/p>\n<p>So we\u2019ve now solved half our problem: each time the HTA starts up it reads the .INI file, parses the contents, then positions the window according to the values saved in that file. That\u2019s good. Like we said, though, that solves only half the problem. What happens if we move the HTA window? In that case, the left and top coordinates will change and the window will no longer be at 0,0. In turn that means we need to update the .INI file. But how? And, equally important, when?<\/p>\n<p>Let\u2019s start by discussing <i>when<\/i> the .INI file should be updated. The best time to do that is right before the HTA closes; that is, right about the time the Window_onUnload event is fired. Admittedly, we <i>could<\/i> update the .INI file each time the window gets moved, but there\u2019s really no need to do that; after all, it might get moved again, and again, and again; each time we\u2019d have to update the .INI file. Instead, we just wait until the window closes; that way we write the coordinates for the last-known position of the HTA to the .INI file.<\/p>\n<p>Which, of course, is all we care about anyway.<\/p>\n<p>To save those coordinates, we first grab the values of the <b>screenLeft<\/b> and <b>screenTop<\/b> properties and stash them in our two global variables:<\/p>\n<pre class=\"codeSample\">intLeft = window.screenLeft\nintTop = window.screenTop\n<\/pre>\n<p>We then define a constant named ForWriting and set the value to 2; this constant enables us to write to the file HTA.ini. We next create a new instance of the Scripting.FileSystemObject object, then open the file HTA.ini for writing:<\/p>\n<pre class=\"codeSample\">Set objFile = objFSO.OpenTextFile(\"HTA.ini\", ForWriting)\n<\/pre>\n<p>All that\u2019s left now is to replace the existing contents of the file with our left coordinate, a comma, and the top coordinate; that\u2019s what this line of code is for:<\/p>\n<pre class=\"codeSample\">objFile.WriteLine intLeft &amp; \",\" &amp; intTop\n<\/pre>\n<p>And then we close the file and simply wait for the HTA to be restarted. When that happens, the window will appear in the exact same spot where it stood the last time we closed the HTA.<\/p>\n<p>Will that really work? Well, there\u2019s only one way to find out: give it a try and see what happens.<\/p>\n<p>Again, the Scripting Guys would like to apologize for our previous indiscretions. It was never our intention to deceive anyone; we just wanted people to believe something was true even when it obviously wasn\u2019t. <\/p>\n<p>Come on; everyone <i>else<\/i> is doing it these days.<\/p>\n<table class=\"dataTable\" id=\"EKAAC\" cellSpacing=\"0\" cellPadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" vAlign=\"top\">\n<td class=\"\">\n<p class=\"lastInCell\"><b>Note<\/b>. Really, we swear: Scripting Guy Jean Ross actually <i>did<\/i> cracker her head open while attending the MMS Conference. We know that sounds hard to believe. But, then again, you\u2019ve never actually <i>met<\/i> Jean.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! Is there any way to get an HTA to remember its previous position onscreen? Some of my users are very particular about moving an HTA to a specific spot on the screen, then wanting it to reappear at that same spot the next time they run the application. &#8212; DF Hey, DF. [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[3,4,5,30],"class_list":["post-56043","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-scripting-guy","tag-scripting-techniques","tag-vbscript","tag-web-pages-and-htas"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! Is there any way to get an HTA to remember its previous position onscreen? Some of my users are very particular about moving an HTA to a specific spot on the screen, then wanting it to reappear at that same spot the next time they run the application. &#8212; DF Hey, DF. [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/56043","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=56043"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/56043\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=56043"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=56043"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=56043"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}