Проблемы при просмотре отчета с машины, на которой не установлен Fastreport.net
При запуске отчета с машины, на которой не установлен FastReport.NET, возникает исключение "System.IO.FileNotFoundException: Невозможно загрузить файл или сборку \"FastReport, Version=1.4.12.0, Culture=neutral, PublicKeyToken=db7e5ce63278458c\" или один из зависимых от них компонентов. Не удается найти указанный файл.":"FastReport, Version=1.4.12.0, Culture=neutral, PublicKeyToken=db7e5ce63278458c"
Трассировка:
в System.Signature._GetSignature(SignatureStruct& signature, Void* pCorSig, Int32 cCorSig, IntPtr fieldHandle, IntPtr methodHandle, IntPtr declaringTypeHandle)
в System.Signature.GetSignature(SignatureStruct& signature, Void* pCorSig, Int32 cCorSig, RuntimeFieldHandle fieldHandle, RuntimeMethodHandle methodHandle, RuntimeTypeHandle declaringTypeHandle)
в System.Signature..ctor(RuntimeFieldHandle fieldHandle, RuntimeTypeHandle declaringTypeHandle)
в System.Reflection.RtFieldInfo.get_FieldType()
в System.Reflection.RtFieldInfo.GetOneTimeFlags()
в System.Reflection.RtFieldInfo.InternalSetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, CultureInfo culture, Boolean doVisibilityCheck, Boolean doCheckConsistency)
в System.Reflection.RtFieldInfo.InternalSetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, CultureInfo culture, Boolean doVisibilityCheck)
в System.Reflection.RtFieldInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, CultureInfo culture)
в qenkKr3sLuA2VuH2x8.9oeHvTQ1k9dVJNvTH7.YSJAbu2C3(String , Object )
в qenkKr3sLuA2VuH2x8.9oeHvTQ1k9dVJNvTH7.Ef38gNOqM()
в qenkKr3sLuA2VuH2x8.9oeHvTQ1k9dVJNvTH7.BemEBWqd2(Object )
в qenkKr3sLuA2VuH2x8.9oeHvTQ1k9dVJNvTH7.B0Dfqkgea()
в qenkKr3sLuA2VuH2x8.9oeHvTQ1k9dVJNvTH7.0KvIVgbeU()
в FastReport.Report.tOZtoxwPY()
в FastReport.Report.Prepare(Boolean append)
в FastReport.Report.Show(Boolean modal, Form owner)
в FastReport.Report.Show()
в Person.Scan.PhotoEditor._PrintBadge(Int32[] tabNumbers)"
Код, вызывающий отчет: (отчет размещается в файле ресурсов, данные регистрируются в коде, сгенерированом дизайнером VS).
try {
this.report1.Show();
} catch(Exception ex) {
string _msg=string.Empty;
for(Exception _ex=ex;_ex!=null;_ex=ex.InnerException) {
_msg+=string.Format("{0}: {1}\n",_ex.GetType().FullName,_ex.Message);
}
MessageBox.Show(_msg,"Person.Scan.dll",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
В результате анализа удалось выявить участок кода (в FastReport.dll), приводящий к ошибке:
файл AssemblyDescriptor.cs, строка 62:
58: private void InitField(string name, object c)
59: {
60: FieldInfo info = Instance.GetType().GetField(name,
61: BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
62: info.SetValue(Instance, c);
63: }
метод SetValue(...) приводит к исключению, в случае, если отчет скомпилирован в память. Если его скомпилировать в файл, то все работает нормально.
Проблема в том, что в коде, компилирующем отчет, жестко протисано, что компилировать нужно в память (файл AssemblyDescriptor.cs, строка 349):
344: using (CodeDomProvider provider = Report.CodeHelper.GetCodeProvider())
345: {
346: CompilerParameters cp = new CompilerParameters();
347: AddFastReportAssemblies(cp.ReferencedAssemblies);
348: AddReferencedAssemblies(cp.ReferencedAssemblies);
349: cp.GenerateInMemory = true;
350: // sometimes the system temp folder is not accessible...
351: if (Config.TempFolder != null)
352: cp.TempFiles = new TempFileCollection(Config.TempFolder, false);
353: CompilerResults cr = provider.CompileAssemblyFromSource(cp, FScriptText.ToString());
Конечно можно работать с отчетом, сохраненным ввиде класса, но это не решение проблемы.
Возможно ли исправить эту ситуацию?
В дополнение: приложение, вызывающее отчет, иначально unmanaged, затем загружается managed код, который, собственно, и вызывает отчет
Трассировка:
в System.Signature._GetSignature(SignatureStruct& signature, Void* pCorSig, Int32 cCorSig, IntPtr fieldHandle, IntPtr methodHandle, IntPtr declaringTypeHandle)
в System.Signature.GetSignature(SignatureStruct& signature, Void* pCorSig, Int32 cCorSig, RuntimeFieldHandle fieldHandle, RuntimeMethodHandle methodHandle, RuntimeTypeHandle declaringTypeHandle)
в System.Signature..ctor(RuntimeFieldHandle fieldHandle, RuntimeTypeHandle declaringTypeHandle)
в System.Reflection.RtFieldInfo.get_FieldType()
в System.Reflection.RtFieldInfo.GetOneTimeFlags()
в System.Reflection.RtFieldInfo.InternalSetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, CultureInfo culture, Boolean doVisibilityCheck, Boolean doCheckConsistency)
в System.Reflection.RtFieldInfo.InternalSetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, CultureInfo culture, Boolean doVisibilityCheck)
в System.Reflection.RtFieldInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, CultureInfo culture)
в qenkKr3sLuA2VuH2x8.9oeHvTQ1k9dVJNvTH7.YSJAbu2C3(String , Object )
в qenkKr3sLuA2VuH2x8.9oeHvTQ1k9dVJNvTH7.Ef38gNOqM()
в qenkKr3sLuA2VuH2x8.9oeHvTQ1k9dVJNvTH7.BemEBWqd2(Object )
в qenkKr3sLuA2VuH2x8.9oeHvTQ1k9dVJNvTH7.B0Dfqkgea()
в qenkKr3sLuA2VuH2x8.9oeHvTQ1k9dVJNvTH7.0KvIVgbeU()
в FastReport.Report.tOZtoxwPY()
в FastReport.Report.Prepare(Boolean append)
в FastReport.Report.Show(Boolean modal, Form owner)
в FastReport.Report.Show()
в Person.Scan.PhotoEditor._PrintBadge(Int32[] tabNumbers)"
Код, вызывающий отчет: (отчет размещается в файле ресурсов, данные регистрируются в коде, сгенерированом дизайнером VS).
try {
this.report1.Show();
} catch(Exception ex) {
string _msg=string.Empty;
for(Exception _ex=ex;_ex!=null;_ex=ex.InnerException) {
_msg+=string.Format("{0}: {1}\n",_ex.GetType().FullName,_ex.Message);
}
MessageBox.Show(_msg,"Person.Scan.dll",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
В результате анализа удалось выявить участок кода (в FastReport.dll), приводящий к ошибке:
файл AssemblyDescriptor.cs, строка 62:
58: private void InitField(string name, object c)
59: {
60: FieldInfo info = Instance.GetType().GetField(name,
61: BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
62: info.SetValue(Instance, c);
63: }
метод SetValue(...) приводит к исключению, в случае, если отчет скомпилирован в память. Если его скомпилировать в файл, то все работает нормально.
Проблема в том, что в коде, компилирующем отчет, жестко протисано, что компилировать нужно в память (файл AssemblyDescriptor.cs, строка 349):
344: using (CodeDomProvider provider = Report.CodeHelper.GetCodeProvider())
345: {
346: CompilerParameters cp = new CompilerParameters();
347: AddFastReportAssemblies(cp.ReferencedAssemblies);
348: AddReferencedAssemblies(cp.ReferencedAssemblies);
349: cp.GenerateInMemory = true;
350: // sometimes the system temp folder is not accessible...
351: if (Config.TempFolder != null)
352: cp.TempFiles = new TempFileCollection(Config.TempFolder, false);
353: CompilerResults cr = provider.CompileAssemblyFromSource(cp, FScriptText.ToString());
Конечно можно работать с отчетом, сохраненным ввиде класса, но это не решение проблемы.
Возможно ли исправить эту ситуацию?
В дополнение: приложение, вызывающее отчет, иначально unmanaged, затем загружается managed код, который, собственно, и вызывает отчет
Комментарии
Если сборка на компьютере разработчика в GAC не установлена, то нужно с приложением поставлять используемые в нем dll-файлы FastReport.
Обо всем этом можно почитать в руководстве для программистов по FastReport .NET, в разделах Установка сборок в GAC и Распространение.
Руководство пользователя можно скачать здесь в разделе Документация.