Carlos Quintero (Microsoft MVP) blog

Visual Studio Extensibility: macros, add-ins, SDK packages

If you are trying to retrieve attributes in the assemblyinfo file, it's better to use the ProjectItem.FileCodeModel rather than the Project.CodeModel:

BUG: EnvDTE.Project.CodeModel doesn't retrieve attributes in the AssemblyInfo file
http://www.mztools.com/articles/2009/MZ2009014.aspx

The bug report for Microsoft is here:

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=471708

Posted by carlosq | with no comments

It took me quite a lot of time to fix the problem of Error 0x80070002 "The system cannot find the file specified" using PEVerify.exe to verify add-in with referenced assemblies from Visual Studio not in the GAC. I found the problem yesterday Sunday afternoon when I was with my laptop at a Starbucks with no connection to Internet other than a very weak GPRS connection with my mobile phone, so I could only get on the web that the solution was to use the codeBase tag in a .config file. The file that I used was:

<?xml version="1.0" ?>
<configuration>
<runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
         <dependentAssembly>
            <assemblyIdentity name="Microsoft.VisualStudio.Data.Interop" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
            <codeBase version="8.0.0.0" href="C:\Program Files\Microsoft Visual Studio 8\Common7\IDE" />
         </dependentAssembly>
      </assemblyBinding>
   </runtime>
</configuration>

Using this file I got this other error:

0x80070005 "Access Denied"

rather than:

0x80070002 "The system cannot find the file specified".

So today with more Internet connectivity I have been investigating the problem. The only reference to this problem was Debugging Assembly Loading Failures, where Suzzane Cook stated the obvious, to check file locks without shared-read access and ACLs. But this was not the problem.

The fusion log showed this:

LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL file:///C:/Program Files/Microsoft Visual Studio 8/Common7/IDE.
LOG: Assembly download was successful. Attempting setup of file: C:\Program Files\Microsoft Visual Studio 8\Common7\IDE
LOG: Entering run-from-source setup phase.
ERR: Error extracting manifest import from file (hr = 0x80070005).
ERR: Failed to complete setup of assembly (hr = 0x80070005). Probing terminated.

So I was clueless until I found the string "ERR: Error extracting manifest import from file" in a .rc file inside  www.koders.com, the site that has the source code of some open source portions of the .NET Framework CLR and tools. The string led me to the identifier ID_FUSLOG_MANIFEST_EXTRACT_FAILURE which in turn led me to the following code in the bindhelpers.cpp file:

HRESULT BindToSystem(IAssemblyName *pNameSystem,
                     LPCWSTR pwzSystemDirectory,
                     IUnknown *pUnk,
                     IAssembly **ppAsmOut,
                     IAssembly **ppNIAsmOut,
                     IFusionBindLog **ppdbglog)
{
    HRESULT hr = S_OK;
    IAssembly *pAsm = NULL;
    CAssembly *pCAsm = NULL;
    CNativeImageAssembly *pAsmNI = NULL;       
    DWORD dwSize = 0;
    IAssemblyManifestImport *pAsmImport = NULL;
    INativeImageEvaluate *pNIEva = NULL;
    WCHAR wzManifestFilePath[MAX_PATH];
    IAssemblyName *pName = NULL;
    static BOOL bCalled = FALSE;
    CDebugLog *pdbglog = NULL;
    BOOL    bFoundInDevOverride = FALSE;
   
    MEMORY_REPORT_CONTEXT_SCOPE("FusionBindToSystem");

    if (!pNameSystem || !ppAsmOut || CAssemblyName::IsPartial(pNameSystem) || !CAssemblyName::IsStronglyNamed(pNameSystem) || !pwzSystemDirectory){
        return E_INVALIDARG;
    }

    *ppAsmOut = NULL;

    // should only be called once.
    if (bCalled) {
        *ppAsmOut = g_pSystemAssembly;
        if (g_pSystemAssembly) {
            g_pSystemAssembly->AddRef();
            return S_OK;
        }
        else {
            return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
        }
    }

    if (IsLoggingNeeded()) {
        CDebugLog::Create(NULL, pNameSystem, NULL, &pdbglog);
    }

    wzManifestFilePath[0]= L'\0';

    if (pUnk) {
        hr = pUnk->QueryInterface(IID_INativeImageEvaluate, (void **)&pNIEva);
        if (FAILED(hr)) {
            goto Exit;
        }
    }

    // temporary IAssemblyName for mscorlib
    g_pSystemAssemblyName = pNameSystem;
    g_pSystemAssemblyName->AddRef();


    // we are here because we cannot find the custom assembly,
    // or we are not asked for a custom assembly.

    if (!bFoundInDevOverride) {
        hr = CAssemblyName::CloneForBind(pNameSystem, &pName);
        if (FAILED(hr)) {
            goto Exit;
        }

        hr = CreateAssemblyFromCacheLookup(NULL, pName, ppAsmOut, NULL);
        if (FAILED(hr) && hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) {
            goto Exit;
        }
       
        if (hr == S_OK) {
            DEBUGOUT(pdbglog, 1, ID_FUSLOG_CACHE_LOOKUP_SUCCESS);
        }
        else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)){
            DEBUGOUT(pdbglog, 1, ID_FUSLOG_ASSEMBLY_LOOKUP_FAILURE);
        }
       
        if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) {
            dwSize = MAX_PATH;
            hr = StringCchPrintf(wzManifestFilePath, MAX_PATH, L"%ws%ws.dll", pwzSystemDirectory, SYSTEM_ASSEMBLY_NAME);
            if (FAILED(hr)) {
                goto Exit;
            }

            DEBUGOUT1(pdbglog, 0, ID_FUSLOG_ATTEMPT_NEW_DOWNLOAD, wzManifestFilePath);

            hr = CreateAssemblyFromManifestFile(wzManifestFilePath, NULL, NULL, ppAsmOut);
            if (FAILED(hr)) {
                DEBUGOUT1(pdbglog, 1, ID_FUSLOG_MANIFEST_EXTRACT_FAILURE, hr);

                goto Exit;
            }
        }
    }


Exit:

    if (pdbglog) {
        pdbglog->SetResultCode(FUSION_BIND_LOG_CATEGORY_DEFAULT, hr);
        DUMPDEBUGLOG(pdbglog, g_dwLogLevel);
        DUMPDEBUGLOGNGEN(pdbglog, g_dwLogLevel);
        if (ppdbglog) {
            *ppdbglog = pdbglog;
            pdbglog->AddRef();
        }
    }

    SAFERELEASE(g_pSystemAssemblyName);

    if (SUCCEEDED(hr)) {
        pCAsm = static_cast<CAssembly *>(*ppAsmOut); // dynamic_cast
        pCAsm->SetIsSystemAssembly(TRUE);

        g_pSystemAssembly = *ppAsmOut;
        g_pSystemAssembly->AddRef();
        g_pSystemAssembly->GetAssemblyNameDef(&g_pSystemAssemblyName);
    }

    if (FAILED(hr)) {
        SAFERELEASE(*ppAsmOut);
    }

    SAFERELEASE(pdbglog);
    SAFERELEASE(pAsmImport);
    SAFERELEASE(pAsm);
    SAFERELEASE(pAsmNI);
    SAFERELEASE(pNIEva);
    SAFERELEASE(pName);

    bCalled = TRUE;
    return hr;
}

I have marked in bold the relevant code. It was not until I saw the name of the function CreateAssemblyFromManifestFile when I realized that I had to specify the full file name and not the folder of the assembly in the .config file. Once modified to the following it worked without errors:

<?xml version="1.0" ?>
<configuration>
<runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
         <dependentAssembly>
            <assemblyIdentity name="Microsoft.VisualStudio.Data.Interop" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
            <codeBase version="8.0.0.0" href="C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\Microsoft.VisualStudio.Data.Interop.dll" />
         </dependentAssembly>
      </assemblyBinding>
   </runtime>
</configuration>

The "access denied" error was misleading since it would be more useful to keep showing the "file not found" error.

Now, imagine the time that you could save diagnosing problems in extensions for Visual Studio if you could have access to the Visual Studio source code, even without being able to debug, just debugging with the brain as I did...

Posted by carlosq | with no comments

I am currently working on a new version of MZ-Tools and yesterday I updated its build script. When running it, to my surprise, I found the following error in the step that verifies the assembly with the peverify.exe tool after the obfuscation step:

Error 0x80070002 "The system cannot find the file specified"

After diagnosing the problem with the Assembly Binding Log Viewer, I found that the file in question was the Microsoft.VisualStudio.Data.Interop.dll assembly that this version of MZ-Tools will reference for one of its features. This file, on the contrary to others such as Microsoft.VisualStudio.Shell.Interop.8.0.dll, does not reside on the Global Assembly Cache (GAC) and, as any Visual Studio assembly, should not be distributed, the VS IDE will find it. However, when using the peverify.exe tool, that referenced assembly is not found.

Fortunately Microsoft has ways to fix for all these problems through a .config file. Long time ago I posted how to fix the problem PEVerify.exe causes problem with EnvDTE.dll verifying Visual Studio 2005 add-ins and this new article explains how to fix this other problem:

PRB: PEVerify.exe causes problem verifying add-in with referenced assemblies from Visual Studio not in the GAC
http://www.mztools.com/articles/2009/MZ2009013.aspx

Posted by carlosq | 1 comment(s)

From time to time I blog about strange cases of errors when loading add-ins for Visual Studio. At least three of them have been about errors with hexadecimal codes such as 8013XXXX:

The strange case of <Unknown Error> 8013150A loading a Visual Studio add-in
http://msmvps.com/blogs/carlosq/archive/2009/03/24/the-strange-case-of-lt-unknown-error-gt-8013150a-loading-a-visual-studio-add-in.aspx

The strange case of <Unknown Error> 8013141A loading a Visual Studio add-in
http://msmvps.com/blogs/carlosq/archive/2008/11/28/the-strange-case-of-lt-unknown-error-gt-8013141a-loading-a-visual-studio-add-in.aspx

The strange case of error 80131018 loading a Visual Studio add-in
http://msmvps.com/blogs/carlosq/archive/2007/03/23/the-strange-case-of-error-80131018-loading-a-visual-studio-add-in.aspx

When those errors happen, the description that Visual Studio shows is "Unknown Error". I'm sure that Visual Studio could do a better job getting the description of such errors, but meantime you have to Google them, which usually gets no much meaningful information. If you ever encounter such error that you don't get much information about, here is what you can do:

1) Those errors are coded in the corerror.h file. You have an online copy of that file at the Koders web site www.koders.com: enter "file:corerror.h" (without quotes) as your search term to get the file.

2) You will notice that the file contains a lot of error definitions such as EMAKEHR(0x101A)

3) So, you really need to search for the last 4 hexadecimal digits of your error. For example for the error 8013141A you would get:

#define CORSEC_E_INVALID_STRONGNAME     EMAKEHR(0x141a)         // Strong name validation failed

and then you know that the error is related to an invalid strong name.

If you are curious, the EMAKEHR macro is defined as:

#define FACILITY_URT            0x13
#endif
#ifndef EMAKEHR
#define SMAKEHR(val) MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_URT, val)
#define EMAKEHR(val) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_URT, val)

So you now know where the 0x13 digits (3th and 4th) of all those errors come from.

Hope this helps.

Posted by carlosq | with no comments

These days I have been playing a lot with resource images in managed satellite dlls and one thing that I was noticing sporadically was that the Add Resource \ New Image menu on the toolbar of the document window of a resource.resx file was empty, while it should have the typical "Bmp image", "Png image", etc. menu entries. Since I was playing with 32-bit bitmaps images with transparency in the alpha channel that cannot be created with Visual Studio, most of the time I was using a 3rd party bitmap editor and using the Add Resource \ Add Existing File... menu. But nonetheless, I was intrigued by the missing submenus in the New Image menu. Today that I finished my investigation of the managed satellite dlls, I decided to investigate the issue.

The first thing that I noticed was that the issue was not reported on the web, or maybe only mentioned once without a solution, which was strange because I could reproduce the problem on two computers on mine. I was clueless when I discovered by chance that the problem happened only when I had my MZ-Tools add-in loaded in Visual Studio on startup. After a few minutes of debugging I isolated the problem: it happened when the toolbar of the add-in was created, so I was able to create a minimal add-in to reproduce the problem and report it to Microsoft:

The Add Resource\New Image menu empty when VS add-in creates a toolbar
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=470755

The problem happens with VS 2005 and 2008, but it is fixed in VS 2010 Beta 1, likely due to its new WPF-based commandbars.

Posted by carlosq | with no comments

Recently I have migrated the next version of MZ-Tools for Visual Studio .NET that I am working on from COM-based add-in to XML-based add-in (giving up Visual Studio .NET 2002/2003 support). I tried to do it many months ago but I gave up because moving to XML-based add-in meant also moving from native resource DLL to managed resource DLL, and I didn't want to do that at that time, I just wanted to get rid of COM. But tired of the two bugs in the Visual Studio 2005/2008 Add-In Managers with COM-addins (the former one only fixed in VS 2008 and the latter one reopened and again under investigation after strong discussion with Microsoft), and tired of the problems of COM and transparent bitmaps, etc. finally I have moved to a managed satellite DLL.

AFAIK, the only official documentation from Microsoft to build a managed satellite dll for a XML add-in is the following gem in MSDN, that involves using command-line tools such as resgen.exe (Resource File Generator) or al.exe (Assembly Linker) and Windows tools such as Notepad:

How to: Display a Custom Icon on the Add-in Button
http://msdn.microsoft.com/en-us/library/ms228771(VS.80).aspx

How they can sleep well with that is beyond me ;-). I am currently trying to convince the Program Manager in charge of this to support resources in the own dll of the add-in for VS 2010 so maybe in 2014 your add-in targeting VS 2010, VS 2012 and VS 2014 can get rid of the resource dll...

Of course there is a much better way to create a resource dll that doesn't involve command-line tools, that is, a class library project in the same solution of the add-in that provides the resources. I have updated the following article to cover this scenario:

HOWTO: Creating custom pictures for Visual Studio .NET add-ins commands, buttons and toolwindows.
http://www.mztools.com/articles/2005/MZ2005007.aspx

I have updated also the section about toolwindow bitmaps to provide better information. I have not included yet information about VS 2010 but you have these other posts:

Solved: transparent bitmaps in add-in toolwindows of VS 2010 (Beta 1)

and

Solved: transparent bitmaps in add-in commands of VS 2010 (Beta 1)

I will update the article when the current two bugs under investigation are solved in some way or another and VS 2010 gets release candidate status.

Posted by carlosq | 1 comment(s)

In the previous post I explained how to get transparent bitmaps for add-in commands in VS 2010 Beta 1 and previous versions. Now it is the turn of toolwindow bitmaps. Again, if you have a .NET 2.0 add-in that uses XML registration and a managed satellite DLL and targets VS 2005, 2008 and 2010 Beta 1, the situation is as follows:

1) Toolwindow bitmaps for VS 2005:

- Use either:

   * A 32-bit bitmap with transparency in the alpha channel.
   * A 24-bit bitmap with RGB=255,0,255 (magenta) as transparent color

- Call EnvDTE.Window.SetTabPicture(bitmap.GetHbitmap) (for some reason passing bitmap.GetHbitmap().ToInt32 causes System.ArgumentException: Value does not fall within the expected range)
- Call EnvDTE.Window.Visible = True (this must be done after setting the toolwindow picture)

2) Toolwindow bitmaps for VS 2008:

- Use either:

   * A 32-bit bitmap with transparency in the alpha channel.
   * If the color depth of the screen is:
        - 16-bit, you can use a 24-bit bitmap with RGB=0,254,0 (almost pure green) or a 24-bit bitmap with RGB=255,0,255 (magenta) as transparent color
        - 24-bit: I couldn't test this case on my computers.
        - 32-bit: you need to make the bitmap transparent calling bitmap.MakeTransparent(<background color>).

- Call EnvDTE.Window.SetTabPicture(bitmap.GetHbitmap().ToInt32()) (for some reason passing just bitmap.GetHbitmap causes System.ArgumentException. You need to convert the IntPtr to integer)
- Call EnvDTE.Window.Visible = True (this must be done after setting the toolwindow picture)

3) Toolwindow bitmaps for VS 2010 Beta 1:

- Use either.
   * A 32-bit bitmap with transparency in the alpha channel. Due to a bug that I have already reported, in this case the toolwindow picture shows transparency when focused, but doesn't when not focused.
   * A 24-bit bitmap with RGB=0,254,0 (almost pure green) as transparent color
   * A 24-bit bitmap with RGB=255,0,255 (magenta) as transparent color

- Call either EnvDTE.Window.SetTabPicture(bitmap.GetHbitmap()) or EnvDTE.Window.SetTabPicture(bitmap.GetHbitmap().ToInt32())
- Call EnvDTE.Window.Visible = True (this must be done after setting the toolwindow picture)

Bottom line: if the bug mentioned above with VS 2010 and 32-bit bitmap with transparency in the alpha channel is fixed for VS 2010 final release, you will be able to use 32-bit bitmap with transparency in the alpha channel in the three VS versions, but taking into account that sometimes you need to use the IntPtr value returned by GetHBitmap, and others its Int32 value.

I hope the information above is accurate because it is really messing to test all cases. Let me know if you can corroborate or not.

Posted by carlosq | with no comments

After my rant of yesterday about Bitmap transparency nightmares at Microsoft too I have continued today with my testings and finally I got transparent bitmaps in commands of add-ins for VS 2010 Beta 1. If you have a .NET 2.0 add-in that uses XML registration and a managed satellite DLL and targets VS 2005, 2008 and 2010, the situation is as follows:

1) Command bitmaps for VS 2005 and VS 2008:

- They need to use RGB=0,254,0 (almost pure green) as transparent color. This has been so since VS.NET 2002.

- They do not support 32-bit bitmaps (which support built-in transparency through the alpha channel). You get white background instead.

2) Command bitmaps for VS 2010 Beta 1:

- They do not use RGB=0,254,0 (almost pure green) as transparent color. You get a green background instead. This is a lack of backwards compatibility that I reported some weeks ago through Microsoft Connect. At the time of this writing, the bug is under investigation but it might well be closed as "by design" because it seems that Microsoft is finally solving the problem for good supporting built-in transparency with 32-bit bitmaps and removing old hacks such as magenta or green background as their own user interface guidelines suggest.

- They do support 32-bit bitmaps (which support built-in transparency through the alpha channel). Support for 32-bit bitmaps in add-in commands is something new that didn't work in previous versions of Visual Studio.

Bottom line: if nothing changes from Beta 1 to final release, your satellite managed Dll will need to include two sets of bitmaps: ones with 24-bit and RGB=0,254,0 background for VS 2005/2008 and other with 32-bit bitmaps with transparency in alpha channel for VS 2010. This is so because you don't have any chance of manipulating the bitmap in your code when suplying bitmaps Ids to the AddNamedCommand method, on the contrary to the Window.SetTabPicture method of toolwindows (which will be the subject of another future post).

While it would be good to support the old way too a couple of VS releases, I don't care suplying two sets of bitmaps because finally this is going in the good direction, that is, built-in transparency without magic tricks.

There is a little problem though: it can be tricky to get an editor that support 32-bit bitmaps correctly. First, some editors allow "4-bit", "8-bit", and "True Color" bitmaps, where it is not clear if "True Color" means 24-bit or 32-bit (with alpha channel). Most of the time it means 24-bit, though. Second, some editors don't support 32-bit bitmaps at all: forget MS Paint and others such as the Visual Studio bitmap editor (it seems). For this purpose I have used the wonderful Axialis IconWorkshop icon editor. Other modern icon editors may work too. The procedure is the following:

- Create a 16x16 icon with RGB/Alpha Channel (RGB/A - 32 bits) depth color

- Draw your icon leaving the transparent background

- Click File\Export...\Bitmap Image. When prompted, select "Preserve Transparency information (saved to 32 bpp)".

Now, if the add-in could supply the bitmaps in its own Dll rather than in a satellite Dll...

Posted by carlosq | 1 comment(s)

While trying to find a workaround for the Visual Studio 2010 Beta 1 problem with command bitmaps in add-ins, and sick about the issue of transparency in Visual Studio, today I have taken a look at the Microsoft Visual Studio 2010 User Interface Guidelines that are available here:

Microsoft Visual Studio 2010 User Interface Guidelines
http://code.msdn.microsoft.com/VS2010UX/Release/ProjectReleases.aspx?ReleaseId=2743

It's impressive the level of effort and details that Microsoft puts to get the Visual Studio interface right from point of view of "look & feel".

But the thing that I would like to comment about is the section 11.01.01 "Creating High Color Artwork" and subsequent ones , which I have read with a mixed feeling of joy and horror: it's incredible how many different ways to get bitmap transparency are used in Visual Studio:

- Icons (with built-in transparency)

- 24-bit bitmaps with transparent color RGB=255,0,255 (magenta)

- 24-bit bitmaps with transparent color RGB=0, 255, 0 (lime green)

- Any of the two previous at the same time

- 24-bit bitmaps with transparent color RGB=0, 254, 0 (almost lime green).

- 32-bit bitmaps with built-in transparency (alpha channel)

- The bottom-left pixel (x: 0, y: height - 1. Which sometimes needs to be magenta too!

- Code to make bitmaps transparent

- Etc.

Then, do not use Microsoft Paint, it can alter the bitmap header and color table. When using Photoshop, do not click File\Save. Do not click File\Export. Do click File\Save As. And be aware of copy/paste operations... BTW, any mention to Visual Studio resource editor?

All that explained, you find this little gem: "high-color artwork integrates seamlessly into Visual Studio 80% of the time. If you're the unfortunate developer who falls into the 20% case, this section is for you."

The section is 11.02.04 "Debugging High-Color Artwork", where you are provided with some images (I'm still figuring out how to extract them from a IE-only .mht file) that you can use to diagnose your transparency problem against 7 different causes (including one that can put your bitmap upside down!), that can appear combined, and that can be something new...

If this is the scenario inside Microsoft Visual Studio, it's no wonder that add-ins (which are not part of Visual Studio on the contrary to packages) have always problems in each new version of Visual Studio for the two only things that they need transparency: command pictures and toolwindow pictures.

All this mess is caused by a problem that was solved when VS.NET 2002 was developed:

"Historically, developers only had twenty colors to work with: base 16 and four shades of gray. In Visual Studio 2002 that increased to 255 colors; however, most artwork was left at twenty colors. Because of the twenty-color limitation, early developers were forced to get creative in their use of images and palettes."

(it seems that they were too creative...)

and then:

"Even though high-color has been around for many years now, we still need to work to remove these historic hacks and assumptions."

To the Microsoft Visual Studio Team: how about removing all them for this very Visual Studio 2010 version? Keep it really simple: either icons, or 32-bit bitmaps (built-in transparency in both cases). No more magic colors. No more magic pixels coordinates. Given that we are forced to change our add-ins to get transparency on each VS version, you could sacrifice backwards compatibility and get this fixed for good.

Posted by carlosq | with no comments

If you have coded many add-ins or a complex add-in, chances are that you have encountered the dreaded System.ArgumentException "Value does not fall within the expected range." when adding commands, buttons, commandbars, etc. Most of the AddXXX methods of the automation model receive so many parameters (many ones optional) that one little mistake and you get that exception. The problem is that you can't know where is the little mistake because you aren't provided the offending parameter and a hint of the problem.

I have filed a suggestion to Microsoft to make our debugging time easier:

Provide better error information in automation model (EnvDTE) for add-ins
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=469337

You can vote for it if you hate to waste your time guessing...

Posted by carlosq | with no comments

Although I don't use permanent commandbars in my MZ-Tools but temporary ones, I became aware of a bug when writing the samples that use permanent user interface of the article HOWTO: Adding buttons, commandbars and toolbars to Visual Studio .NET from an add-in, and I mentioned it in this article and this post. The bug is that executing devenv.exe /resetaddin resets commands and CommandBarButtons, but not permanent commandbars.

Today I finally have reported it to Microsoft, just in case they want to fix it for VS 2010:

devenv.exe /resetaddin doesn't reset permanent add-in commandbars
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=469322

If you are affected by this problem, vote for it there.

As a workaround, remove the commandbar by code in the ext_cm_UISetup phase of the OnConnection method before adding it again.

BTW, if you are curious about where VS persists information of commands, commandbars, etc., it is the file CmdUI.prf stored here (Windows XP):

C:\Documents and Settings\<user>\Application Data\Microsoft\VisualStudio\<version>\1033

where <user> is your Windows user name and <version> is:

7.0 (VS.NET 2002)
7.1 (VS.NET 2003)
8.0 (VS 2005)
9.0 (VS 2008)
10.0 (VS 2010)

Deleting that file removes all the commands, buttons, commandbars, etc. of add-ins or user customizations.

Posted by carlosq | with no comments

I have updated the following MZ-Tools Series articles to fix/explain better some things, provide C# code some cases, cover Windows Vista folders, cover Visual Studio 2008/2010 in some other cases, etc:

HOWTO: Removing commands and UI elements during Visual Studio .NET add-in uninstallation
http://www.mztools.com/Articles/2005/MZ2005002.aspx

HOWTO: Reset a Visual Studio add-in
http://www.mztools.com/Articles/2006/MZ2006014.aspx

HOWTO: Get rid of a Visual Studio add-in
http://www.mztools.com/Articles/2006/MZ2006018.aspx

INFO: Visual Studio .NET Add-In Commands Disappear On Next Session
http://www.mztools.com/Articles/2005/MZ2005014.aspx

Posted by carlosq | with no comments

Since I have no much hope of getting a new EnvDTE100.Commands.AddNamedCommand3 that accepts an icon as parameter rather than a resource id, I have filed a new feature request to at least get rid of the satellite DLL just making EnvDTE80.Commands.AddNamedCommand2 to search for resources in the own add-in dll, which wouldn't require a new method or a change in the method signature:

Make EnvDTE80.Commands.AddNamedCommand2 to search for custom pictures in the own add-in dll
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=467535

You can vote for it if you like the idea.

Posted by carlosq | with no comments

Another scenario where a managed add-in for VS 2005 or higher still requires the ComVisible(True) attribute (apart from the Connect class that I blogged about in the last post) is when creating toolwindows with the EnvDTE80.Windows2.CreateToolWindow2 method: if you move the ComVisible(True) attribute from the AssemblyInfo file to the Connect class (which is actually the class that needs it) then the usercontrol class passed to the CreateToolWindow2 is not visible to COM and in these circumstances the CreateToolWindow2 method doesn't return the created usercontrol as last parameter, and EnvDTE.Window.Object (which should return the usercontrol) is also null.

I had heard reports from people that said that when the usercontrol resided in another assembly rather than in the own add-in assembly, the CreateToolWindow2 didn't return the instance of the usercontrol. Now the explanation is clear:  usercontrols in Windows Control Library projects have the ComVisible attribute set to false in the assemblyinfo file, while usercontrols in the add-in project have it set to true in the assemblyinfo file. So, the problem is not where the usercontrol resides, but whether the usercontrol is visible to COM or not.

Since managed add-ins should get rid of COM semantics, I have filed another bug report to Microsoft:

EnvDTE80.Windows2.CreateToolWindow2 doesn't return in the last parameter the hosted usercontrol if ComVisible attribute not set to true
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=467084

Posted by carlosq | with no comments

While add-ins for Visual Studio .NET 2002/2003 required COM registration (COM Interop) and registration for Visual Studio using the Windows registry, Visual Studio 2005 introduced XML-registration (.AddIn file) and removed the need for COM registration, both a big advance.

Then, one day, visiting the assemblyinfo.vb file that is not very much visited, you notice the following line:

<Assembly: ComVisible(True)>

and then you think that you can change it to:

<Assembly: ComVisible(False)>

At this point, if you try to load the add-in after this change you get an exception:

Error 80004002 (No such interface supported)

I blogged about this problem some months ago and today I have filed a bug report for MS to fix it:

Error 80004002 (No such interface supported) in add-in when ComVisible attribute is set to False
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=467081

Note 1: while the add-in wizard sets the ComVisible attribute to True at assembly level, actually only the Connect class needs to have such attribute.

Note 2: since the ComVisible attribute uses a boolean parameter that can be set to true o false, one may wonder which is the behavior if the attribute is missing at all. The answer is in the MSDN docs: (public) types are visible to COM by default, the attribute is only needed to hide them to COM. So, it seeing <Assembly: ComVisible(True)> in your code bothers you too much, you can actually delete the line and the effect would be the same.

Posted by carlosq | 1 comment(s)

I thought that I had already reported these ones to Microsoft for VS 2008, but I don't find the bug reports and anyway the bugs are still present in VS 2010 Beta 1:

Visual Studio hardcodes "Application Data" folder in the list of folders for .AddIn files
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=466756

%ALLUSERSDOCUMENTS%\Microsoft\MSEnvShared\AddIns folder is not searched for add-ins
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=466741

Posted by carlosq | with no comments

Given that add-ins for Visual Studio can use COM-based registration or XML-based registration and that the first one uses two locations (HKEY_LOCAL_MACHINE / HKEY_CURRENT_USER) and the second one uses up to six folders by default (Tools, Options window, Environment, AddIn/Macros Security section), when developing and troubleshooting add-ins I often wonder where an add-in is registered from.

I have filed a suggestion report to get this info in the Add-In Manager of Visual Studio 2010:

Add information of add-in registration in Add-In Manager
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=466762

You can vote for it if you would like to have that info too.

Posted by carlosq | with no comments

If you are subscribed to the RSS of this blog, chances are that you are an add-in developer, because despite its title, I don't write very much about macros (nobody really uses them) and I don't know about SDK packages, only a little about how to call SDK services from an add-in. So, if you are an add-in developer, you must know how difficult is to get custom, transparent pictures on add-in buttons.

I have tried with Microsoft to get this fixed in the last years publicly and privately to no avail, but I keep pushing :-) and now that they are changing the commandbars to WPF is the best chance to get this fixed forever. Just in case you haven't tried yet, you can't get transparent pictures in VS 2010 Beta 1, neither using native (C++) satellite DLLs nor using managed (.NET) satellite DLLs (I tried managed DLLs after opening the bug report).

The short story (call to action):

Go to this page and vote to get this problem fixed (I am thinking that if it gets some hundreds of votes maybe they will fix it):

Automation Model (EnvDTE) Enhancement: Accept .NET System.Drawing.Icon to set custom pictures in add-in commands and toolwindows
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=336868

The long story (my last internal e-mail to Microsoft some days ago):

I would like to call the attention of all the people inside the Visual Studio Shell team that can make something to fix this problem that lasts 12 years now: it is very difficult to provide custom, transparent, pictures in buttons (CommandBarButton) created from add-ins:

- In VB5 (1997), VB6 and VBA you had to use the CopyFace/PasteFace methods to put custom pictures. The use of clipboard is causing problems today with remote desktop tools that monitor the clipboard.

- VS.NET 2002 forced to create a native (C++) resource library where the background color have to be almost green RGB = 0, 254, 0. The picture for ToolWindow.SetTabPicture have to use also that background color.

- VS 2005 allowed managed (VB.NET/C#) resource libraries, but you have to use also that color, or maybe magenta RGB=255,0,255.

- VS 2010 has again problem with transparency as I have reported here (neither almost green nor magenta works, at least with native satellite DLLs):

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=461192

The problems are two:

- There should no need to use resource libraries.
- The transparency should be much easier.

A very simple solution that solves both problems is:

- To allow to use icons, rather than bitmaps. Icons do support transparency natively.
- To provide a EnvDTE100.Commands3.

AddNamedCommand3 method with this signature:

Function AddNamedCommand2(ByVal AddInInstance As EnvDTE.AddIn, ByVal Name As String, ByVal ButtonText As String, ByVal Tooltip As String, Optional ByVal Icon As System.Drawing.Icon, Optional ByRef ContextUIGUIDs As Object( ), Optional ByVal vsCommandStatusValue As Integer = 3, Optional ByVal CommandStyleFlags As Integer = 3, Optional ByVal ControlType As EnvDTE80.vsCommandControlType = 2) As EnvDTE.Command.

The same for the current Window.SetTabPicture(object): Make it to accept a Systen.Drawing.Icon with transparency.

It would be up to the developer the decission to get this icon from a resource library, an embedded resource in the own add-in dll, a ImageList, a Picture control, a file on disk, an icon in memory, or whatever.

Then, internally in VS, make whatever you need to do with the icon: transform it to a bitmap, transform the transparent color to green, magenta or whatever, and paint it with transparent background.

Now that you are changing the commandbars to WPF and we are in Beta 1, it would be the best chance to get this fixed for good.

I have reported this twice through Microsoft Connect last years, to no avail:

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=336868

If you still feel that the current implementation that you offer to people extending Visual Studio with add-ins to use custom, transparent pictures in their add-ins is not so bad, then be 100% fully coherent and modify the add-in wizard to create a solution with:

1) The add-in project
2) A satellite DLL project with a custom, transparent, picture

and make it work just pressing F5 to debug the add-in. If it is quite difficult, then it means that the current implementation is not so acceptable after all. But it is too easy to ignore the problem and make the add-in wizard to create only the add-in project, without the satellite DLL, and use the parameter values MsoButton=True, Bitmap=59 to use the smiley face from the Office bitmaps rather than using a custom picture.

With best regards,

Carlos Quintero
Posted by carlosq | 2 comment(s)

A week ago I blogged about some nasty bugs that happened in VS 2010 Beta 1 when using the new WPF-based commandbars from an add-in. While VS 2010 Beta 1 was very disappointing for me in this regard, the response from Microsoft in the last days has been great and so far the following ones will be fixed in the next build:

CommandBarButtons created by add-ins in context menus don't appear

CommandBarPopup on toolbars doesn't show arrow to indicate the dropdown

EnvDTE.Command.Delete does not remove CommandBarButtons created from that command on Visual Studio commandbars

"Object must be the same type as the enum" exception calling CommandBars.Add from an add-in

Custom pictures in CommandBarButtons created by add-in don't show a transparent background

These others are still active (I hope they are fixed too) but are not so critical or have workarounds:

System.ArgumentNullException: "Value cannot be null." getting CommandBar.Position from an add-in
Workaround: since it seems that VS 2010 toolbars can't be moved by hand by the user, it is not much needed to use this property

CommandBars.Item("Tools") causes exception rather than finding the commandbar.
Workaround: HOWTO: Locate commandbars in international versions of Visual Studio

CommandBarButton.TooltipText causes exceptions when getting or setting its value
Workaround: use the tooltip parameter of the AddNamedCommand method rather than this property.

Posted by carlosq | with no comments

I started programming in the old times of 16-bit MS-DOS, where you had only 640 KB of memory, and you had concepts like "expanded memory" and "extended memory" and memory bank switching to use more than 640 KB and then wonderful things like the Watcom C++ compiler that allowed you to create linear 32-bit MS-DOS programs to use all the available memory, not just 640 KB or 1 GB MB (oops!). When Windows (95) became a 32-bit OS and I learned at college about 32 bit pointers, it seemed that 4 GB of memory will be enough forever. Guess what? Some weeks ago I got "out of memory" errors from Visual Studio when trying some features of my MZ-Tools add-in that operate on every file of a solution. Specifically, the problem happened when iterating the code elements of the EnvDTE.ProjectItem.FileCodeModel of every file of the solution. My computer had 4 GB of RAM so I was surprised by this error (later I learned that the amount of RAM is irrelevant for most "out of memory" errors in modern virtual memory operating systems).

The first reference that I found on the web about this error was in the MSDN VSX forum:

ProjectItem.FileCodeModel causes memory fragmentation?
http://social.microsoft.com/Forums/en-US/vsx/thread/9d6c1d17-63c8-40c4-b6bc-e7f0ead65c3d

Notice that while MSFT people explained that this is due to COM objects in memory wrapped by .NET objects that are not released, the explanation does not solve the problem, neither the manipulation of the Garbage Collector (GC). I didn't try using EnvDTE.Project.CodeModel because it didn't meet my needs of "file by file" processing.

Then I found that mine was not the only extension for Visual Studio experiencing this problem. Resharper was also experiencing it and provided some tools to fix it. But it was non until I read this post when I learned about the cause and (kind of) solution for this problem:

Hacking Visual Studio to Use More Than 2Gigabytes of Memory
http://stevenharman.net/blog/archive/2008/04/29/hacking-visual-studio-to-use-more-than-2gigabytes-of-memory.aspx

So, the problem is not the lack of physical memory (RAM) or virtual memory, but the address space of 32-bit processes, which is limited to 4 GB and half of it is reserved for the OS (kernel mode) so the process has only 2 GB for it (user mode). And using the file code model of every file of a solution can cause Visual Studio to reach the limit of 2 GB of its user-mode address space. Using the /3GB option in the boot.ini file allows 3 GB of address space for the user mode part of the process and 1 GB for the kernel mode part, which can cause other problems because 1 GB is little these days for some video cards, etc.

Also, to take advantage of the 3 GB address space, a process must be "marked" to indicate the OS that it can use all those memory addresses. This is done with the LARGEADDRESSAWARE flag in the executable image that Visual Studio 2008 does have set, but Visual Studio 2005 doesn't (although you can patch it with the editbin utility as explained in the link above).

In my case, using the /3GB option in boot.ini with VS 2008 "solved" the problem and using the Task Manager I saw devenv.exe passing the limit of 2 GB without causing the "OutOfMemory" exception. I say "solved" because this is not really a happy solution, it is not something that you can patch in your add-in, you need to show a message explaining the user to either use Windows 64-bit (which gives 32-bit processes the full 4 GB address space for user-mode) or to use the /3GB option with Windows 32-bit (that can cause other problems, in my case with two other applications).

So, 32-bit pointers and 4 GB are not enough these days... maybe with 64-bit pointers we'll have these problems solved forever.

There is a bunch of very interesting resources on the web about all this, starting by the Raymond Chen's series:

Summary of the recent spate of /3GB articles
http://blogs.msdn.com/oldnewthing/archive/2004/08/22/218527.aspx

and this one of today:

“Out Of Memory” Does Not Refer to Physical Memory
http://blogs.msdn.com/ericlippert/archive/2009/06/08/out-of-memory-does-not-refer-to-physical-memory.aspx

Posted by carlosq | with no comments
More Posts Next page »