我最近将.NET NLog日志记录组件集成到我们的一个应用程序中,这些应用程序纯粹是在非托管代码(在Visual Studio 6中编译的C++和VB6组件)中开发的.我们有一堆C++应用程序通过COM接口与NLog通信.
目前一切正常,但我注意到在程序终止期间弹出以下消息(在输出窗口中调试VS6中的C++组件;如果在IDE中调试NLog,则通过VS 2005调试NLog):
检测到LoaderLock消息:尝试在OS Loader锁定内执行托管执行.不要尝试在DllMain或图像初始化函数中运行托管代码,因为这样做会导致应用程序挂起.
DllMain如下:
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
_Module.Init(ObjectMap, hInstance);
DisableThreadLibraryCalls(hInstance);
}
else if (dwReason == DLL_PROCESS_DETACH)
_Module.Term();
return TRUE; // ok
}
Run Code Online (Sandbox Code Playgroud)
我的猜测_Module.Term();现在包括释放一些.NET引用(我在我的一个C++类中保留对NLog对象的引用,以避免每次都必须实例化和释放),这会导致弹出此警告.
我的问题:这可以安全地忽略吗?如果不是,那么什么是好的解决方法?(我能想到的最好的方法是实例化对该NLog对象的引用,并在每次要写入日志文件时释放它...不是最优雅的解决方案)
我有一个编译器,它将汇编语言编译为机器语言(在内存中).我的项目是在C#.net中.有没有办法在线程上运行内存?DEP如何防止它?
byte[] a:
01010101 10111010 00111010 10101011 ...
Run Code Online (Sandbox Code Playgroud) 我正在研究自定义调试引擎,当我将我的结构编组到IntPtrVisual Studio崩溃时(正在调试的那个崩溃而不是调试器).
我的结构只不过是:
public struct DocumentContext : IDebugDocumentContext2, IDebugCodeContext2
{
private string _fileName;
//.....Implementation of interfaces
}
Run Code Online (Sandbox Code Playgroud)
我的编组代码如下所示:
var documentContext = new DocumentContext(_node.FileName);
var size = Marshal.SizeOf(documentContext);
IntPtr ptrDocContext = Marshal.AllocHGlobal(size);
//This is what is crashing
//I don't have a chance to catch anything, it just craps out
//Event log says faulting dll is nt.dll
Marshal.StructureToPtr(documentContext, ptrDocContext, true);
Run Code Online (Sandbox Code Playgroud)
我错过了什么吗?
我有一个包含非托管C压缩库的C++/CLI项目,该项目由调用C++ Compress函数的MVC3项目引用.
一切都在本地工作正常,但当我将解决方案发布到Azure云时,我得到一个错误,说它无法找到模块/ dll:
无法加载文件或程序集"LZGEncoder.DLL"或其依赖项之一.指定的模块无法找到.
为什么找不到DLL文件?是去了错误的地方还是正在编译?有什么方法可以检查吗?谢谢!
我意识到这个应用程序的一个小C#移植允许从内存/流加载库,而不是使用通过文件系统工作的LoadLibrary API函数.用指针和匹配结果弄乱了一点......最后我有一些按预期工作的东西.我唯一的问题是对DLLMain的调用总是失败(我尝试使用Kernel32.dll和User32.dll).我无法理解为什么,我不知道如何调试问题.
这是我的项目(一个简单的32位控制台应用程序)的主要功能,它读取库,将其分配到内存并手动加载:
public static UInt32 Load(String libraryName)
{
if (libraries.ContainsKey(libraryName))
return libraries[libraryName];
String libraryPath = Path.Combine(Environment.SystemDirectory, libraryName);
Byte[] libraryBytes = File.ReadAllBytes(libraryPath);
fixed (Byte* libraryPointer = libraryBytes)
{
HeaderDOS* headerDOS = (HeaderDOS*)libraryPointer;
if ((UInt16)((headerDOS->Magic << 8) | (headerDOS->Magic >> 8)) != IMAGE_DOS_SIGNATURE)
return 0;
HeadersNT* headerNT = (HeadersNT*)(libraryPointer + headerDOS->LFANEW);
UInt32 addressLibrary = VirtualAlloc(headerNT->OptionalHeader.ImageBase, headerNT->OptionalHeader.SizeOfImage, AllocationType.RESERVE, MemoryProtection.READWRITE);
if (addressLibrary == 0)
addressLibrary = VirtualAlloc(0, headerNT->OptionalHeader.SizeOfImage, AllocationType.RESERVE, MemoryProtection.READWRITE);
if (addressLibrary == 0)
return 0;
Library* library = (Library*)Marshal.AllocHGlobal(sizeof(Library));
library->Address …Run Code Online (Sandbox Code Playgroud) 我现在正在学习很多关于托管和非托管解决方案的知识,我肯定会看到在生产中使用托管解决方案带来很多好处.
我看到推荐的模式是拥有一个开发环境,您可以在其中使用非托管解决方案,导出解决方案的非托管和托管版本,最后将托管解决方案部署到生产环境(可能首先用于测试的暂存环境).
这一切都非常好,干净,但并非没有陷阱.我最近遇到了以下情况:
我们使用上述模式为帐户实体创建和部署托管解决方案,并为客户安装.该解决方案包含用于与遗留系统集成的表单和其他一些内容
草图:
管理部分
场A场B.
场C场D.
在我不知情的情况下,客户继续使用"自定义"菜单自定义帐户表单.他所做的是创建一个新的表单部分,并将我们的托管解决方案中包含的一些自定义字段从原始部分移动到新部分
草图:
非管理部分
场A场B.
管理部分
场C场D.
由于这是一个非托管的更改,它优先于我的托管更改,破坏了对表单布局的破坏,而我做了一些其他更改(删除其他一些字段并更改表单上某些字段的顺序)
我当然尝试重新安装解决方案,同时使用"覆盖自定义"选项,该选项承诺覆盖对实体的非托管自定义,但这不会改变任何内容.
我还尝试删除新部分和作为非托管自定义移动的字段(使用自定义菜单),然后重新安装托管解决方案,希望这将以某种方式"撤消"非托管更改,并且diff机制将检测到有问题的字段仅出现在托管解决方案中,这将导致它们出现在原始位置.但事实证明,它似乎只是在雕刻更多的石头 - 这次告诉系统从表格中删除字段.
真的可以这样吗,一旦你对表单进行了非托管更改,你的托管表单就搞砸了?
有没有办法强制托管表单再次优先?
我当然可以对表单进行一些更多的非托管自定义,将字段放回原来的位置,但这只会推迟问题,直到下次我想要更改托管表单中字段的顺序 - 非托管更改来自上次仍然有优先权.
似乎我唯一的选择是从头开始,或者切换到帐户实体的非托管机制.
如果这看起来很糟糕,我应该使用托管属性来禁止在托管解决方案中对表单进行自定义.如果这是一个自定义实体,我会这样做,但我认为这对于像帐户实体这样的实体来说会有点严格.另一个经验教训可能是永远不会给客户sysadmin/customizer权限......
会喜欢这方面的其他想法和经验.
让我来描述我的问题 - 我有一个包含非托管句柄的结构(让我们称之为Mem).每当复制时,我都需要这个句柄来调用一个特定的方法(比如说"保留"或者保持引用计数).
换句话说,我需要一个在内部维护引用计数的结构(我在外部也有一个机制,但需要一种方法来调用该机制).
不幸的是,C#不允许我以任何方式这样做.
我也不能使Mem成为一个类,因为我将这些结构的数组传递给非托管代码,我不希望在传入它们之前逐个转换它们(只是引脚和传递).
有没有人知道可以应用于添加此行为的任何变通方法(IL Weaving等)?我相信IL不会阻止我这样做,只有C#,对吗?
我很乐意回答有关框架和限制的任何问题,但我不是在寻找 - "请改变你的设计"或"不要使用C#这个"答案,非常感谢.
我有一个托管的.Net类,它创建了我需要确保正确清理的非托管资源.
我有一个顺序结构:
[StructLayout(LayoutKind.Sequential)]
struct FooBar { ... }
Run Code Online (Sandbox Code Playgroud)
然后在构造函数中我有:
// Allocate the memory
var fb = new FooBar(...);
int length = Marshal.SizeOf(typeof(FooBar));
this.pointer = Marshal.AllocHGlobal(length);
Marshal.StructureToPtr(fb, this.pointer, false);
// Then I use this.pointer in extern calls
Run Code Online (Sandbox Code Playgroud)
然后在我的~Finaliser/ Dispose方法中,我使用Marshal.DestroyStructure或者Marshal.FreeHGlobal两者(如果是这样,以什么顺序)忍受我不泄漏内存?
奖金问题:
IDisposable类是否需要继承CriticalFinalizerObject以确保始终调用清理?Microsoft.Win32.SafeHandles我可以用来包装危险的非托管内存的类?