CallbackOnCollectedDelegate was detected
-
hi, I am getting this error when generating pdf docs from crystal report app (C# 2.0). CallbackOnCollectedDelegate was detected Message: A callback was made on a garbage collected delegate of type 'CrystalDecisions.ReportAppServer.DataSetConversion!CrystalDecisions.ReportAppServer.DataSetConversion.DataSetConverter+CrdbAdoPlusDelegate::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. I am creating pdf docs from crystal report app which is being hosted in console app. I have a report document with 6 sub reports. I am poppulating these sub reports on the report document by pushing a datatable/dataset. In doing that, I am instantiating report document once as a global variable. Then each next pdf doc will be using that same report document object but I am loading a new report doc every time new report(pdf doc) needs to be generated. After about 20 to 30 docs are generated I get error listed on top "CallbackOnCollectedDelegate was detected" with detail description also provided earlier. Reading this error made me think that if I put some kind of delay (1000 miliseconds) before loading report, it would help but did not solve my problem. It did went further than 20 to 30 docs to 104 docs but that error did come back. I would appreciate if some one can shed some light
Thanks Needy
-
hi, I am getting this error when generating pdf docs from crystal report app (C# 2.0). CallbackOnCollectedDelegate was detected Message: A callback was made on a garbage collected delegate of type 'CrystalDecisions.ReportAppServer.DataSetConversion!CrystalDecisions.ReportAppServer.DataSetConversion.DataSetConverter+CrdbAdoPlusDelegate::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. I am creating pdf docs from crystal report app which is being hosted in console app. I have a report document with 6 sub reports. I am poppulating these sub reports on the report document by pushing a datatable/dataset. In doing that, I am instantiating report document once as a global variable. Then each next pdf doc will be using that same report document object but I am loading a new report doc every time new report(pdf doc) needs to be generated. After about 20 to 30 docs are generated I get error listed on top "CallbackOnCollectedDelegate was detected" with detail description also provided earlier. Reading this error made me think that if I put some kind of delay (1000 miliseconds) before loading report, it would help but did not solve my problem. It did went further than 20 to 30 docs to 104 docs but that error did come back. I would appreciate if some one can shed some light
Thanks Needy
Hi, the message is clear: some code is calling back on an object that no longer exists. This happens because the PDF reporter is still using some event, while you are changing the report document. In simple sequential situations, a useful work-around may be to keep the previous document alive, so the following pseudo-code may show what I mean:
DOC myDoc;
DOC myPreviousDoc;void doMyDocuments() {
while(moreDocumentsToDo) {
myPreviousDoc=myDoc; // keep one alive
myDoc=new DOC();
... attach delegates
... process document
}
myPreviousDoc=null;
... maybe more processing
}:)
Luc Pattyn [My Articles]
-
Hi, the message is clear: some code is calling back on an object that no longer exists. This happens because the PDF reporter is still using some event, while you are changing the report document. In simple sequential situations, a useful work-around may be to keep the previous document alive, so the following pseudo-code may show what I mean:
DOC myDoc;
DOC myPreviousDoc;void doMyDocuments() {
while(moreDocumentsToDo) {
myPreviousDoc=myDoc; // keep one alive
myDoc=new DOC();
... attach delegates
... process document
}
myPreviousDoc=null;
... maybe more processing
}:)
Luc Pattyn [My Articles]
If I do this, do I need to put the 1000 milisecond detail between two report processing? And, would it release the resources or just give it some time to process the events? The reason why I am questoning this approach is that, i am looping through list of records and checking if data exists. Before doing this, i am setting loading report document in to the variable i have already decalred and using it. So if data doesn't exist for perticular id then I am immediately skipping that perticular record and get the next record from the datatable and try to process that record (and once again, I will load the report document in to the report document object I was using before). Also, If I recreate the report object by doc = new doc() when I am looping through it takes a lot of time to process the whole list. Is there another way where I can use the same doc and still not get the error. Like declare ReportDocument doc = new ReportDocument() as global variable within class then use this doc in the methods but keep loading different docs in to this same object so we can do away with reinitializing the reportdocument object and processing would be faster. Also, problem with creating a new report object is that, crystal report has limitation of number of new object set to 75 (named PrintJob limit which is registry entry item). I tried changing the limit to 1000 to 10000 and still didn't help so then I tried instantiating report object only one during whole process and just loading a different document everytime I need a new report to be generated. Please elaborate. -- modified at 16:38 Monday 16th April, 2007
Thanks Needy
-
If I do this, do I need to put the 1000 milisecond detail between two report processing? And, would it release the resources or just give it some time to process the events? The reason why I am questoning this approach is that, i am looping through list of records and checking if data exists. Before doing this, i am setting loading report document in to the variable i have already decalred and using it. So if data doesn't exist for perticular id then I am immediately skipping that perticular record and get the next record from the datatable and try to process that record (and once again, I will load the report document in to the report document object I was using before). Also, If I recreate the report object by doc = new doc() when I am looping through it takes a lot of time to process the whole list. Is there another way where I can use the same doc and still not get the error. Like declare ReportDocument doc = new ReportDocument() as global variable within class then use this doc in the methods but keep loading different docs in to this same object so we can do away with reinitializing the reportdocument object and processing would be faster. Also, problem with creating a new report object is that, crystal report has limitation of number of new object set to 75 (named PrintJob limit which is registry entry item). I tried changing the limit to 1000 to 10000 and still didn't help so then I tried instantiating report object only one during whole process and just loading a different document everytime I need a new report to be generated. Please elaborate. -- modified at 16:38 Monday 16th April, 2007
Thanks Needy
OK, then what about this: have two documents (instead of one) and use them in ping-pong so code could be like this:
DOC doc1=new DOC();
DOC doc2=new DOC();void doAllDocs() {
while (moreDocs) {
// interchange the docs
DOC temp=doc1;
doc1=doc2;
doc2=temp;
... handle one document, using doc1 (dont touch doc2 at all)
}The net result is while processing doc1, doc2 is still present to get finished. :)
Luc Pattyn [My Articles]
-
OK, then what about this: have two documents (instead of one) and use them in ping-pong so code could be like this:
DOC doc1=new DOC();
DOC doc2=new DOC();void doAllDocs() {
while (moreDocs) {
// interchange the docs
DOC temp=doc1;
doc1=doc2;
doc2=temp;
... handle one document, using doc1 (dont touch doc2 at all)
}The net result is while processing doc1, doc2 is still present to get finished. :)
Luc Pattyn [My Articles]
This did not help, I am still getting the error: CallbackOnCollectedDelegate was detected Message: A callback was made on a garbage collected delegate of type 'CrystalDecisions.ReportAppServer.DataSetConversion!CrystalDecisions.ReportAppServer.DataSetConversion.DataSetConverter+CrdbAdoPlusDelegate::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.
Thanks Needy
-
This did not help, I am still getting the error: CallbackOnCollectedDelegate was detected Message: A callback was made on a garbage collected delegate of type 'CrystalDecisions.ReportAppServer.DataSetConversion!CrystalDecisions.ReportAppServer.DataSetConversion.DataSetConverter+CrdbAdoPlusDelegate::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.
Thanks Needy
OK, first thing to figure out is which delegate is disappearing. So the main question is, do you ever create a new delegate, without assigning it to a class member ? The following shows good and bad situations:
class A {
EventHandler keepAlive;public void demo() { EventHandler dying=new EventHandler(something); callNativeMethod(dying); keepAlive=new EventHandler(something); callNativeMethod(keepAlive); }
}
The dying delegate can be collected at any time demo() has finished. :)
Luc Pattyn [My Articles]
-
OK, first thing to figure out is which delegate is disappearing. So the main question is, do you ever create a new delegate, without assigning it to a class member ? The following shows good and bad situations:
class A {
EventHandler keepAlive;public void demo() { EventHandler dying=new EventHandler(something); callNativeMethod(dying); keepAlive=new EventHandler(something); callNativeMethod(keepAlive); }
}
The dying delegate can be collected at any time demo() has finished. :)
Luc Pattyn [My Articles]
Well, I am not manipulating/adding/removing any delegates in my code. It is Crystal Report that is somehow removing (may be) the reference to the delegate. I have been trying to solve this issue for a couple of days but no luck yet. I will post my partial code tomorrow morning first thing. Looks like you are suggesting that I am declaring the event handle in which case I am not and it is CR that is I guess collecting this delegate before execution completes or may be not being properly handled. Please provide some kind of guidance
Thanks Needy
-
Well, I am not manipulating/adding/removing any delegates in my code. It is Crystal Report that is somehow removing (may be) the reference to the delegate. I have been trying to solve this issue for a couple of days but no luck yet. I will post my partial code tomorrow morning first thing. Looks like you are suggesting that I am declaring the event handle in which case I am not and it is CR that is I guess collecting this delegate before execution completes or may be not being properly handled. Please provide some kind of guidance
Thanks Needy
The problem seems to be one (or more) delegate is created, passed to native code, which preserves it for future reference, and then the gc collects it because it is not reachable anymore in the managed world. The remedy is to make sure there is a managed reference (hence my class variable "keepAlive"). As I expect only managed code to create delegates, if it is not your code, it must be the managed layer inside Crystal Report (assuming they have a native code product plus a managed layer to make it work under .NET). But then I expect a lot of people having the same trouble (assuming they have report jobs of similar complexity); but then it must be among the known bugs, and maybe a fix already exists... Having reread your original post, looks to me that post must be sufficient to trigger the CR people ... :)
Luc Pattyn [My Articles]
-
The problem seems to be one (or more) delegate is created, passed to native code, which preserves it for future reference, and then the gc collects it because it is not reachable anymore in the managed world. The remedy is to make sure there is a managed reference (hence my class variable "keepAlive"). As I expect only managed code to create delegates, if it is not your code, it must be the managed layer inside Crystal Report (assuming they have a native code product plus a managed layer to make it work under .NET). But then I expect a lot of people having the same trouble (assuming they have report jobs of similar complexity); but then it must be among the known bugs, and maybe a fix already exists... Having reread your original post, looks to me that post must be sufficient to trigger the CR people ... :)
Luc Pattyn [My Articles]
These are very hard to find, I encountered this in a System.Windows.Forms.NativeWindow class which was used to extend a Win32 app via a C++/CLR, vis afxwinforms CWinFormsControl implementation. Where due an a coding error; the ReleaseHandle() method was not being called during the Dispose operation of the NativeWindow. It would manifest it self most often as a crash when changing the focus to another application.