Problem accessing regedit after updating to Windows 8

At work, I recently upgraded to Windows 8, and I have to admit that the upgrade was very quick and painless, and, so far, I really enjoy the changes.  The new start menu is taking some time to get used to, but all-in-all I enjoy it.  I recently had a reason to modify the registry, and I got the following error:

image

I thought this was odd because I am an administrator on my box.  I even added myself to the local administrators group explicitly, and chose “Run As Administrator” from the context menu, but the error message still persisted.

Here are the steps I took to fix it:

  1. Open File Explorer (at some point, Windows Explorer needed a name change?) and navigate to C:\Windows\
  2. Right click on regedit.exe and select Properties
  3. Go to the Security tab and click the Advanced button so this screen appears:
    image
  4. Click the Continue button with the shield
  5. Click the Add button and the following window appears:
    image
  6. Click “Select a principle” at the top and the following window appears:
    image
  7. Enter your network ID, click Check Names just to make sure, and then click OK
  8. Click OK, OK, Yes

Now, you can run regedit.exe as normal.

I hope this post has helped you.  Please leave a comment below if you found this post helpful.

Forcing Save As in Microsoft Word

My wife came to me a few weeks ago with a problem: When she would open a word document attached to an e-mail sent to her Yahoo account, she would sometimes lose the changes made to the document when she closed it.  Even though she clicked ‘yes’ when the program asked if she wanted to save her changes, the document was being saved to a temporary internet file that she couldn’t access once the document was closed.

There are several solutions to this problem, but my wife wasn’t particularly enthused about changing her online habits.  And, why shouldn’t she expect her document to be found after hitting the save button?  Why doesn’t MS Word recognize that the open document is in Temporary Internet Files and perform a Save As instead of a Save?  Word should, but it doesn’t, so I wrote a Word Add-In to do the trick for her.

Our solution should force a Save As if the Save function is invoked, but do not interfere if the Save As is invoked…and of course, ignore any document that is not in the Temporary Internet Files location.  I knew it would be easy, but I didn’t realize just how easy it would be. 

I’m using VS 2012 these days, but I did this in VS 2010 because we use Office 2007, and VS 2012 didn’t have (or I couldn’t find) the Office 2007 Add-In templates…so, open up VS 2010 and create a new project, choose Installed Templates –>Visual C# –>Office –>2007—>Word 2007 Add-In.

image

The template opens up with two events already wired-up, the Startup and Shutdown events.  We need to add the DocumentBeforeSave event, so first create the function:

private void Application_DocumentBeforeSave(Word.Document Doc, 
                                            ref bool SaveAsUi, 
                                            ref bool Cancel)
{
}

Doc is the document that is open.  SaveAsUi will be true if the SaveAs was invoked, false if it’s just Save.  Cancel, you can set to true if you want to cancel the save event.  One thing to remember is that neither the SaveAsUi or the Cancel properties are read-only.  You can set them to true or false; however, setting SaveAsUi to true doesn’t do anything.  It’s for your informational purposes only.  So, just remember to treat SaveAsUi as read-only, and treat Cancel as write only and you won’t get frustrated or confused.

Now, we need to add the event handler to our application.  So, put this code in the ThisAddIn_Startup function:

this.Application.DocumentBeforeSave +=
    new Word.ApplicationEvents4_DocumentBeforeSaveEventHandler(
           Application_DocumentBeforeSave);

Now, remember that we need to ignore the SaveAs event, and we have this handy variable called SaveAsUi, which tells us if we in a SaveAs event.  So, let’s start with that by adding an If statement to our DocumentBeforeSave function:

if (!SaveAsUi)
{
}

If SaveAsUi is false, then we need to check our location.  We only want to intercede if we are inside the “Temporary Internet Files” folder, so place that check inside the if statement above:

if (Doc.Path.Contains("Temporary Internet Files"))
{
}

If both conditions are true, then we need to invoke the Save As dialog box.  The only problem here is that I was not able to find a way to invoke the Save As dialog box, which means we have to make our own.   If you go to File –> Save As from just about any program, you will see a drop-down box labeled File Type.  This is populated by a property called “Filter” on the SaveFileDialog control.  If you happen to look at the Filter for MS Word 2007, you will see that there are 18 items listed.  I didn’t want to type “filter += foo” 18 times, so I created a dictionary.  We, of course, also need a SaveFileDialog control.  So first add the following using statement to your class, and then add to two properties.

using System.Windows.Forms;
private Dictionary<string, string> SaveAsFilters { get; set; }
private SaveFileDialog SaveAsDialog { get; set; }

The idea is to populate the dictionary with the filters and then just loop over the dictionary to populate the dialogs filter property.  So, inside the ThisAddIn_Startup function, include the following code.

First, populate the dictionary:

this.SaveAsFilters = new Dictionary<string, string>
{
    { "Word Document", "*.docx" },
    { "Word Macro-Enabled Document", "*.docm" },
    { "Word 97-2003 Document", "*.doc" },
    { "Word Template", "*.dotx" },
    { "Word Macro-Enabled Template", "*.dotm" },
    { "Word 97-2003 Template", "*.dot" },
    { "PDF", "*.pdf" },
    { "XPS Document", "*.xps" },
    { "Single File Web Page", "*.mht;*.mhtml" },
    { "Web Page", "*.htm;*.html" },
    { "Web Page, Filtered", "*.htm;*.html" },
    { "Rich Text Format", "*.rtf" },
    { "Plain Text", "*.txt" },
    { "Word XML Document", "*.xml" },
    { "Word 2003 XML Document", "*.xml" },
    { "OpenDocument Text", "*.odt" },
    { "Works 6.0 - 9.0", "*.wps" },
    { "Works 7.0", "*.wps" }
};

As of Word 2007, this is all the filters in Words Save-As dialog.

Even though it’s just a string, I ran into some problems appending to the Filter property, so we will create a string and append to it.  We’ll also include a counter so that we can include a pipe (“|”) character in between each filter.

int x = 1;
string filterText = string.Empty;
foreach (KeyValuePair<string, string> filter in this.SaveAsFilters)
{
    filterText += filter.Key + " (" + filter.Value + ")|" + 
                                                       filter.Value;

    //add the pipe to seperate the filters
    if (x != this.SaveAsFilters.Count())
    {
        filterText += "|";
    }
    x++;
}

this.SaveAsDialog.Filter = filterText;

We want our dialog to look and feel as much like Microsoft Word as possible, so we set the following properties:

this.SaveAsDialog.Filter = filterText;
this.SaveAsDialog.Title = "Save As";
this.SaveAsDialog.SupportMultiDottedExtensions = true;
this.SaveAsDialog.OverwritePrompt = true;
this.SaveAsDialog.InitialDirectory = Environment.GetFolderPath(
                              Environment.SpecialFolder.MyDocuments);
this.SaveAsDialog.AutoUpgradeEnabled = true;
this.SaveAsDialog.AddExtension = true;
this.SaveAsDialog.DefaultExt = "docx";

Now that we have everything in place, we can finish off our DocumentBeforeSave event by including the following code inside our nested if statement:

if (this.SaveAsDialog.ShowDialog() == DialogResult.OK)
{
    Doc.SaveAs(this.SaveAsDialog.FileName);
}

Only act if the user presses the “Save” button, and when they do call the Documents SaveAs method, passing in the filename and path that the user selected.  This will save the document, but it still doesn’t feel just right.  If I call SaveAs from any program (MS Word included), the current document is changed to reflect the newly created document.  Calling the SaveAs function in this manner does not do that, so we need some code to mimic that behavior.

Cancel = true;
this.Application.Documents.Close();
this.Application.Documents.Open(this.SaveAsDialog.FileName);

First we cancel the calling save event, then we can close the current document and then open the new document.

And that’s it, now we have created our Word Add-In.  Before I show you the code in it’s entirety, we need to walk through the publish process.  Word Add-Ins are published using ClickOnce, and because it’s integrating into Word, it requires a certification to go along with it.  I didn’t want to spend the money on a Signed Cert., so I published it without one.  It’s easy to do if you can control the computer you are installing to.

First thing is to set up ClickOnce.  Right-click on your project file in Soultion Explorer and choose Properties, and then click on the Publish Tab:

image

The first box is where the deployment files will be uploaded to.  I use ftp because I’m sending this to my website, but you could also choose to use a UNC path.  The nested box below that is where to go to download the installation files.  So, I upload to an ftp site, and then point to a webpage for the actual deployment.  In my case it’s http://www.karrapps.com/tempsaveintercept/TempSaveIntercept.vsto.

By default, the prerequisite options are set to allow the program to download and install any missing prereqs from each vendor’s web site.  I recommend leaving it this way.  If you need to change this behavior though, just click the Prerequisites button.

Your add-in will check for updates “every time the customization runs” by default.  For my purposes this isn’t really that important, so I clicked the Update button and set it to check every 1 day.  You can also select to never check for updates.

The Options buttons contains two sections; Description and Office Settings.  Here you can select a publishing language, define the publishers author, define the product name, and provide a support url.  Office settings include Solution name, and description as well as a choice between loading the Add-In at startup or on demand.

Once the settings are to your liking, just click the Publish Now button, address any prompts that come up (authentication prompts for example), and your ready for the client PC.

Here’s where we get around the cert.  This method will still prompt the user with a warning that the installation can’t be trusted, but it works and is free.  The website domain will need to be added as a trusted location, you can do that under Internet Options –> Security—>Trusted Sites—>Sites button.  So, I add http://karrapps.com as a trusted site.

Then, download and run setup.exe from the Installation Folder and that’s it.  The Add-In is automatically installed and enabled inside MS Word.

Now, the code in it’s entirety:

namespace TempSaveIntercept
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Forms;
    using Word = Microsoft.Office.Interop.Word;

    public partial class ThisAddIn
    {
        private Dictionary<string, string> SaveAsFilters;
        private SaveFileDialog SaveAsDialog = new SaveFileDialog();

        private void ThisAddIn_Startup(object sender, 
                                       System.EventArgs e)
        {
            this.Application.DocumentBeforeSave +=
         new Word.ApplicationEvents4_DocumentBeforeSaveEventHandler(
                                    Application_DocumentBeforeSave);

            this.SaveAsFilters = new Dictionary<string, string>
            {
                { "Word Document", "*.docx" },
                { "Word Macro-Enabled Document", "*.docm" },
                { "Word 97-2003 Document", "*.doc" },
                { "Word Template", "*.dotx" },
                { "Word Macro-Enabled Template", "*.dotm" },
                { "Word 97-2003 Template", "*.dot" },
                { "PDF", "*.pdf" },
                { "XPS Document", "*.xps" },
                { "Single File Web Page", "*.mht;*.mhtml" },
                { "Web Page", "*.htm;*.html" },
                { "Web Page, Filtered", "*.htm;*.html" },
                { "Rich Text Format", "*.rtf" },
                { "Plain Text", "*.txt" },
                { "Word XML Document", "*.xml" },
                { "Word 2003 XML Document", "*.xml" },
                { "OpenDocument Text", "*.odt" },
                { "Works 6.0 - 9.0", "*.wps" },
                { "Works 7.0", "*.wps" }
            };

            int x = 1;
            string filterText = string.Empty;
            foreach (KeyValuePair<string, string> filter in 
                                                 this.SaveAsFilters)
            {
                filterText += filter.Key + " (" + filter.Value + 
                                                 ")|" + filter.Value;

                //add the pipe to seperate the filters
                if (x != this.SaveAsFilters.Count())
                {
                    filterText += "|";
                }
                x++;
            }

            this.SaveAsDialog.Filter = filterText;
            this.SaveAsDialog.Title = "Save As";
            this.SaveAsDialog.SupportMultiDottedExtensions = true;
            this.SaveAsDialog.OverwritePrompt = true;
            this.SaveAsDialog.InitialDirectory = 
    Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            this.SaveAsDialog.AutoUpgradeEnabled = true;
            this.SaveAsDialog.AddExtension = true;
            this.SaveAsDialog.DefaultExt = "docx";
        }

        private void ThisAddIn_Shutdown(object sender, 
                                        System.EventArgs e)
        {
        }

        private void Application_DocumentBeforeSave(Word.Document Doc,
                                                    ref bool SaveAsUi,
                                                    ref bool Cancel)
        {
            if (!SaveAsUi)
            {
                if (Doc.Path.Contains("Temporary Internet Files"))
                {
                    if (this.SaveAsDialog.ShowDialog() == 
                                                     DialogResult.OK)
                    {
                        Doc.SaveAs(this.SaveAsDialog.FileName);
                        Cancel = true;
                        this.Application.Documents.Close();
                        this.Application.Documents.Open(
                                         this.SaveAsDialog.FileName);
                    }
                }
            }
        }

        #region VSTO generated code
                …………………………
        #endregion
    }
}

Please note that I had to adjust the spacing to make everything fit on the page, but you get the idea Winking smile

Please leave your comments below.  I would love to hear from you.