[C#] Callback was made on a garbage collected delegate of ..

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Hallo,
ik probeer een programma te schrijven voor mijn usbuirt remote. Hiervoor gebruik ik een .dll file van usbuirt zelf waar enkele functies in staan. Het basisprogramma werkte maar nu het uitgebreider is werkt het ineens niet meer. Ik krijg volgende fout:
A callback was made on a garbage collected delegate of type 'UsbUirtManagedWrapper!UsbUirt.Controller+ReceiveCallback::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.
De fout gebeurd wanneer ik de event: ir_Received opvang. Zet ik niets in die methode dan is er geen fout.

Stukjes code:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
namespace usbRemote
{
    public class frmMain : Form
    {
        public static Controller ir;
        public frmMain()
        {
            InitializeComponent();
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            //activationTimer.Start();
            //LoadProfiles();

            ir = new Controller();
            ir.BlinkOnReceive = true;
            ir.BlinkOnTransmit = true;
            ir.GenerateLegacyCodesOnReceive = true;

            ir.Received += new Controller.ReceivedEventHandler(ir_Received);
            ir.LearnCompleted += new Controller.LearnCompletedEventHandler(ir_LearnCompleted);
            ir.Learning += new Controller.LearningEventHandler(ir_Learning);
            ir.TransmitCompleted += new Controller.TransmitCompletedEventHandler(ir_TransmitCompleted);

        }




        //Events
        //--------------------------------------------------------
        void ir_Received(object sender, ReceivedEventArgs e)
        {
            SetIrReceived(e.IRCode); //hier gebeurd dan de fout

        }



Ik weet wel wat de fout enzo betekent maar begrijp het toch niet helemaal goed. (Is dan ook eerste keer dat ik met een unmanaged dll werk). Iemand die me opweg kan helpen?

Ik heb al veel hierover op internet gezocht/gelezen/geprobeerd maar niets maakt uit dus daarom vraag ik hier wat hulp :)

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:56
Hmm, blijkbaar vind de garbage collector dat je ir object niet langer nodig / gebruikt is ...

Een collega van me heeft ooit eens een gelijkaardig probleem gehad, zijn code zag er bv zo uit:
code:
1
2
3
4
5
public void Send()
{
    Sender s = new Sender();
    s.OnSend += ...
}
Op een gegeven moment was zijn 'Sender' (ik noem nu maar wat) object ook ge GC't. Door zijn object te declareren als een member van de class, was zijn probleem opgelost.
Echter, ik zie dat dit bij jou al het geval is. Maar, heb je een reden waarom je Controller instance (ir) static is ?
Wat als je die niet static maakt ?
Of, wat als je die initialiseert bij het declareren ?

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
En als je de GC een handje helpt met een hint?

^^ Met hem verder. Weird. Een reference vasthouden in en private field zou voldoende moeten zijn.

[ Voor 160% gewijzigd door RobIII op 21-07-2008 23:21 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:56
RobIII schreef op maandag 21 juli 2008 @ 23:15:
En als je de GC een handje helpt met een hint?
Ik zat daar ook nog aan te denken, maar ik kon er niet meer opkomen. 8)7

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Ik had dit ook laatst toen ik een Delegate naar Unmanaged code gaf. De GC wist (natuurlijk) niet dat er nog een refference naar was en ruimde hem op.

De oplossing was gewoon een extra refference naar de delegate bijhouden. Ik zal ook het topic op MSDN proberen te zoeken.

http://msdn.microsoft.com/en-us/library/43yky316(VS.80).aspx

[ Voor 11% gewijzigd door Woy op 22-07-2008 09:10 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • HawVer
  • Registratie: Februari 2002
  • Laatst online: 13-09 16:51
Als het event unmanaged code is, is het opslaan van de class als variabele niet altijd voldoende. Probeer eens explicitiet een reference naar de delegate op te slaan. Like:
C#:
1
2
3
4
5
6
7
private ReceivedEventHandler recieved;

private void frmMain_Load(object sender, EventArgs e)
{
  recieved  = new Controller.ReceivedEventHandler(ir_Received);
  ir.Received += recieved;
}


/edit.. rwb.. zit ik netjes een reply in elkaar te tikken, kom jij er tussen door.. :P

[ Voor 10% gewijzigd door HawVer op 22-07-2008 09:13 ]

http://hawvie.deviantart.com/


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
HawVer schreef op dinsdag 22 juli 2008 @ 09:13:
Als het event unmanaged code is, is het opslaan van de class als variabele niet altijd voldoende. Probeer eens explicitiet een reference naar de delegate op te slaan. Like:
C#:
1
2
3
4
5
6
7
private ReceivedEventHandler recieved;

private void frmMain_Load(object sender, EventArgs e)
{
  recieved  = new Controller.ReceivedEventHandler(ir_Received);
  ir.Received += recieved;
}


/edit.. rwb.. zit ik netjes een reply in elkaar te tikken, kom jij er tussen door.. :P
Hallo,
dit heb ik gedaan, helaas zonder succes. Geeft nog steeds dezelfde fout.
Ga nu even andere dingen proberen

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
RobIII schreef op maandag 21 juli 2008 @ 23:15:
En als je de GC een handje helpt met een hint?

^^ Met hem verder. Weird. Een reference vasthouden in en private field zou voldoende moeten zijn.
werkt ook niet helaas...

ik doe dus op het einde:


C#:
1
System.GC.KeepAlive(ir);


maar zonder resultaat

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
whoami schreef op maandag 21 juli 2008 @ 21:56:
Hmm, blijkbaar vind de garbage collector dat je ir object niet langer nodig / gebruikt is ...

Een collega van me heeft ooit eens een gelijkaardig probleem gehad, zijn code zag er bv zo uit:
C#:
1
2
3
4
5
public void Send()
{
    Sender s = new Sender();
    s.OnSend += ...
}
Op een gegeven moment was zijn 'Sender' (ik noem nu maar wat) object ook ge GC't. Door zijn object te declareren als een member van de class, was zijn probleem opgelost.
Echter, ik zie dat dit bij jou al het geval is. Maar, heb je een reden waarom je Controller instance (ir) static is ?
Wat als je die niet static maakt ?
Of, wat als je die initialiseert bij het declareren ?
Dit helpt ook niet. Static was idd niet nodig.
Ik heb nu (wat dus niet werkt):

C#:
1
2
3
4
5
6
7
8
9
private Controller ir = new Controller();

private void frmMain_Load(object sender, Eventargs e)
{
    ......

    //op het einde
    System.GC.KeepAlive(ir);
}

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
RobIII schreef op maandag 21 juli 2008 @ 23:15:
En als je de GC een handje helpt met een hint?

^^ Met hem verder. Weird. Een reference vasthouden in en private field zou voldoende moeten zijn.
helaas werkt dit dus ook niet. Dacht dat dit wel ging helpen eigenlijk... :(

Acties:
  • 0 Henk 'm!

  • HawVer
  • Registratie: Februari 2002
  • Laatst online: 13-09 16:51
Verwijderd schreef op dinsdag 22 juli 2008 @ 11:07:
[...]

helaas werkt dit dus ook niet. Dacht dat dit wel ging helpen eigenlijk... :(
Wat je nog zou kunnen proberen is de controller en de delegate of beide static of beide alleen private maken.
Eventueel kun je nog kijken of je wat aan dit artikel hebt:
http://msdn.microsoft.com/en-us/magazine/cc163606.aspx

http://hawvie.deviantart.com/


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Hoe ziet je controller class er dan uit? Ik vind het vreemd dat je aan een unmanaged dll met de += syntax eventhandlers toevoegt. Meestal heb je namenlijk een functie waar je de eventhandlers aan mee geeft.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • HawVer
  • Registratie: Februari 2002
  • Laatst online: 13-09 16:51
Verwijderd schreef op dinsdag 22 juli 2008 @ 11:07:
[...]
helaas werkt dit dus ook niet. Dacht dat dit wel ging helpen eigenlijk... :(
Het kan natuurlijk ook zo zijn dat het niet jouw code is die het probleem veroorzaakt. Die controller is die volledig unmanaged? Is dat je eigen source of is dat de source van iemand anders? Als dat van jezelf is kun je daar wat van laten zien?

http://hawvie.deviantart.com/


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Het lijkt me dat je code er iets als volgt uit ziet?
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class Controller : IDisposable
{
    private delegate void MyCallback();
    [DllImport("MyDll")]
    private extern static void RegisterCallback(MyCallback callback);
    [DllImport("MyDll")]
    private extern static void UnRegisterCallback(MyCallback callback);
    private MyCallback callback;

    public event EventHandler Event;

    public void Init()
    {
        callback = Controller_Event;
        RegisterCallback(callback);
    }

    private void Controller_Event()
    {
        OnEvent();
    }

    protected virtual void OnEvent()
    {
        if (Event != null)
        {
            Event(this, EventArgs.Empty);
        }
    }

    public void Dispose()
    {
        if(callback != null)
        {
            UnRegisterCallback(callback);
            callback = null;
        }
    }
}

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
rwb schreef op dinsdag 22 juli 2008 @ 11:59:
Het lijkt me dat je code er iets als volgt uit ziet?
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class Controller : IDisposable
{
    private delegate void MyCallback();
    [DllImport("MyDll")]
    private extern static void RegisterCallback(MyCallback callback);
    [DllImport("MyDll")]
    private extern static void UnRegisterCallback(MyCallback callback);
    private MyCallback callback;

    public event EventHandler Event;

    public void Init()
    {
        callback = Controller_Event;
        RegisterCallback(callback);
    }

    private void Controller_Event()
    {
        OnEvent();
    }

    protected virtual void OnEvent()
    {
        if (Event != null)
        {
            Event(this, EventArgs.Empty);
        }
    }

    public void Dispose()
    {
        if(callback != null)
        {
            UnRegisterCallback(callback);
            callback = null;
        }
    }
}
euhm nee. Die
Controller ir = new Controller();
die komt rechtstreeks uit de dll file die ik via "Add Reference" aan het project heb toegevoegd.
Dus ik heb in mijn project:
Using myDll;
en dan rechtstreeks:
myDll.Controller ir = new Controller();
Ik doe dus nergens DLLImport of iets dergelijks.
Ik heb dus zelf geen Controller klasse ofzo
Eigenlijk alle code die relevant is staat in de openings post.
HawVer schreef op dinsdag 22 juli 2008 @ 11:55:
[...]

Het kan natuurlijk ook zo zijn dat het niet jouw code is die het probleem veroorzaakt. Die controller is die volledig unmanaged? Is dat je eigen source of is dat de source van iemand anders? Als dat van jezelf is kun je daar wat van laten zien?
Ik heb dus een Dll bestand:
UsbUirtManagedWrapper.dll
Hierin zit (via Object Browser te zien):
namespace UsbUirt
Klasse Controller met daarin enkele methods (Learn, LearnAsync, Transmit, TransmitAsync)
en enkele Events (LearnCompleted, Learning, Received, TransmitCompleted)

Ik heb even een screenshot gemaakt, dat maakt het misschien iets duidelijker:
http://www.plaatjesupload.nl/bekijken/816209.html

http://www.plaatjesupload.nl/bekijken/816211.html

Misschien dat dit het iets duidelijker maakt?

[ Voor 29% gewijzigd door Verwijderd op 22-07-2008 12:38 ]


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Maar die UsbUirtManagedWrapper.dll is dus al een Managed dll. Weet je zeker dat de fout niet al daar in zit? Jij passed namenlijk zelf helemaal geen delegate naar Unmanaged code

[ Voor 24% gewijzigd door Woy op 22-07-2008 12:59 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
rwb schreef op dinsdag 22 juli 2008 @ 12:58:
Maar die UsbUirtManagedWrapper.dll is dus al een Managed dll. Weet je zeker dat de fout niet al daar in zit? Jij passed namenlijk zelf helemaal geen delegate naar Unmanaged code
Mnja, dat zou natuurlijk kunnen maar dit is de officieele dll die bij het apparaat (een usb apparaat) werd uitgegeven. Dus opzich zou die toch wel een normaal receive event moeten kunnen opvangen. Het ding is wel, toen mijn programma nog erg basic was werkte het wel en kreeg ik deze fout in 1 van de 100 toetsindrukken ofzo (zéér zelden dus). Nu heb ik het programma wat gebruiksvriendelijker etc gemaakt en nu krijg ik die fout dus iedere keer...

Het lijkt me ook sterk dat ze een .dll uitgeven met zo'n zware fout erin? :)

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Kijk eens met reflector hoe de dll in elkaar steekt, en dan met name hoe het event gefired word waar je jij op subscribed

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
rwb schreef op dinsdag 22 juli 2008 @ 13:53:
Kijk eens met reflector hoe de dll in elkaar steekt, en dan met name hoe het event gefired word waar je jij op subscribed
al geprobeerd maar Reflector zegt:
Geen CLI header gevonden

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
En als je met ILDASM kijkt?

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
rwb schreef op dinsdag 22 juli 2008 @ 14:00:
En als je met ILDASM kijkt?
daarmee lukt het wel (kende dat programma niet).
Maar eerlijk gezegd snap ik niet goed waar ik naartoe moet zoeken of moet kijken.
Ik heb hier een screenshot van het belangrijkste gedeelte. Misschien dat dit u iets zegt.
http://www.plaatjesupload.nl/bekijken/816331.html

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Het lijkt mij gewoon een bug in de dll die je gekregen hebt. Ik heb de dll die je gestuurd heb met Reflector geopend ( Lukte bij mij wel gewoon ) gekeken, en hij set in deze functie de callback
C#:
1
2
3
4
5
6
7
8
9
10
[DllImport("uuirtdrv.dll", SetLastError=true)]
private static extern bool UUIRTSetReceiveCallback(IntPtr hDrvHandle, ReceiveCallback receiveProc, IntPtr userData);

private void SetReceiveCallback()
{
    if (!UUIRTSetReceiveCallback(this._hDrvHandle, new ReceiveCallback(this.ReceiveCallbackProc), IntPtr.Zero))
    {
        Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
    }
}

Hier word dus een Delegate naar unmanaged code gegeven waarna er geen refference meer naar is.

[ Voor 13% gewijzigd door Woy op 22-07-2008 16:21 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
rwb schreef op dinsdag 22 juli 2008 @ 16:20:
Het lijkt mij gewoon een bug in de dll die je gekregen hebt. Ik heb de dll die je gestuurd heb met Reflector geopend ( Lukte bij mij wel gewoon ) gekeken, en hij set in deze functie de callback
C#:
1
2
3
4
5
6
7
8
9
10
[DllImport("uuirtdrv.dll", SetLastError=true)]
private static extern bool UUIRTSetReceiveCallback(IntPtr hDrvHandle, ReceiveCallback receiveProc, IntPtr userData);

private void SetReceiveCallback()
{
    if (!UUIRTSetReceiveCallback(this._hDrvHandle, new ReceiveCallback(this.ReceiveCallbackProc), IntPtr.Zero))
    {
        Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
    }
}

Hier word dus een Delegate naar unmanaged code gegeven waarna er geen refference meer naar is.
Alvast enorm bedankt.
hmm. Het is toch in Reflector.NET dat je dit hebt geopend hé? Want dat lukt bij mij dus echt niet. Raar...

Maar je zult wel gelijk hebben met wat je hier zegt maar heb je dan nog enig idee hoe het voor mij werkend te krijgen is? :(

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Met deze reflector ( http://www.aisto.com/roed...nload.aspx?File=Reflector )

Hoe je het werkend zou kunnen krijgen? Ik zou eerst contact opnemen met de leverancier van de dll, mischien hebben ze wel een fix ervoor.

Anders zou je zelf een wrapper om de uuirtdrv.dll kunnen maken, of ( maar ik weet niet of dat mag van de leverancier ) je zou de code kunnen decompileren en dan een wijziging kunnen maken.

Dit zou het op moeten lossen
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
[DllImport("uuirtdrv.dll", SetLastError=true)] 
private static extern bool UUIRTSetReceiveCallback(IntPtr hDrvHandle, ReceiveCallback receiveProc, IntPtr userData); 

private ReceiveCallback myCallBack;

private void SetReceiveCallback() 
{
    myCallBack = new ReceiveCallback(this.ReceiveCallbackProc);
    if (!UUIRTSetReceiveCallback(this._hDrvHandle, myCallBack, IntPtr.Zero)) 
    { 
        Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
    } 
}

En dan bij het disposen netjes opruimen.

edit:
Wat je eventueel zou kunnen doen, maar wat niet echt optimaal is, is via reflection _hDrvHandle uitlezen en zelf UUIRTSetReceiveCallback aanroepen en dus je eigen Callback beheren. Wat ik in de dll zag gebeurt er niet meer dan het aanroepen van het Received event. Je moet dan alleen wel oppassen dat je device niet al disposed is als je de aanroep doet.

[ Voor 15% gewijzigd door Woy op 22-07-2008 17:05 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
rwb schreef op dinsdag 22 juli 2008 @ 16:37:
Met deze reflector ( http://www.aisto.com/roed...nload.aspx?File=Reflector )

Hoe je het werkend zou kunnen krijgen? Ik zou eerst contact opnemen met de leverancier van de dll, mischien hebben ze wel een fix ervoor.

Anders zou je zelf een wrapper om de uuirtdrv.dll kunnen maken, of ( maar ik weet niet of dat mag van de leverancier ) je zou de code kunnen decompileren en dan een wijziging kunnen maken.

Dit zou het op moeten lossen
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
[DllImport("uuirtdrv.dll", SetLastError=true)] 
private static extern bool UUIRTSetReceiveCallback(IntPtr hDrvHandle, ReceiveCallback receiveProc, IntPtr userData); 

private ReceiveCallback myCallBack;

private void SetReceiveCallback() 
{
    myCallBack = new ReceiveCallback(this.ReceiveCallbackProc);
    if (!UUIRTSetReceiveCallback(this._hDrvHandle, myCallBack, IntPtr.Zero)) 
    { 
        Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
    } 
}

En dan bij het disposen netjes opruimen.

edit:
Wat je eventueel zou kunnen doen, maar wat niet echt optimaal is, is via reflection _hDrvHandle uitlezen en zelf UUIRTSetReceiveCallback aanroepen en dus je eigen Callback beheren. Wat ik in de dll zag gebeurt er niet meer dan het aanroepen van het Received event. Je moet dan alleen wel oppassen dat je device niet al disposed is als je de aanroep doet.
Hallo,
enorm bedankt voor deze moeite allemaal en de vele uitleg. Ik heb via leverancier de sourcecode van de .dll gekregen en uw wijzigingen aangebracht. Nu werkt het volledig.

Enorm bedankt! O+ 8)

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Zorg dat je in de ClearReceiveCallback ieder geval de myCallBack weer op null zet. Dan kan hij wel ge GC't worden. Het haalt niet zo heel veel uit, maar het is wel zo netjes.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”

Pagina: 1