J'ai une application en C# qui utilise une dll codée en C à l'aide de
DllImport. Ca marche presque mais j'ai des bugs aléatoires (une erreur
quand le code non managé appelle la callback codée en C#) de temps en temps.
Je soupconne les callbacks d'être garbage collectées même si je fais
tout pour qu'elles ne le soient pas.
Les callbacks sont toutes passées d'un seul coup à l'aide d'une
structure appelée phCallbacks. Je récupère le pointeur du delegate que
je créé pour le mettre dans la structure, que je passe plus tard à ma
fonction C/non managée.
Quelqu'un aurait une idée ? J'ai manqué un truc ?
Merci.
NB: le code est sur http://rafb.net/paste/results/ec4TIb23.html
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
Mehdi
On Thu, 19 May 2005 13:25:32 +0200, Fabien Penso wrote:
J'ai une application en C# qui utilise une dll codée en C à l'aide de DllImport. Ca marche presque mais j'ai des bugs aléatoires (une erreur quand le code non managé appelle la callback codée en C#) de temps en temps.
Je soupconne les callbacks d'être garbage collectées même si je fais tout pour qu'elles ne le soient pas.
Quelqu'un aurait une idée ? J'ai manqué un truc ?
Pas trop d'idées mais a tu essayé d'appeler GC.KeepAlive pour chacun de tes delegate avant de les passer au code non manager afin de t'assurer qu''ils ne sont pas garbage collectés trop tot ?
On Thu, 19 May 2005 13:25:32 +0200, Fabien Penso wrote:
J'ai une application en C# qui utilise une dll codée en C à l'aide de
DllImport. Ca marche presque mais j'ai des bugs aléatoires (une erreur
quand le code non managé appelle la callback codée en C#) de temps en temps.
Je soupconne les callbacks d'être garbage collectées même si je fais
tout pour qu'elles ne le soient pas.
Quelqu'un aurait une idée ? J'ai manqué un truc ?
Pas trop d'idées mais a tu essayé d'appeler GC.KeepAlive pour chacun de tes
delegate avant de les passer au code non manager afin de t'assurer qu''ils
ne sont pas garbage collectés trop tot ?
On Thu, 19 May 2005 13:25:32 +0200, Fabien Penso wrote:
J'ai une application en C# qui utilise une dll codée en C à l'aide de DllImport. Ca marche presque mais j'ai des bugs aléatoires (une erreur quand le code non managé appelle la callback codée en C#) de temps en temps.
Je soupconne les callbacks d'être garbage collectées même si je fais tout pour qu'elles ne le soient pas.
Quelqu'un aurait une idée ? J'ai manqué un truc ?
Pas trop d'idées mais a tu essayé d'appeler GC.KeepAlive pour chacun de tes delegate avant de les passer au code non manager afin de t'assurer qu''ils ne sont pas garbage collectés trop tot ?
Fabien Penso
Mehdi wrote:
Pas trop d'idées mais a tu essayé d'appeler GC.KeepAlive pour chacun de tes delegate avant de les passer au code non manager afin de t'assurer qu''ils ne sont pas garbage collectés trop tot ?
Bon en fait j'ai la réponse, il faut que je garde les delegates et là je ne gardais que les pointeurs vers les delegates (a coup d'astuce à la con).
Donc le truc à se rappeler, c'est de s'assurer que les callbacks ne sont pas garbages collectées, sinon ça foire à un moment ou un autre. Dans le cas ou on passe une structure de callbacks les callbacks ne sont pas marshallés, il faut donc récupérer les pointeurs (voir le hack à la con dans le code) de chaque callback, les mettre dans la structure, et passer celle là à la fonction native; tout en gardant les delegates dans une autre structure.
Voir le code attaché (merci à Jonathan Pryor de Mono).
public class SIPphapi {
private phCallbacks callbacksfunc;
// We define type of callbacks public delegate void CallBackInt(int x, int y); public delegate void CallBackPtr(int x, IntPtr info); public delegate void CallBackStrings(String a, String b, String c);
# region struct de callback [StructLayout(LayoutKind.Sequential)] public struct phCallbacks { public IntPtr callProgress; public IntPtr transferProgress; public IntPtr confProgress; public IntPtr regProgress; public IntPtr msgProgress; public IntPtr onNotify; public phCallbacks(IntPtr c1, IntPtr t, IntPtr c2, IntPtr r, IntPtr m, IntPtr o) { callProgress = c1; confProgress = c2; msgProgress = m; onNotify = o; regProgress = r; transferProgress = t; } } // Holds the delegate for not being garbage collected private struct callBacksHolder { public CallBackPtr callProgress; public CallBackPtr transferProgress; public CallBackPtr confProgress; public CallBackInt regProgress; public CallBackPtr msgProgress; public CallBackStrings onNotify; public callBacksHolder(CallBackPtr c1, CallBackPtr t, CallBackPtr c2, CallBackInt r, CallBackPtr m, CallBackStrings o) { callProgress = c1; confProgress = c2; msgProgress = m; onNotify = o; regProgress = r; transferProgress = t; }
} #endregion
// use a msvcrt function to return a pointer from the delegate [DllImport("msvcrt")] public static extern IntPtr strncpy(Delegate pd, IntPtr src, int size); static IntPtr GetFunctionPtrFromDelegate(Delegate d) { // strncpy returns the buffer address (the marshaled delegate pointer). // We obviously don't copy anything return strncpy(d, IntPtr.Zero, 0); }
private callBacksHolder callbackdelegates; public SIPphapi(ISIPCallBacks callbacks) { this.callbackdelegates = new callBacksHolder( new CallBackPtr(callProgress), new CallBackPtr(transferProgress), new CallBackPtr(confProgress), new CallBackInt(regProgress), new CallBackPtr(msgProgress), new CallBackStrings(onNotify) );
Pas trop d'idées mais a tu essayé d'appeler GC.KeepAlive pour chacun de tes
delegate avant de les passer au code non manager afin de t'assurer qu''ils
ne sont pas garbage collectés trop tot ?
Bon en fait j'ai la réponse, il faut que je garde les delegates et là je
ne gardais que les pointeurs vers les delegates (a coup d'astuce à la con).
Donc le truc à se rappeler, c'est de s'assurer que les callbacks ne sont
pas garbages collectées, sinon ça foire à un moment ou un autre. Dans le
cas ou on passe une structure de callbacks les callbacks ne sont pas
marshallés, il faut donc récupérer les pointeurs (voir le hack à la con
dans le code) de chaque callback, les mettre dans la structure, et
passer celle là à la fonction native; tout en gardant les delegates dans
une autre structure.
Voir le code attaché (merci à Jonathan Pryor de Mono).
public class SIPphapi {
private phCallbacks callbacksfunc;
// We define type of callbacks
public delegate void CallBackInt(int x, int y);
public delegate void CallBackPtr(int x, IntPtr info);
public delegate void CallBackStrings(String a, String b, String c);
# region struct de callback
[StructLayout(LayoutKind.Sequential)]
public struct phCallbacks {
public IntPtr callProgress;
public IntPtr transferProgress;
public IntPtr confProgress;
public IntPtr regProgress;
public IntPtr msgProgress;
public IntPtr onNotify;
public phCallbacks(IntPtr c1, IntPtr t, IntPtr c2, IntPtr
r, IntPtr m, IntPtr o) {
callProgress = c1;
confProgress = c2;
msgProgress = m;
onNotify = o;
regProgress = r;
transferProgress = t;
}
}
// Holds the delegate for not being garbage collected
private struct callBacksHolder {
public CallBackPtr callProgress;
public CallBackPtr transferProgress;
public CallBackPtr confProgress;
public CallBackInt regProgress;
public CallBackPtr msgProgress;
public CallBackStrings onNotify;
public callBacksHolder(CallBackPtr c1, CallBackPtr t,
CallBackPtr c2,
CallBackInt r, CallBackPtr m, CallBackStrings o) {
callProgress = c1;
confProgress = c2;
msgProgress = m;
onNotify = o;
regProgress = r;
transferProgress = t;
}
}
#endregion
// use a msvcrt function to return a pointer from the delegate
[DllImport("msvcrt")]
public static extern IntPtr strncpy(Delegate pd, IntPtr src,
int size);
static IntPtr GetFunctionPtrFromDelegate(Delegate d) {
// strncpy returns the buffer address (the marshaled
delegate pointer).
// We obviously don't copy anything
return strncpy(d, IntPtr.Zero, 0);
}
private callBacksHolder callbackdelegates;
public SIPphapi(ISIPCallBacks callbacks) {
this.callbackdelegates = new callBacksHolder(
new CallBackPtr(callProgress),
new CallBackPtr(transferProgress),
new CallBackPtr(confProgress),
new CallBackInt(regProgress),
new CallBackPtr(msgProgress),
new CallBackStrings(onNotify)
);
Pas trop d'idées mais a tu essayé d'appeler GC.KeepAlive pour chacun de tes delegate avant de les passer au code non manager afin de t'assurer qu''ils ne sont pas garbage collectés trop tot ?
Bon en fait j'ai la réponse, il faut que je garde les delegates et là je ne gardais que les pointeurs vers les delegates (a coup d'astuce à la con).
Donc le truc à se rappeler, c'est de s'assurer que les callbacks ne sont pas garbages collectées, sinon ça foire à un moment ou un autre. Dans le cas ou on passe une structure de callbacks les callbacks ne sont pas marshallés, il faut donc récupérer les pointeurs (voir le hack à la con dans le code) de chaque callback, les mettre dans la structure, et passer celle là à la fonction native; tout en gardant les delegates dans une autre structure.
Voir le code attaché (merci à Jonathan Pryor de Mono).
public class SIPphapi {
private phCallbacks callbacksfunc;
// We define type of callbacks public delegate void CallBackInt(int x, int y); public delegate void CallBackPtr(int x, IntPtr info); public delegate void CallBackStrings(String a, String b, String c);
# region struct de callback [StructLayout(LayoutKind.Sequential)] public struct phCallbacks { public IntPtr callProgress; public IntPtr transferProgress; public IntPtr confProgress; public IntPtr regProgress; public IntPtr msgProgress; public IntPtr onNotify; public phCallbacks(IntPtr c1, IntPtr t, IntPtr c2, IntPtr r, IntPtr m, IntPtr o) { callProgress = c1; confProgress = c2; msgProgress = m; onNotify = o; regProgress = r; transferProgress = t; } } // Holds the delegate for not being garbage collected private struct callBacksHolder { public CallBackPtr callProgress; public CallBackPtr transferProgress; public CallBackPtr confProgress; public CallBackInt regProgress; public CallBackPtr msgProgress; public CallBackStrings onNotify; public callBacksHolder(CallBackPtr c1, CallBackPtr t, CallBackPtr c2, CallBackInt r, CallBackPtr m, CallBackStrings o) { callProgress = c1; confProgress = c2; msgProgress = m; onNotify = o; regProgress = r; transferProgress = t; }
} #endregion
// use a msvcrt function to return a pointer from the delegate [DllImport("msvcrt")] public static extern IntPtr strncpy(Delegate pd, IntPtr src, int size); static IntPtr GetFunctionPtrFromDelegate(Delegate d) { // strncpy returns the buffer address (the marshaled delegate pointer). // We obviously don't copy anything return strncpy(d, IntPtr.Zero, 0); }
private callBacksHolder callbackdelegates; public SIPphapi(ISIPCallBacks callbacks) { this.callbackdelegates = new callBacksHolder( new CallBackPtr(callProgress), new CallBackPtr(transferProgress), new CallBackPtr(confProgress), new CallBackInt(regProgress), new CallBackPtr(msgProgress), new CallBackStrings(onNotify) );