标签: pinvoke

在密封的类上实现IDisposable

我认为以前没有问过这个问题.我IDisposable对在密封类上实现的最佳方法感到困惑- 特别是一个不从基类继承的密封类.(也就是说,这是一个"纯密封的类",这是我的术语.)

也许你们有些人同意我的观点,因为实施指南IDisposable非常混乱.也就是说,我想知道我打算实施的方式IDisposable是充分和安全的.

我正在做一些P/Invoke代码,分配一个IntPtr通过Marshal.AllocHGlobal,自然,我想干净地处理我创建的非托管内存.所以我在考虑这样的事情

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public sealed class MemBlock : IDisposable
{
     IntPtr ptr;
     int length;

     MemBlock(int size)
     {
           ptr = Marshal.AllocHGlobal(size);
           length = size;
     }

     public void Dispose()
     {
          if (ptr != IntPtr.Zero)
          {
               Marshal.FreeHGlobal(ptr);
               ptr = IntPtr.Zero;
               GC.SuppressFinalize(this);
          }
     }

     ~MemBlock()
     {
           Dispose();
     }    
}
Run Code Online (Sandbox Code Playgroud)

我假设因为MemBlock完全是密封的,并且永远不会从另一个实现a的类中派生出来virtual protected Dispose(bool disposing).

那么,终结者是否必须?欢迎所有的想法.

c# pinvoke

24
推荐指数
3
解决办法
7531
查看次数

P/Invo in Mono

Linux 上Mono的Platform Invoke实现的当前状态是什么?在Solaris上?

.net linux mono pinvoke solaris

23
推荐指数
1
解决办法
3848
查看次数

为什么我会在这个简单的例子中得到"PInvokeStackImbalance"?

我正在创建一个非常简单的PInvoke示例:

extern "C" __declspec(dllexport) int Add(int a, int b)
{
    return a + b;
}

[DllImport("CommonNativeLib.dll")]
extern public static int Add(int a, int b);

return NativeMethods.Add(a, b);
Run Code Online (Sandbox Code Playgroud)

但每当我调用上面的NativeMethods.Add方法时,我都会得到以下托管调试助手:

检测到PInvokeStackImbalance消息:对PInvoke函数'CommonManagedLib!CommonManagedLib.NativeMethods :: Add'的调用使堆栈失衡.这很可能是因为托管PInvoke签名与非托管目标签名不匹配.检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配.

然后调用以预期的返回值完成,但是出现MDA消息既令人讨厌又令人担忧 - 我还没有完全理解PInvoke,但是从我读过的内容我很确定我的签名是正确的 - 什么我做错了吗?

这都是在32位操作系统上.

.net pinvoke extern

22
推荐指数
1
解决办法
2万
查看次数

通过Interop/pinvoke传递C#回调函数

我正在编写一个C#应用程序,它使用Interop服务来访问本机C++ DLL中的函数.我已经使用了大约10种不同的功能.

现在我不知道如何处理将回调作为参数传递,以便DLL可以调用我的代码.

这是DLL的函数原型:

typedef void (WINAPI * lpfnFunc)(const char *arg1, const char *arg2)
Run Code Online (Sandbox Code Playgroud)

并且允许我传递上述类型的函数:

int WINAPI SetFunc(lpfnFunc f)
Run Code Online (Sandbox Code Playgroud)

这是委托和函数定义的C#代码:

public delegate void Func(string arg1, string arg2);

public static void MyFunc(string arg1, string arg2)
Run Code Online (Sandbox Code Playgroud)

这是我的SetFunc Interop函数的C#代码:

[DllImport("lib.dll", CharSet = CharSet.Ansi)]
public static extern int SetFunc(Func lpfn);
Run Code Online (Sandbox Code Playgroud)

最后这里是我调用SetFunc函数并将其传递给我的回调的代码:

SetFunc(new Func(MyFunc));
Run Code Online (Sandbox Code Playgroud)

不幸的是,我的功能应该被调用.SetFunc函数的返回值是返回Success的错误代码,所以要么它没有调用我的函数,要么因为我的代码错误而无法正常工作.

c# pinvoke interop function callback

22
推荐指数
2
解决办法
1万
查看次数

AttachConsole(-1),但Console.WriteLine不会输出到父命令提示符?

如果我已经将我的程序设置为a Windows Application,并使用了AttachConsole(-1)API,那么如何Console.WriteLine从我启动应用程序的控制台写入?它不适合我.

如果它是相关的,我使用的是Windows 7 x64,并且我启用了UAC.提升似乎并没有解决问题,也没有使用start /wait.

更新

一些可能有用的其他背景:

我刚刚发现,如果我转到命令提示符并输入cmd /c MyProgram.exe,那么控制台输出就可以了.如果我启动命令提示符,打开cmd.exe子进程并从该子shell运行程序,情况也是如此.

我还尝试注销并重新登录,从开始菜单启动的cmd.exe(而不是右键单击 - >命令提示符)运行,并从console2实例运行.这些都不起作用.

背景

我已经阅读过其他网站和几个SO答案,我可以调用win32 API AttachConsole将我的Windows应用程序绑定到运行我的程序的控制台,所以我可以拥有一个"控制台应用程序和Windows应用程序" .

例如,这个问题:是否可以在C#/ .Net中将消息记录到cmd.exe?.

我已经编写了一堆逻辑来完成这项工作(使用其他几个API),并且我已经让其他所有方案都可以工作(包括重定向,其他人声称这些方案不起作用).剩下的唯一方案是Console.WriteLine写入我启动程序的控制台.从我读过的所有内容中,如果我使用它,它应该可以工作AttachConsole.

摄制

这是一个最小的样本 - 请注意,项目设置为Windows Application:

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;

class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        if (!AttachConsole(-1))
        {
            MessageBox.Show(
                new Win32Exception(Marshal.GetLastWin32Error())
                    .ToString()
                );
        }

        Console.WriteLine("Test");
    } …
Run Code Online (Sandbox Code Playgroud)

.net pinvoke winapi console-application

22
推荐指数
1
解决办法
1万
查看次数

从另一个进程获取win32线程的StartAddress

背景:

我在Win32中编写了一个多线程应用程序,我使用Process来自System.Diagnostics命名空间的类从C#代码开始.

现在,在C#代码中,我想获取在Win32应用程序中创建的每个线程的起始地址的名称/符号,以便我可以将与线程相关的信息(例如CPU使用情况)记录到数据库中.基本上,C#代码启动Win32应用程序的多个实例,监视它们,如果需要则终止,然后将info/error/exceptions/reason/etc记录到数据库.

为此,我已经包装了两个Win32 API viz.SymInitialize以及SymFromAddr我自己编写的程序友好API,如下所示:

extern "C"
{
    //wraps SymInitialize
    DllExport bool initialize_handler(HANDLE hModue);

    //wraps SymFromAddr
    DllExport bool get_function_symbol(HANDLE hModule, //in
                                       void *address,  //in
                                       char *name);    //out
}
Run Code Online (Sandbox Code Playgroud)

然后使用pinvoke从C#代码调用这些API.但它不起作用,并GetLastError提供126 错误代码,这意味着:

指定的模块无法找到

我传递Process.HandlehModule这两个函数; initialize_handler似乎工作,但get_function_symbol没有; 它给出了上述错误.我不确定我是否通过了正确的手柄.我尝试传递以下句柄:

Process.MainWindowHandle
Process.MainModule.BaseAddress
Run Code Online (Sandbox Code Playgroud)

两者都在第一步失败(即调用时initialize_handler).我Process.Threads[i].StartAddress作为第二个参数传递,这似乎是失败的原因,ProcessThread.StartAddress似乎是RtlUserThreadStart函数的地址,而不是特定于应用程序的启动函数的地址.在MSDN说一下吧:

每个Windows线程实际上都是在系统提供的函数中开始执行,而不是应用程序提供的函数.因此,主线程的起始地址与系统中的每个Windows进程相同(因为它表示系统提供的函数的地址).但是,StartAddress属性允许您获取特定于应用程序的起始函数地址.

但它没有说明如何使用ProcessThread.StartAddress获取特定于应用程序的startinbg函数地址.

题:

我的问题是从另一个应用程序(用C#编写)获取win32线程的起始地址,因为一旦我得到它,我将使用上面提到的API得到名称.那么如何获得起始地址?


我从C++代码测试了我的符号查找API.如果给出正确的地址,它可以很好地将地址解析为符号.

这是我的p/invoke声明:

[DllImport("UnmanagedSymbols.dll", SetLastError = true, …
Run Code Online (Sandbox Code Playgroud)

c# c++ dll pinvoke process

22
推荐指数
1
解决办法
6614
查看次数

在"托管到原生过渡"期间究竟发生了什么?

我知道CLR需要在某些情况下进行编组,但是让我说我​​有:

using System.Runtime.InteropServices;
using System.Security;

[SuppressUnmanagedCodeSecurity]
static class Program
{
    [DllImport("kernel32.dll", SetLastError = false)]
    static extern int GetVersion();

    static void Main()
    {
        for (; ; )
            GetVersion();
    }
}
Run Code Online (Sandbox Code Playgroud)

当我用调试器进入这个程序时,我总是看到:

鉴于没有需要完成的编组(对吗?),有人可以解释一下这种"托管到本地的过渡"中实际发生了什么,以及为什么有必要?

.net c# pinvoke unmanaged managed

22
推荐指数
3
解决办法
4846
查看次数

使用AllocConsole和目标体系结构x86时没有控制台输出

我有一个WinForms项目,如果用户想要一个调试控制台,我会分配一个控制台AllocConsole().

所有控制台输出都正常工作,目标架构设置为"任何CPU",但当我将其更改为"x86"时,它不输出任何内容(Console.Read()仍然按预期工作).如果我直接打开EXE,则输出有效.看起来Visual Studio将其重定向到它自己的"输出"窗口.

我也试过这个答案,但它没有用,我也尝试过Console.SetOut(GetStdHandle(-11)),但也没用.

将目标体系结构设置为"任何CPU"对我来说是没有选择的.

所以这是我的两个问题:

  • 为什么只有当目标体系结构设置为x86时才会出现这种情况?
  • 在Visual Studio中运行时如何输出到我的控制台?

.net c# pinvoke

22
推荐指数
4
解决办法
2万
查看次数

如何在C#中找到Mutex?

如何从C#中的互斥锁中找到获取互斥锁的?

如果mutex.WaitOne(timeout)超时,则返回false.但是,如何从互斥锁手柄中找到它?(也许使用p/invoke.)

更新:

public class InterProcessLock : IDisposable
{
    readonly Mutex mutex;

    public bool IsAcquired { get; private set; }

    public InterProcessLock(string name, TimeSpan timeout)
    {
        bool created;
        var security = new MutexSecurity();
        security.AddAccessRule(new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.Synchronize | MutexRights.Modify, AccessControlType.Allow));
        mutex = new Mutex(false, name, out created, security);
        IsAcquired = mutex.WaitOne(timeout);
    }

    #region IDisposable Members

    public void Dispose()
    {
        if (IsAcquired)
        {
            mutex.ReleaseMutex();
            IsAcquired = false;
        }
    }

    #endregion
}
Run Code Online (Sandbox Code Playgroud)

目前,我正在使用自己的属性IsAcquired来确定是否应该释放互斥锁.不是必要但更清楚,不是使用IsAcquired …

c# pinvoke synchronization mutex handle

21
推荐指数
2
解决办法
2万
查看次数

将C#委托的调用约定更改为CDECL

当我使用DotNet1.1时,我遇到了C#的这个问题

问题是这个.我有一个非托管的DLL,它有一个函数,它接受一个函数指针(以及其他参数).当我在C#代码中声明DLLImport时,我传递了一个委托.但是C#中的委托具有stdcall调用约定,而非托管函数需要cdecl函数指针.因此,我天真的做法导致了崩溃.然后我找到了以下内容:http://www.codeproject.com/KB/cs/cdeclcallback.aspx有些人编写了一个优秀的库,可以根据我的理解改变代理的调用约定,MSIL-hacking.事情进展顺利,直到......

我迁移到VS2008和新版本的.NET.在此版本下,上述库不起作用.我不是真正的C#或.NET专家,说实话,我几乎不了解他的库做了什么(虽然它是开源的),所以我甚至不想尝试将它适应新的.NET.但是,我希望更新版本的C#可以为我的问题提供更好的解决方案.

那么,SO专家,请帮我解决臀部疼痛:)

c# c++ pinvoke interop calling-convention

21
推荐指数
1
解决办法
9697
查看次数