"CallbackOnCollectedDelegate was detected" error.
"CallbackOnCollectedDelegate was detected" error.
"CallbackOnCollectedDelegate was detected" error.
"CallbackOnCollectedDelegate was detected" error.
"CallbackOnCollectedDelegate was detected" error.
"CallbackOnCollectedDelegate was detected" error. "CallbackOnCollectedDelegate was detected" error. "CallbackOnCollectedDelegate was detected" error. "CallbackOnCollectedDelegate was detected" error. "CallbackOnCollectedDelegate was detected" error. "CallbackOnCollectedDelegate was detected" error. "CallbackOnCollectedDelegate was detected" error. "CallbackOnCollectedDelegate was detected" error.
"CallbackOnCollectedDelegate was detected" error. "CallbackOnCollectedDelegate was detected" error.
"CallbackOnCollectedDelegate was detected" error.
Go Back  Xtreme Visual Basic Talk > > > "CallbackOnCollectedDelegate was detected" error.


Reply
 
Thread Tools Display Modes
  #1  
Old 05-23-2007, 10:07 PM
Scriptdaemon Scriptdaemon is offline
Newcomer
 
Join Date: May 2007
Posts: 3
Default "CallbackOnCollectedDelegate was detected" error.


I'm trying to use SetTimer with my code, but I always get this error with my code. Two lines specifically I have found cause this this error to occur, and I have commented them out for reference (the very last two subroutines). Anyone know how to fix my problem?

Code:
Public Class settingsForm
    Private Delegate Function delegateCallBack() As Integer
    Private Declare Function SetTimer Lib "user32" (ByVal hwnd As Integer, ByVal nIDEvent As Integer, ByVal uElapse As Integer, ByVal lpTimerFunc As delegateCallBack) As Integer
    Private Declare Function KillTimer Lib "user32" (ByVal hwnd As Integer, ByVal nIDEvent As Integer) As Integer
    Dim startTimer As Integer

    Public Sub New()
        InitializeComponent()
        If My.Settings.folderPath.Length = 0 Then
            My.Settings.folderPath = My.Computer.FileSystem.SpecialDirectories.MyPictures
            Me.folderPathTextBox.Text = My.Settings.folderPath
            My.Settings.Save()
        End If
        If Me.useTimerByCheckBox.Checked Then
            Me.timerIntervalComboBox.Enabled = True
            startTimer = SetTimer(0, 0, getTimerInterval(), AddressOf timerProc)
        End If
        Me.largerThanScreenComboBox.DataSource = System.Enum.GetNames(GetType(desktopBackgroundStyle))
        Me.smallerThanScreenComboBox.DataSource = System.Enum.GetNames(GetType(desktopBackgroundStyle))
        Me.smallerThanImageSizeComboBox.DataSource = System.Enum.GetNames(GetType(desktopBackgroundStyle))
    End Sub

    Private Sub changeDesktopBackground()
        My.Settings.Save()
        Dim img As Bitmap = getImageFile()
        If img Is Nothing Then
            MessageBox.Show("Sorry, no images located in specified folder.")
            Return
        Else
            Dim style As desktopBackgroundStyle = getImageStyle(img)
            WindowsAPIClass.setDesktopBackground(img, style)
        End If
    End Sub

    Private Function getTimerInterval() As Integer
        If Me.timerIntervalComboBox.Text = "½ Hour" Then
            Return 1800000
        ElseIf Me.timerIntervalComboBox.Text = "Hour" Then
            Return 3600000
        ElseIf Me.timerIntervalComboBox.Text = "Day" Then
            Return 86400000
        End If
    End Function

    Private Function getImageFile() As Bitmap
        Dim opt As System.IO.SearchOption = System.IO.SearchOption.TopDirectoryOnly
        If subFoldersCheckbox.Checked Then opt = System.IO.SearchOption.AllDirectories
        Dim files As String() = System.IO.Directory.GetFiles(folderPathTextBox.Text, "*", opt)
        Dim filteredFiles As New List(Of String)()
        For Each file As String In files
            Dim ext As String = file.Substring(file.LastIndexOf("."))
            If ".jpg .bmp .gif".IndexOf(ext) > -1 AndAlso file.EndsWith("desktop.bmp") = False AndAlso Not file = My.Settings.lastImageShown Then
                filteredFiles.Add(file)
            End If
        Next
        If filteredFiles.Count = 0 Then Return Nothing
        Dim filename As String = filteredFiles(rnd.Next(filteredFiles.Count))
        My.Settings.lastImageShown = filename
        My.Settings.Save()
        Return New Bitmap(filename)
    End Function

    Private Function getImageStyle(ByVal img As Bitmap) As desktopBackgroundStyle
        Dim smallestSize As Integer = Integer.Parse(imageSizeTextBox.Text)
        Dim imgH As Integer = img.Height
        Dim imgW As Integer = img.Width
        Dim desktopH As Integer = Screen.PrimaryScreen.Bounds.Height
        Dim desktopW As Integer = Screen.PrimaryScreen.Bounds.Width
        Dim style As String
        If ((imgW > desktopW) OrElse (imgH > desktopH)) Then
            style = Me.largerThanScreenComboBox.Text
        ElseIf ((imgW <= smallestSize) AndAlso (imgH <= smallestSize)) Then
            style = Me.smallerThanImageSizeComboBox.Text
        Else
            style = Me.smallerThanScreenComboBox.Text
        End If
        Return CType(System.Enum.Parse(GetType(desktopBackgroundStyle), style), desktopBackgroundStyle)
    End Function

    Private Function timerProc() As Integer
        changeDesktopBackground()
    End Function

    Private Sub timerIntervalComboBox_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timerIntervalComboBox.SelectedIndexChanged
        Call KillTimer(0, startTimer)
        'startTimer = SetTimer(0, 0, getTimerInterval(), AddressOf timerProc)
        My.Settings.timerInterval = Me.timerIntervalComboBox.Text
        My.Settings.Save()
    End Sub

    Private Sub useTimerByCheckBox_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles useTimerByCheckBox.CheckedChanged
        If Me.useTimerByCheckBox.Checked Then
            'startTimer = SetTimer(0, 0, getTimerInterval(), AddressOf timerProc)
        Else
            Call KillTimer(0, startTimer)
        End If
        Me.timerIntervalComboBox.Enabled = Me.useTimerByCheckBox.Checked
        My.Settings.useTimerBy = Me.useTimerByCheckBox.Checked
        My.Settings.Save()
    End Sub
End Class
Reply With Quote
  #2  
Old 05-24-2007, 03:50 AM
jo0ls&quot;CallbackOnCollectedDelegate was detected&quot; error. jo0ls is offline
Senior Contributor

Forum Leader
* Expert *
 
Join Date: Feb 2005
Location: London
Posts: 1,050
Default

The problem is that your delegate signature does not match the signature of the unmanaged callback, which is defined here. You have:

Private Delegate Function delegateCallBack() As Integer

But it should match:

VOID CALLBACK TimerProc(
HWND hwnd,
UINT uMsg,
UINT_PTR idEvent,
DWORD dwTime
);


This page helps translate c types to .Net types. UInt_Ptr will be marshalled to a UInteger. If you have a vb 2003 edition, then you don't have UInteger, so use Integer. If you hate UInteger, then use integer . As the C method has a return type VOID, use a Sub rather than a function.

As for SetTimer, you have Integer for the hwnd and send 0. You should use IntPtr, and send the form's handle (Me.Handle). You should also pick a number to represent the timer (idEvent), 1 will do. You could use Integer rather than UInteger for this one too, as the maximum permitted value for nElapse is Integer.MaxValue anyway. (min value is 10).

KillTimer should also use IntPtr for HWnd - pass the Form's handle, and the idEvent that you chose to identify the timer.

Last edited by jo0ls; 05-24-2007 at 04:17 AM.
Reply With Quote
  #3  
Old 05-24-2007, 05:36 PM
Scriptdaemon Scriptdaemon is offline
Newcomer
 
Join Date: May 2007
Posts: 3
Default

I did a little on my own before I got your answer and it appears to work as is, but as I just winged it since I'm not too familiar with the managed/unmanaged code and what all that means, so I'll use the things you've told me to. I changed a little, but could you tell me what I may be missing in this? (Note: I didn't know what to use instead of dword so I just put in integer for now.)

P.S. Also, I didn't actually know timerproc was, what appears to be, an already defined function, I just renamed it from a page I somewhat learned about delegates and the SetTimer API from. Am I able to use the actual delegate and timerproc (renamed to something not already taken, I suppose) without specifying any parameters, as I had it before?

P.P.S. I put in the KillTimer in the beginning of the setTimerInterval() function so when I call it when I click the button to manually change the background (I took that out of the code I show here because I figure it is unnecessary to my problem), so it resets the timer.

Code:
Private Delegate Sub delegateCallBack(ByVal hwnd As IntPtr, ByVal uMsg As Integer, ByVal idEvent As Integer, ByVal dwTime As Integer)
Private Declare Function SetTimer Lib "user32" (ByVal hwnd As IntPtr, ByVal nIDEvent As Integer, ByVal uElapse As Integer, ByVal lpTimerFunc As delegateCallBack) As Integer
Private Declare Function KillTimer Lib "user32" (ByVal hwnd As IntPtr, ByVal nIDEvent As Integer) As Integer

Public Sub New()
    InitializeComponent()
    If My.Settings.folderPath.Length = 0 OrElse My.Computer.FileSystem.DirectoryExists(My.Settings.folderPath) = False Then
        My.Settings.folderPath = My.Computer.FileSystem.SpecialDirectories.MyPictures
        Me.folderPathTextBox.Text = My.Settings.folderPath
    End If
    If Me.useTimerByCheckBox.Checked Then
        Me.timerIntervalComboBox.Enabled = True
        setTimerInterval()
    End If
    Me.largerThanScreenComboBox.DataSource = System.Enum.GetNames(GetType(desktopBackgroundStyle))
    Me.smallerThanScreenComboBox.DataSource = System.Enum.GetNames(GetType(desktopBackgroundStyle))
    Me.smallerThanImageSizeComboBox.DataSource = System.Enum.GetNames(GetType(desktopBackgroundStyle))
End Sub

Private Function getImageFile() As Bitmap
    Dim opt As System.IO.SearchOption = System.IO.SearchOption.TopDirectoryOnly
    If Me.subFoldersCheckbox.Checked Then
        opt = System.IO.SearchOption.AllDirectories
    End If
    If My.Computer.FileSystem.DirectoryExists(My.Settings.folderPath) = False Then
        MessageBox.Show("Sorry, specified folder does not exist.")
        Return Nothing
    End If
    Dim files As String() = System.IO.Directory.GetFiles(Me.folderPathTextBox.Text, "*", opt)
    Dim filteredFiles As New List(Of String)()
    For Each file As String In files
        Dim ext As String = file.Substring(file.LastIndexOf("."))
        If ".jpg .bmp .gif".IndexOf(ext) > -1 AndAlso file.EndsWith("desktop.bmp") = False AndAlso Not file = My.Settings.lastImageShown Then
            filteredFiles.Add(file)
        End If
    Next
    If filteredFiles.Count = 0 Then
        Return Nothing
    End If
    Dim filename As String = filteredFiles(rnd.Next(filteredFiles.Count))
    My.Settings.lastImageShown = filename
    My.Settings.Save()
    Return New Bitmap(filename)
End Function

Private Function getImageStyle(ByVal img As Bitmap) As desktopBackgroundStyle
    Dim smallestSize As Integer = Integer.Parse(Me.imageSizeTextBox.Text)
    Dim imgH As Integer = img.Height
    Dim imgW As Integer = img.Width
    Dim desktopH As Integer = Screen.PrimaryScreen.Bounds.Height
    Dim desktopW As Integer = Screen.PrimaryScreen.Bounds.Width
    Dim style As String
    If ((imgW > desktopW) OrElse (imgH > desktopH)) Then
        style = Me.largerThanScreenComboBox.Text
    ElseIf ((imgW <= smallestSize) AndAlso (imgH <= smallestSize)) Then
        style = Me.smallerThanImageSizeComboBox.Text
    Else
        style = Me.smallerThanScreenComboBox.Text
    End If
    Return CType(System.Enum.Parse(GetType(desktopBackgroundStyle), style), desktopBackgroundStyle)
End Function

Private Sub changeDesktopBackground()
    Dim img As Bitmap = getImageFile()
    If My.Computer.FileSystem.DirectoryExists(My.Settings.folderPath) = False Then
        Return
    End If
    If img Is Nothing Then
        MessageBox.Show("Sorry, no images located in specified folder.")
        Return
    Else
        Dim style As desktopBackgroundStyle = getImageStyle(img)
        WindowsAPIClass.setDesktopBackground(img, style)
    End If
End Sub

Private Sub setTimerInterval()
    Call KillTimer(Me.Handle, 1)
    If Me.useTimerByCheckBox.Checked Then
        If Me.timerIntervalComboBox.Text = "½ Hour" Then
            Call SetTimer(Me.Handle, 1, 1800000, AddressOf timerProc)
        ElseIf Me.timerIntervalComboBox.Text = "Hour" Then
            Call SetTimer(Me.Handle, 1, 3600000, AddressOf timerProc)
        ElseIf Me.timerIntervalComboBox.Text = "Day" Then
            Call SetTimer(Me.Handle, 1, 86400000, AddressOf timerProc)
        End If
    End If
End Sub

Private Sub timerProc(ByVal hwnd As IntPtr, ByVal uMsg As Integer, ByVal idEvent As Integer, ByVal dwTime As Integer)
    changeDesktopBackground()
End Sub
Reply With Quote
  #4  
Old 05-25-2007, 03:36 AM
jo0ls&quot;CallbackOnCollectedDelegate was detected&quot; error. jo0ls is offline
Senior Contributor

Forum Leader
* Expert *
 
Join Date: Feb 2005
Location: London
Posts: 1,050
Default

Argh, yes it works without the fancy parameters. I guess it just dumps them. (my fault for assuming I knew what the problem was). You can get away with no parameters, use a Sub for even fewer.

So, what was the real problem then??

A delegate is just a variable that stores a function. So, you can use them to pass a function to another function. Here you are passing your TimerProc sub in the API call so that it can call you back when the timer ticks.

Briefly, if you have an object, and it is no longer referenced by a variable, then it gets collected by the Garbage Collector and disappears, freeing memory. A Delegate is just another object. In your code, the delegate is created by "AddressOf timerProc" and is not referenced by any variable, and so it is free for garbage collection immediately after the api call.

You can't guarentee when the collector is going to swipe away an object. If you test your code with a small timer - say 5 seconds, then the garbage collector probably won't have found the delegate and removed it, so the callback works as it can be routed to the correct function. But if you have a long time period, then the delegate will be gone, and so you get the error about the delegate going AWOL.

Here's a quick test that will throw the error you described originally:

Code:
Imports System.Runtime.InteropServices Public Class settingsForm Private timerRunning As Boolean Private Delegate Sub TimerProcDelegate() <DllImport("User32")> _ Private Shared Function SetTimer(ByVal hwnd As Integer, _ ByVal nIDEvent As Integer, _ ByVal uElapse As Integer, _ ByVal lpTimerFunc As TimerProcDelegate) As UInteger End Function <DllImport("User32")> _ Private Shared Function KillTimer( _ ByVal hwnd As IntPtr, _ ByVal nIDEvent As Integer) As UInteger End Function Public Sub TimerProc() Me.Text = Now.ToString End Sub Private Sub settingsForm_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click If timerRunning Then KillTimer(Me.Handle, 1) Me.Text = "timer 1 killed" Else SetTimer(Me.Handle, 1, 5000, AddressOf TimerProc) Me.Text = "Timer 1 started..." GC.Collect() End If timerRunning = Not timerRunning End Sub End Class

Here the GC.Collect line forces the garbage collector into action.

So, to fix it. I said that the garbage collector looks for objects that are not referenced by a variable. You need to alter your code so that the delegate is referenced by a variable. Which is pretty easy:

Code:
Imports System.Runtime.InteropServices Public Class settingsForm Private timerRunning As Boolean Private Delegate Sub TimerProcDelegate() Private TimerProcDelegate1 As New TimerProcDelegate(AddressOf TimerProc) <DllImport("User32")> _ Private Shared Function SetTimer(ByVal hwnd As Integer, _ ByVal nIDEvent As Integer, _ ByVal uElapse As Integer, _ ByVal lpTimerFunc As TimerProcDelegate) As UInteger End Function <DllImport("User32")> _ Private Shared Function KillTimer( _ ByVal hwnd As IntPtr, _ ByVal nIDEvent As Integer) As UInteger End Function Public Sub TimerProc() Me.Text = Now.ToString End Sub Private Sub settingsForm_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click If timerRunning Then KillTimer(Me.Handle, 1) Me.Text = "timer 1 killed" Else SetTimer(Me.Handle, 1, 5000, TimerProcDelegate1) Me.Text = "Timer 1 started..." End If timerRunning = Not timerRunning End Sub End Class
Reply With Quote
  #5  
Old 05-25-2007, 02:25 PM
Scriptdaemon Scriptdaemon is offline
Newcomer
 
Join Date: May 2007
Posts: 3
Default

Now I get a Loaderlock error. I have limited time at the moment and won't be back until after the weekend, so I will be able to explain the new problem then.

I replied now because I wanted to say that I really appreciate the help you have given me, as I now understand how to use it a bit more.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
&quot;CallbackOnCollectedDelegate was detected&quot; error.
&quot;CallbackOnCollectedDelegate was detected&quot; error.
&quot;CallbackOnCollectedDelegate was detected&quot; error. &quot;CallbackOnCollectedDelegate was detected&quot; error.
&quot;CallbackOnCollectedDelegate was detected&quot; error.
&quot;CallbackOnCollectedDelegate was detected&quot; error.
&quot;CallbackOnCollectedDelegate was detected&quot; error. &quot;CallbackOnCollectedDelegate was detected&quot; error. &quot;CallbackOnCollectedDelegate was detected&quot; error. &quot;CallbackOnCollectedDelegate was detected&quot; error. &quot;CallbackOnCollectedDelegate was detected&quot; error. &quot;CallbackOnCollectedDelegate was detected&quot; error. &quot;CallbackOnCollectedDelegate was detected&quot; error.
&quot;CallbackOnCollectedDelegate was detected&quot; error.
&quot;CallbackOnCollectedDelegate was detected&quot; error.
 
&quot;CallbackOnCollectedDelegate was detected&quot; error.
&quot;CallbackOnCollectedDelegate was detected&quot; error.
 
-->