Problem with Shell32.dll in thread: BadImageFormatException - Invalid access to memory location


What have I done:
I've adapted and tested the code from and it works fine in the sub main of a console application.

Then I wrapped the code up in a class and it throws an error whenever I run the subroutine from another thread or from timer_elasped.

What the code does:
The subroutine goes into control panel --> Network Connections --> Local Area Connection (or any other connection), iterate through the verbs to disable, then enable that connection

What went wrong:
The following exception has been thrown when it tried to get the verbs from Shell32.FolderItem
    System.BadImageFormatException: {"Invalid access to memory location. (Exception from HRESULT: 0x800703E6)"}
    Data: {System.Collections.ListDictionaryInternal}
    HelpLink: Nothing
    InnerException: Nothing
    Message: "Invalid access to memory location. (Exception from HRESULT: 0x800703E6)"
    Source: "Interop.Shell32"
    StackTrace: "   at Shell32.FolderItem.Verbs()
   at (my app)..ctor(String ConnectionName) in (my file path):line 83"
    TargetSite: {System.Reflection.RuntimeMethodInfo}

I've attached my adapted version of the source code, which is largely the same as the one in the URL, except I've removed some "console.writeline" and hard-wired the connection name.

The attached code works in "sub main" and I've referenced the relevant dll etc. So why doesn't it work on a separate thread or in a timer_elasped sub?
If Not My.Computer.Network.IsAvailable Then
            ' Control Panel Identifier 
            Const ssfCONTROLS = 3
            ' Generate Shell item 
            Dim ShellApp As New Shell32.Shell()
            ' Obtain the Control Panel 
            Dim ControlPanel As Shell32.Folder = ShellApp.NameSpace(ssfCONTROLS)
            Dim NetworkFolder As Shell32.Folder
            Dim LANConnection As Shell32.FolderItem
            ' Loop through the items in the control panel and obtain the Network Connections folder 
            For Each FolderItem As Shell32.FolderItem In ControlPanel.Items()
                If FolderItem.Name = "Network Connections" Then
                    ' When found - exit the loop 
                    NetworkFolder = FolderItem.GetFolder
                    Exit For
                End If
            ' Debug check 
            If IsNothing(NetworkFolder) Then
                Console.WriteLine("Error - No network folder found")
                Exit Sub
            End If
            ' Obtain the appropriate connection record 
            For Each FolderItem As Shell32.FolderItem In NetworkFolder.Items()
                If FolderItem.Name = _ConnectionName Then
                    ' When found - exit the loop 
                    LANConnection = FolderItem
                    Exit For
                End If
            ' Debug check 
            If LANConnection Is Nothing Then
                Console.WriteLine("Error - No LAN entry was not found")
            End If
            Const EnableVerb As String = "En&able"
            Const DisableVerb As String = "Disa&ble"
            ' Run through all available options and obtain the appropriate action 
' ***** error here ***
            For Each Verb As Shell32.FolderItemVerb In LANConnection.Verbs
                If Verb.Name = DisableVerb Then
                    Console.Write("Current Status: Enabled --> Trying to disable")
                    Exit For
                End If
            ' wait for 5 seconds before enabling again
            ' Enable it...
            For Each Verb As Shell32.FolderItemVerb In LANConnection.Verbs
                If Verb.Name = EnableVerb Then
                    Console.Write("Current Status: Disabled --> Trying to enable")
                    Exit For
                End If
        End If

Open in new window

Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

COM components use apartments to synchronize access to resources. In contrast, managed objects use synchronized regions, synchronization primitives such as mutexes, locks and completion ports, and synchronized contexts to ensure that all shared resources are used in a thread-safe manner.
For interoperability, the common language runtime creates and initializes an apartment when calling a COM object. A managed thread can create and enter a single-threaded apartment (STA) that contains only one thread, or a multi-threaded apartment (MTA) that contains one or more threads. When a COM apartment and a thread-generated apartment are compatible, COM allows the calling thread to make calls directly to the COM object. If the apartments are incompatible, COM creates a compatible apartment and marshals all calls through a proxy in the new apartment.
The runtime calls CoInitializeEx to initialize the COM apartment as either an MTA or an STA apartment.
In the .NET Framework version 2.0, managed threads are initialized as MTA if their apartment state has not been set prior to starting the thread.
Use the SetApartmentState or TrySetApartmentState method to set the apartment state before starting the thread.
In the .NET Framework version 2.0, the main application thread is initialized as MTA unless the STAThreadAttribute is applied to the entry point procedure.

I have created a modul and included your code in a function passing the _ConnectionName
Public Function enableLanConnection(<MarshalAs(UnmanagedType.LPWStr)> ByVal _ConnectionName As String) As Boolean
   ....'// handle the return true - false of the function....
End Function

The code to load the function is
        Dim t As New Thread(AddressOf ThreadProc)

    Sub ThreadProc()
        enableLan = enableLanConnection("LAN Connection")
    End Sub

If you access the function from the main thread (You application UI) thne you do not need threading, you can call it directlly...

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
zip001Author Commented:
I see...

The problem is this is code for a windows service, so there is no UI.

The windows service is quite big, so I put the initialization code in a background process, i.e. a different thread, I guess I can work around that pretty easily.

However, the code is also accessed through a timer, which creates another thread. I tried inheriting the service class so it can be the schronizing object of the timer, but it still creates another thread.

My current solution is to put that code into another app, and start it using the process class. It's silly, but it works
As I wrote in the past...Limited memberships. The asker gets the guidelines and then he/she has no points to award and the result is this.
I'd suggest close the question with no points refunded.

Out of curiosity
zip001, did my answer assist you at all?
zip001Author Commented:

Yes and No.

From your answer I realised that everything has to be on the same thread. As mentioned in my last post, I couldn't do it with a Windows service.

I tried to close the question a few times, each time it says it will post a comment here and if no one objects it will close the question in 4 days. It just didn't happen that way.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.