Stuart Cox’s Tech Punch

Entries from June 2009

COM Interop – QueryInterface not supported (E-NOINTERFACE)

June 22, 2009 · Leave a Comment

Problem

Encountering an error when trying to instantiate COM objects through Primarary Interop Assemblies (PIA’s) or Runtime Callable Wrappers (RCW’s) created using the TLBIMP.exe tool. 

When calling the object for the first time, you encounter the following COM exception:

Unable to cast COM object of type ‘xxx to interface type ‘xxx’. This operation failed because the QueryInterface call on the COM component for the interface with IID ‘{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}’ failed due to the following error: No such interface supported (Exception from HRESULT: 0×80004002 (E_NOINTERFACE)).

You are likely to encounter this problem when developing ASP.Net applications, Windows Console applications, or Windows Services.  You are unlikely to experience this issue when developing Windows Forms applications.

Solution

The problem is that you are attempting to call Single-Threaded Apartment (STA) model COM components from an Multi-Threaded Apartment (MTA) thread.  The primary thread of Windows Forms applications are STA threads, so the components work fine there.  Most other project types, including Console applications and Windows Service applications are run on an MTA thread by default.  When you attempt to instantiate the an STA component, you will get the ubiquitous error described above.

You might try calling System.Threading.Thread.CurrentThread.SetApartmentState(ApartmentState.STA), but this won’t work.  You cannot change the thread execution model on a running thread. 

To fix the problem, you can set the thread execution type on the main application thread before it is started, but this is not optimal.  It is better to set the threading model specifically for the portion of code that needs it.

A better solution is to spin up a new thread for the job at hand, and set the thread execution state on the new thread before executing it.  There are a few different methods to accomplish this depending on what you’re trying to accomplish.  Here’s one to get you started:

using System.Threading;
...

// Setup an object to host the thread entry point
// Start a process on an MTA thread 
MyThreadedJob jobHost = new MyThreadedJob(jobId);
Thread t = new Thread(new ThreadStart(MyThreadedJob.Execute));
t.SetApartmentState(ApartmentState.MTA);

// Start the thread
t.Start();

// Wait for thread to complete (optional)
t.Join();

 

More Gory Details

For more of the gory details and differences between threading models in Windows and COM, you can start here.

 

  del.icio.us it! digg it! reddit! technorati! yahoo!

Categories: .Net · C# · COM Interop · Threading

SharePoint 2007 – Get SPList Object by Url

June 3, 2009 · 5 Comments

I want to get a reference to a SPList object associated with a given list url.  This method works with any of the url’s associated with the list, including view page url’s, or list form url’s. 

This should be much easier to achieve by using the object model, in my opinion.  String parsing of the url is not my favorite, but I couldn’t find a better way to accomplish it. 

If you know of an easier way to accomplish this, please leave me a comment.  Otherwise, you can steal this from me, if you want it!

/// <summary>
/// Gets an SPList based on the url to the list
/// </summary>
/// <param name="listUrl">Full url to the list</param>
/// <returns>SPList object, null if list is not found</returns>
public SPList GetListByUrl(string listUrl)
{
    SPList list = null;

    try
    {
        using (SPSite site = new SPSite(listUrl))
        {
            if (site != null)
            {
                // Strip off the site url, leaving the rest
                // We'll use this to open the web
                string webUrl = listUrl.Substring(site.Url.Length);

                // Strip off anything after /forms/
                int formsPos = webUrl.IndexOf("/forms/", 0, StringComparison.InvariantCultureIgnoreCase);
                if (formsPos >= 0)
                {
                    webUrl = webUrl.Substring(0, webUrl.LastIndexOf('/', formsPos));
                }

                // Strip off anything after /lists/
                int listPos = webUrl.IndexOf("/lists/", 0, StringComparison.InvariantCultureIgnoreCase);
                if (listPos >= 0)
                {
                    // Must be a custom list
                    // Strip off anything after /lists/
                    webUrl = webUrl.Substring(0, webUrl.LastIndexOf('/', listPos));
                }
                else
                {
                    // No lists, must be a document library.
                    // Strip off the document library name
                    webUrl = webUrl.Substring(0, webUrl.LastIndexOf('/'));
                }

                // Get the web site
                using (SPWeb web = site.OpenWeb(webUrl))
                {
                    if (web != null)
                    {
                        // Initialize the web (avoids COM exceptions)
                        string title = web.Title;

                        // Strip off the relative list Url
                        // Form the full path to the list
                        //string relativeListUrl = listUrl.Substring(web.Url.Length);
                        //string url = SPUrlUtility.CombineUrl(web.Url, relativeListUrl);

                        // Get the list
                        list = web.GetList(listUrl);
                    }
                }
            }
        }
    }
    catch { }

    return list;
}

Enjoy!

  del.icio.us it!

digg it!

reddit!

technorati!

yahoo!

Categories: .Net · C# · MOSS 2007 · SharePoint