Hi Folks,

Really desperate for help here as I've spent days trying to resolve this one.

We have a VB 2008 web browser app using a webbrowser control on our Kiosks at our uni - it works very well and locks down the workstation so teh students can only use it for the intended purpose.

As it never closes we need to kill the session cookies between users.

We can run this via the auto-homepage routine we have but nothing we've tried will kill them.

I've searched doezens of forums and tried the most common:
webbrowser1.Document.Cookie.Remove(0, (webbrowser1.Document.Cookie.Count - 1))
Also some java script that clears cookies for the current page but isn't usable as it means users would need to log in every time they click an internal link.
Other code suggests changing the dates so the cookies are expired but the code has a type used that doesn't seem to work with any 2008 namespace.

If anyone has a module or code that works with 2008, or can offer any advice that will kill or expire all cookies I would be very, very grateful.

Many thanks in advance - Adam.

Recommended Answers

All 11 Replies

p.s. If unloading and relaoding the webbrowser control is a way of doing it then I can work with that. I've tried disposing it but after I re-initialise it the cookies are still active.

Probably doing something wrong but my meagre skill slie with VB6 so learning all the time!

Thanks again.

I think the WebBrowser control uses all the cookies from ie so to delete them you'd have to delete all the cookies in the standard ie cookie folder. I'm not sure on access rights to that folder but you could try this:

Dim cookieFiles As System.Collections.ObjectModel.ReadOnlyCollection(Of String) = My.Computer.FileSystem.GetFiles(System.Environment.GetFolderPath(Environment.SpecialFolder.Cookies), FileIO.SearchOption.SearchTopLevelOnly, New String() {"*.txt"})
        For i = 0 To cookieFiles.Count - 1
            Try
                My.Computer.FileSystem.DeleteFile(cookieFiles(i))
            Catch ex As Exception
            End Try
        Next

Many thanks Me655321,

I've tried this but it doesn't actually clear the cookies. It doesn't throw an error either which I suspect it would if there was a file access issue. But general advice seems to be that I need to pre-expire the cookies arther than try to kill them.

The only success I've had so far is with:

For Each cookie As String In Webbrowser1.Document.Cookie.Split(";"c)
            Dim domain As String = "." + Webbrowser1.Url.Host
            While domain.Length > 0
                Dim path As String = Webbrowser1.Url.LocalPath
                While path.Length > 0
                    Webbrowser1.Document.Cookie = cookie.Split("="c)(0).Trim & "= ;expires=Thu, 30-Oct-1980 16:00:00 GMT;path=" & path & ";domain=" & domain
                    path = path.Substring(0, path.Length - 1)
                End While
                Select Case domain.IndexOf(".")
                    Case 0
                        domain = domain.Substring(1)
                    Case -1
                        domain = ""
                    Case Else
                        domain = domain.Substring(domain.IndexOf("."))
                End Select
            End While
        Next

which I'm triggering on every domain change. However it only works on the current URL cookie, so if you log into your email, then navigate to another page in the same domain, then try to clear cookies it won't work.

It would seem that an amalgamation of both codes would be the ideal solution, but probably beyond my skills :)

Thanks again for getting back to me - Adam.

Did you try running the code without the Try/Catch?

Dim cookieFiles As System.Collections.ObjectModel.ReadOnlyCollection(Of String) = My.Computer.FileSystem.GetFiles(System.Environment.GetFolderPath(Environment.SpecialFolder.Cookies), FileIO.SearchOption.SearchTopLevelOnly, New String() {"*.txt"})
        For i = 0 To cookieFiles.Count - 1
            My.Computer.FileSystem.DeleteFile(cookieFiles(i))
        Next

Then it would throw an error on file access issues. Personally, I would try to get things working this way so you could just clear cookies at the end of a session. The code you have seems like it should work but if I understand right, wouldn't it also clear a user's cookies mid-session if they changed pages and then back again?

Hi,

Yes, I ran the code both with an error routine to pick up any errors and also without the try/catch/end try.

It's not havregistering any errors - just not deleting any (I presume active) cookies.

Just tested again with simply a blank form, webbrowser, url field and button with your code.

You are correct that the code I'm using is a poor fix - even clicking a hyperlink in an webmail etc will close the mail session.

But I've spent weeks (literally) investigating this and the code I'm using is the only code that works so far (tested on XP, 2003 & W7).

The general consensus on most forums is to expire cookies as you can't delete current cookies...

Thanks again - I don't suppose you can see how to adapt the expiry code to write to all cookies in the folder?
Presumably the .Split("="c)(0).Trim & "= ;expires=Thu, 30-Oct-1980 16:00:00 GMT;path=" & path & ";domain=" & domain could be applied rather than simply deleting the file?

Many thanks - Adam.

I don't see any way to modify your code to access all cookies since you can't access cookies cross domain. And to get at them in the actual folder would work but obviously there's some problem with the folder code I gave you. Maybe try switching to FileIO.SearchOption.SearchAllSubDirectories

Dim cookieFiles As System.Collections.ObjectModel.ReadOnlyCollection(Of String) = My.Computer.FileSystem.GetFiles(System.Environment.GetFolderPath(Environment.SpecialFolder.Cookies), FileIO.SearchOption.SearchAllSubDirectories, New String() {"*.txt"})
        For i = 0 To cookieFiles.Count - 1
            My.Computer.FileSystem.DeleteFile(cookieFiles(i))
        Next

Just tested and deleted all my cookies so it works for me.(on Vista)

Hmm, we've tried it on numerous machines. It does delete cookies in general - just not the ones currently in use.

We put a simple webbrowser on a form and a URL box and button pointing at your code.

Navigate to amazon and log in.
Navigate to Google
Run your code
Navigate back to Amazon - no login required

(but all of the other cookies, i.e. sites I hadn't visited since starting the browser have been deleted - just not the active ones).

Very strange. Not just me either. Others who have tried deleting cookies in both .net and VB6 have seen the same thing.

This is from MS: " You cannot directly delete a cookie on a user's computer. However, you can direct the user's browser to delete the cookie by setting the cookie's expiration date to a past date. The next time a user makes a request to a page within the domain or path that set the cookie, the browser will determine that the cookie has expired and remove it. (http://msdn.microsoft.com/en-us/library/ms178195.aspx)"

They propose:

If (Not Request.Cookies("UserPreferences1") Is Nothing) Then
    Dim myCookie As HttpCookie
    myCookie = New HttpCookie("UserPreferences1")
    myCookie.Expires = DateTime.Now.AddDays(-1D)
    Response.Cookies.Add(myCookie)
End If

But this is for individual cookies and needs the cookie name...

Many thanks - Adam

Ok so I finally set up a test project and I see what you're talking about. Sorry, I just never needed to delete cookies on the fly so my code worked for me. IE Cookie set up has got to be one of the strangest things ever.

Try adding these two files to your project: http://support.microsoft.com/kb/311289/EN-US/ Then just run the Module1.Main() to clear the cache. On first test it seems to work.

Thanks me655321, funnily enough this is where I first started! :)

This code gives an access violation ("Attempted to read or write protected memory."), even when run as admin. If you try to ignore the error the program just hangs...

It does seem to delete a number of files from the cache before hitting this error, but eventually hits it first time, every time.

I think this post was aptly named "aarggh!"...

I begin to suspect that it's not going to happen. I've since spoken to other .net developers who are also going around in circles looking for a solution.

I still think the best bet is using your for.. next loop on the file system but expiring the cookies rather than deleting them, perhaps using the MS code (myCookie.Expires = DateTime.Now.AddDays(-1D)) as posted above.

Unfortunately all my attempt sat this have failed.

I really appreciate you trying to help so thanks for your time. If you have any other ideas then please post - and likewise I will update if I find a solution.

Cheers - Adam.

Hmmm that's frustrating. For me, it successfully clears the cache...the first time. The second time I try to clear it, it falls into an infinite loop. It does that pretty consistently. There must be some error in their code. That said, it DOES seem to successfully clear it the first try every time, so there must be some way to use the DeleteUrlCacheEntry function better than their method. I'll try to play around with it for you when I get a chance, see if I can figure something out.

As for cycling through the cookies to expire them, I agree, that should work. I'm not sure how to interpret the cookie files though as there doesn't seem to be a way to decipher cookie names from them. Maybe if you could find out the format of the index.dat files you could read the cookies from them. Not sure though. Got me curious though so I'll keep trying til I figure it out.

(Yes, aaarghhhh cookies is right!!)

Hey, played around with it a little and got it working(at least for me). Changed the msdn code to work on my end, but not sure if it'll fix the error you were getting.

'For PInvoke: Contains information about an entry in the Internet cache
    <StructLayout(LayoutKind.Explicit, Size:=80)> _
    Public Structure INTERNET_CACHE_ENTRY_INFOA
        <FieldOffset(0)> Public dwStructSize As UInt32
        <FieldOffset(4)> Public lpszSourceUrlName As IntPtr
        <FieldOffset(8)> Public lpszLocalFileName As IntPtr
        <FieldOffset(12)> Public CacheEntryType As UInt32
        <FieldOffset(16)> Public dwUseCount As UInt32
        <FieldOffset(20)> Public dwHitRate As UInt32
        <FieldOffset(24)> Public dwSizeLow As UInt32
        <FieldOffset(28)> Public dwSizeHigh As UInt32
        <FieldOffset(32)> Public LastModifiedTime As FILETIME
        <FieldOffset(40)> Public ExpireTime As FILETIME
        <FieldOffset(48)> Public LastAccessTime As FILETIME
        <FieldOffset(56)> Public LastSyncTime As FILETIME
        <FieldOffset(64)> Public lpHeaderInfo As IntPtr
        <FieldOffset(68)> Public dwHeaderInfoSize As UInt32
        <FieldOffset(72)> Public lpszFileExtension As IntPtr
        <FieldOffset(76)> Public dwReserved As UInt32
        <FieldOffset(76)> Public dwExemptDelta As UInt32
    End Structure

    'For PInvoke: Initiates the enumeration of the cache groups in the Internet cache
    <DllImport("wininet.dll", SetLastError:=True, _
       CharSet:=CharSet.Auto, _
       EntryPoint:="FindFirstUrlCacheGroup", _
       CallingConvention:=CallingConvention.StdCall)> _
    Shared Function FindFirstUrlCacheGroup( _
        ByVal dwFlags As Int32, _
        ByVal dwFilter As Integer, _
        ByVal lpSearchCondition As IntPtr, _
        ByVal dwSearchCondition As Int32, _
        ByRef lpGroupId As Long, _
        ByVal lpReserved As IntPtr) As IntPtr
    End Function

    'For PInvoke: Retrieves the next cache group in a cache group enumeration
    <DllImport("wininet.dll", _
       SetLastError:=True, _
       CharSet:=CharSet.Auto, _
       EntryPoint:="FindNextUrlCacheGroup", _
       CallingConvention:=CallingConvention.StdCall)> _
    Shared Function FindNextUrlCacheGroup( _
        ByVal hFind As IntPtr, _
        ByRef lpGroupId As Long, _
        ByVal lpReserved As IntPtr) As Boolean
    End Function

    'For PInvoke: Releases the specified GROUPID and any associated state in the cache index file
    <DllImport("wininet.dll", _
       SetLastError:=True, _
       CharSet:=CharSet.Auto, _
       EntryPoint:="DeleteUrlCacheGroup", _
       CallingConvention:=CallingConvention.StdCall)> _
    Shared Function DeleteUrlCacheGroup( _
        ByVal GroupId As Long, _
        ByVal dwFlags As Int32, _
        ByVal lpReserved As IntPtr) As Boolean
    End Function

    'For PInvoke: Begins the enumeration of the Internet cache
    <DllImport("wininet.dll", _
        SetLastError:=True, _
        CharSet:=CharSet.Auto, _
        EntryPoint:="FindFirstUrlCacheEntryA", _
        CallingConvention:=CallingConvention.StdCall)> _
     Shared Function FindFirstUrlCacheEntry( _
     <MarshalAs(UnmanagedType.LPStr)> ByVal lpszUrlSearchPattern As String, _
          ByVal lpFirstCacheEntryInfo As IntPtr, _
          ByRef lpdwFirstCacheEntryInfoBufferSize As Int32) As IntPtr
    End Function

    'For PInvoke: Retrieves the next entry in the Internet cache
    <DllImport("wininet.dll", _
       SetLastError:=True, _
       CharSet:=CharSet.Auto, _
       EntryPoint:="FindNextUrlCacheEntryA", _
       CallingConvention:=CallingConvention.StdCall)> _
    Shared Function FindNextUrlCacheEntry( _
          ByVal hFind As IntPtr, _
          ByVal lpNextCacheEntryInfo As IntPtr, _
          ByRef lpdwNextCacheEntryInfoBufferSize As Integer) As Boolean
    End Function

    'For PInvoke: Removes the file that is associated with the source name from the cache, if the file exists
    <DllImport("wininet.dll", _
      SetLastError:=True, _
      CharSet:=CharSet.Auto, _
      EntryPoint:="DeleteUrlCacheEntryA", _
      CallingConvention:=CallingConvention.StdCall)> _
    Shared Function DeleteUrlCacheEntry( _
        ByVal lpszUrlName As IntPtr) As Boolean
    End Function
    Public Sub ClearCache()
        Const CACHEGROUP_SEARCH_ALL = &H0
        Const CACHEGROUP_FLAG_FLUSHURL_ONDELETE = &H2
        Const ERROR_FILE_NOT_FOUND = &H2
        Const ERROR_NO_MORE_ITEMS = 259
        Dim groupId As Long = 0
        Dim cacheEntryInfoBufferSizeInitial As Integer = 0
        Dim cacheEntryInfoBufferSize As Integer = 0
        Dim cacheEntryInfoBuffer As IntPtr = IntPtr.Zero
        Dim internetCacheEntry As INTERNET_CACHE_ENTRY_INFOA
        Dim enumHandle As IntPtr = IntPtr.Zero
        Dim returnValue As Boolean = False

        enumHandle = FindFirstUrlCacheGroup(0, CACHEGROUP_SEARCH_ALL, IntPtr.Zero, 0, groupId, IntPtr.Zero)
        'If there are no items in the Cache, you are finished.
        If (enumHandle.Equals(IntPtr.Zero) And (ERROR_NO_MORE_ITEMS.Equals(Marshal.GetLastWin32Error) Or ERROR_FILE_NOT_FOUND.Equals(Marshal.GetLastWin32Error))) Then
        Else
            'Loop through Cache Group, and then delete entries.
            While (True)
                'Delete a particular Cache Group.
                returnValue = DeleteUrlCacheGroup(groupId, CACHEGROUP_FLAG_FLUSHURL_ONDELETE, IntPtr.Zero)

                If (Not returnValue And ERROR_FILE_NOT_FOUND.Equals(Marshal.GetLastWin32Error())) Then
                    returnValue = FindNextUrlCacheGroup(enumHandle, groupId, IntPtr.Zero)
                End If

                If (Not returnValue And (ERROR_NO_MORE_ITEMS.Equals(Marshal.GetLastWin32Error()) Or ERROR_FILE_NOT_FOUND.Equals(Marshal.GetLastWin32Error()))) Then
                    Exit While
                End If
            End While
        End If
        'Start to delete URLs that do not belong to any group.
        enumHandle = FindFirstUrlCacheEntry(vbNull, IntPtr.Zero, cacheEntryInfoBufferSizeInitial)
        If (enumHandle.Equals(IntPtr.Zero) And ERROR_NO_MORE_ITEMS.Equals(Marshal.GetLastWin32Error())) Then
            Exit Sub
        End If
        cacheEntryInfoBufferSize = cacheEntryInfoBufferSizeInitial
        cacheEntryInfoBuffer = Marshal.AllocHGlobal(cacheEntryInfoBufferSize)
        enumHandle = FindFirstUrlCacheEntry(vbNull, cacheEntryInfoBuffer, cacheEntryInfoBufferSizeInitial)

        While (True)
            internetCacheEntry = CType(Marshal.PtrToStructure(cacheEntryInfoBuffer, GetType(INTERNET_CACHE_ENTRY_INFOA)), INTERNET_CACHE_ENTRY_INFOA)
            cacheEntryInfoBufferSizeInitial = cacheEntryInfoBufferSize
            returnValue = DeleteUrlCacheEntry(internetCacheEntry.lpszSourceUrlName)

            returnValue = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, cacheEntryInfoBufferSizeInitial)
            If (Not returnValue And ERROR_NO_MORE_ITEMS.Equals(Marshal.GetLastWin32Error())) Then
                Exit While
            End If

            If (Not returnValue And cacheEntryInfoBufferSizeInitial > cacheEntryInfoBufferSize) Then

                cacheEntryInfoBufferSize = cacheEntryInfoBufferSizeInitial
                Dim tempIntPtr As New IntPtr(cacheEntryInfoBufferSize)
                cacheEntryInfoBuffer = Marshal.ReAllocHGlobal(cacheEntryInfoBuffer, tempIntPtr)
                returnValue = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, cacheEntryInfoBufferSizeInitial)
            End If
        End While
        Marshal.FreeHGlobal(cacheEntryInfoBuffer)
    End Sub
    Public Sub ClearCache2()
        'List of cookie files
        Dim cookieFiles As System.Collections.ObjectModel.ReadOnlyCollection(Of String) = My.Computer.FileSystem.GetFiles("C:\Users\Steve\AppData\Roaming\Microsoft\Windows\Cookies", FileIO.SearchOption.SearchAllSubDirectories, New String() {"*.txt"})
        Dim fileText As String
        Dim tmpDomain, tmpCookieName As String
        Dim cIndex As Integer
        Dim tmpArr() As String
        For i = 0 To cookieFiles.Count - 1
            fileText = My.Computer.FileSystem.ReadAllText(cookieFiles(i))
            'Attributes are separated by CR
            tmpArr = fileText.Split(Chr(10))
            cIndex = 0
            For i2 = 0 To tmpArr.Length - 1
                If cIndex = 0 Then
                    tmpCookieName = tmpArr(i2)
                ElseIf cIndex = 2 Then
                    tmpDomain = tmpArr(i2)
                End If
                'Entries are separated by *
                If tmpArr(i2) = "*" Then

                    'Expire tmpDomain - tmpCookieName

                    cIndex = -1
                End If
                cIndex += 1
            Next
        Next
    End Sub

2 functions, ClearCache and ClearCache2. The first one is the fixed msdn code and the second one is an attempt to cycle through the cookie files and extract the cookie info. Should work, but it's not finished. You'd have to set up the expiry function(not sure if that's even possible). Anyway, check it out and let me know if it works.

(If you're still getting your write error, maybe set a breakpoint on ClearCache() and step through to see what's triggering it.)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.