标签: pinvoke

对象是否有可能"固定"自己并避免垃圾回收?

我正在尝试编写一个System.Media.SoundPlayer使用waveOut...API的替代品.当传递的文件/流完成播放时,此API会对我的SoundPlayer版本中的方法进行回调.

如果我创建一个表单范围的SoundPlayer实例并播放一些东西,一切正常,因为表单使对象保持活动状态,因此委托是活着的来接收回调.

如果我在这样的按钮点击事件中使用它:

SoundPlayer player = new SoundPlayer(@"C:\whatever.wav");
player.Play();
Run Code Online (Sandbox Code Playgroud)

...它在99%的时间内工作正常,但偶尔(并经常在文件很长的情况下)SoundPlayer对象在文件完成之前被垃圾收集,因此代理不再接收回调,我得到一个丑陋的错误.

我知道如何使用"固定"对象GCHandle.Alloc,但只有当其他东西可以挂在手柄上时.对象是否有任何方法可以在内部固定自身,然后在一段时间(或完成播放)后取消固定?如果我尝试GCHandle.Alloc (this, GCHandleType.Pinned);,我得到一个运行时异常"对象包含非原始或非blittable数据."

.net c# pinvoke garbage-collection

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

帮助在C#中使用PInvoke CreateDirectory()

我在VS2010中使用C#for WinForms应用程序,我需要创建一个目录,其中路径对于.NET方法而言太大(我相信248字符串限制),并且跨越了谷歌的建议以使用Unicode Win32 CreateDirectory( ).我最初尝试使用Unicode调用它并传递参数,但在几次尝试失败之后,我已经减少了代码并且使用了完全正确的代码:

http://www.pinvoke.net/default.aspx/Structures/SECURITY_ATTRIBUTES.html

我仍然得到同样的错误:

捕获到System.AccessViolationException Message =尝试读取或写入受保护的内存.这通常表明其他内存已损坏.

不可否认,我对调用Win32函数一无所知,我真的只是拉动我在网上找到的并试图学习.谁能告诉我我做错了什么?删除问题的非必要代码,我有:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Text;

namespace RFCGenerator
{

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    {
        public int nLength;
        public IntPtr lpSecurityDescriptor;
        public int bInheritHandle;
    }

    public class RFC
    {

        [DllImport("kernel32.dll")]
        static extern bool CreateDirectory(string lpPathName, SECURITY_ATTRIBUTES lpSecurityAttributes);   

        protected void CopyDirectory(Uri Source, Uri Destination)
        {

            SECURITY_ATTRIBUTES lpSecurityAttributes = new SECURITY_ATTRIBUTES();
            DirectorySecurity security = new DirectorySecurity();
            lpSecurityAttributes.nLength = Marshal.SizeOf(lpSecurityAttributes);
            byte[] src = …
Run Code Online (Sandbox Code Playgroud)

c# pinvoke

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

从Windows C函数返回字符串

我是C和C++中纯Windows API级功能的完全新手,并且最近一直在尝试使用.NET互操作性.我已经构建了一个简单的库,它已经成功地将数值(int/float等)返回给.NET调用者,但是我没有运气好的字符串.

我尝试了各种不同的数据类型,但似乎都没有:LPSTR,LPCSTR,LPCTSTR和LPCWSTR.不可否认,我没有尝试过char*.此外,一旦设置了一个方法来返回一个字符串,它是否需要.NET作为特定数据类型进行编组,还是可以直接读入System.String对象?我已经尝试解析为IntPtr然后转换为字符串,但这不起作用.

.net c pinvoke winapi interop

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

如何从C#调用SHChangeNotify,无错误14007

我正在编写可以更新文件的代码(多么罕见且令人兴奋!).当文件更新后,我需要Windows资源管理器再次调用覆盖扩展,以便我总是在文件上有正确的覆盖.我想我会用一些p/invoke技巧来做这件事(看看TortoiseSVN是如何做的),但我总是得到错误14007并且无法找到原因.这是代码:

IntPtr ptr = Marshal.StringToHGlobalUni(FullName);
Shell.SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSH, ptr, IntPtr.Zero);
Win32Exception w = new Win32Exception(Marshal.GetLastWin32Error());
LOG.ErrorFormat("Error {0} calling SHChangeNotify : {1}", w.NativeErrorCode, w.Message);
Marshal.FreeHGlobal(ptr)
Run Code Online (Sandbox Code Playgroud)

Fullname是已更新文件的路径.我收到以下错误:

Error 14007 calling SHChangeNotify : The requested lookup key was not found in any active activation context
Run Code Online (Sandbox Code Playgroud)

我在这做错了什么?

仅供参考:

[DllImport("Shell32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern void SHChangeNotify(HChangeNotifyEventID wEventId, HChangeNotifyFlags uFlags, IntPtr dwItem1, IntPtr dwItem2);

SHCNE_UPDATEITEM = 0x00002000
SHCNF_PATH = SHCNF_PATHW = 0x0005
SHCNF_FLUSH = 0x1000
Run Code Online (Sandbox Code Playgroud)

c# pinvoke shell32

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

Application.Exit需要调用两次

我有一个Main方法,它创建一个名为SysTrayApp的消息循环:

void Main()
{
    Application.Run(new SysTrayApp());
}  
Run Code Online (Sandbox Code Playgroud)

我的SysTrayApp类将ContextMenu添加到System Tray图标,然后启动另一个名为的消息循环MouseHook.MouseHook是一个用于管理鼠标事件的类.(以此课程为蓝本.)

class SysTrayApp : Form
{           
    public SysTrayApp()
    {
        // Does some GUI work    
        // Then starts another message loop
        Application.Run(new MouseHook());
    }
}
Run Code Online (Sandbox Code Playgroud)

_

class MouseHook : Form
{           
    public MouseHook()
    {
        // Does some hooking stuff      
    }
}
Run Code Online (Sandbox Code Playgroud)

在SysTrayApp中,Application.Exit()当用户从上下文菜单中选择"退出"选项时调用.问题是我必须调用Exit两次(或添加另一个Application.Exit)才能结束应用程序.这是预期的,但我觉得我这样做是错误的.打电话Application.Exit()两次对我来说似乎不对,但我是C#世界的新手.应该SysTrayAppMouseHook一个大班组合?MouseHook似乎它不应该是Windows.Form的一部分.也许MouseHook需要在一个新的线程?有什么建议?

编辑:哎呀.MouseHook没有第三个Application.Run()

我想我是在想这个.还在探索C#,就像我说的那样.但这是有效的:

Application.Run(new SysTrayApp());Main()是你所需要的.要启动MouseHook …

.net c# pinvoke winforms

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

如何从PInvoke本机回调中返回StringBuilder或其他字符串缓冲区

我想要一个干净的方法来增加StringBuilder()的大小,因为本地代码需要填充,下面的回调方法看起来很干净,但不知怎的,我们得到缓冲区的副本而不是实际的缓冲区 - 我感兴趣的是解释和解决方案(最好坚持回调类型分配,因为只要它可以工作就会很好和干净).

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace csharpapp
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var buffer = new StringBuilder(12);
            // straightforward, we can write to the buffer but unfortunately
            // cannot adjust its size to whatever is required
            Native.works(buffer, buffer.Capacity); 
            Console.WriteLine(buffer);

            // try to allocate the size of the buffer in a callback - but now
            // it seems only a copy of the buffer is passed to native code
            Native.foo(size => …
Run Code Online (Sandbox Code Playgroud)

c# pinvoke stringbuilder

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

SetForegroundWindow不适用于最小化的过程

在此主题上找不到任何好的答案,因此也许有人可以帮我。我正在制作一个小型个人程序,希望将某个应用程序放在前台。它已经可以工作,但是有一个小问题。当过程最小化时,我的代码不起作用。该过程不会像未最小化时那样在前台显示。

这是代码片段:

public partial class Form1 : Form
{
    [DllImport("user32.dll")]
    static extern bool SetForegroundWindow(IntPtr hWnd);

    public Form1()
    {
       InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        System.Diagnostics.Process[] p
            = System.Diagnostics.Process.GetProcessesByName("Client");

        if (p.Length > 0)
        {
            SetForegroundWindow(p[0].MainWindowHandle);
        }
        else
        {
            MessageBox.Show("Window Not Found!");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

c# pinvoke winapi minimized

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

在DllImport中使用Unicode字符串和用Rust编写的DLL

我试图从C#程序调用Rust编写的DLL.DLL有两个简单的函数,它们以不同的方式敲击并打印到控制台.

Rust DLL代码

#![crate_type = "lib"]
extern crate libc;

use libc::{c_char};
use std::ffi::CStr;

#[no_mangle]
pub extern fn printc(s: *const c_char){
    let c_str : &CStr = unsafe {
        assert!(!s.is_null());

        CStr::from_ptr(s)
    };

    println!("{:?}", c_str.to_bytes().len()); //prints "1" if unicode

    let r_str = std::str::from_utf8(c_str.to_bytes()).unwrap();
    println!("{:?}", r_str);
}

#[no_mangle]
pub extern fn print2(string: String) {
    println!("{:?}", string)
}
Run Code Online (Sandbox Code Playgroud)

C#控制台程序代码

[DllImport("lib.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
static extern void print2(ref string str);

[DllImport("lib.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void printc(string str);

static void Main(string[] args) …
Run Code Online (Sandbox Code Playgroud)

c# pinvoke dllimport rust

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

如何正确调用类库中的P/Invoke方法?

我在Visual Studio 2015解决方案中有多个项目.其中一些项目执行P/Invokes,如:

 [DllImport("IpHlpApi.dll")]
        [return: MarshalAs(UnmanagedType.U4)]
        public static extern int GetIpNetTable(IntPtr pIpNetTable, [MarshalAs(UnmanagedType.U4)]
        ref int pdwSize, bool bOrder);
Run Code Online (Sandbox Code Playgroud)

所以我将所有的P/Invokes移动到一个单独的类库中,并将单个类定义为:

namespace NativeMethods
{
    [
    SuppressUnmanagedCodeSecurityAttribute(),
    ComVisible(false)
    ]

    public static class SafeNativeMethods
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern int GetTickCount();

        // Declare the GetIpNetTable function.
        [DllImport("IpHlpApi.dll")]
        [return: MarshalAs(UnmanagedType.U4)]
        public static extern int GetIpNetTable(IntPtr pIpNetTable, [MarshalAs(UnmanagedType.U4)]
        ref int pdwSize, bool bOrder);
    }
}
Run Code Online (Sandbox Code Playgroud)

从其他项目中,此代码称为:

 int result = SafeNativeMethods.GetIpNetTable(IntPtr.Zero, ref bytesNeeded, false);
Run Code Online (Sandbox Code Playgroud)

所有编译都没有错误或警告.

现在在代码上运行FxCop会发出警告:

警告CA1401更改P/Invoke'SafeNativeMethods.GetIpNetTable(IntPtr,ref int,bool)'的可访问性,以便从其程序集外部不再可见.

好.将可访问性更改为内部:

[DllImport("IpHlpApi.dll")]
[return: …
Run Code Online (Sandbox Code Playgroud)

c# pinvoke native-methods

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

将系统剪贴板读为流而不是字符串

如果我在系统剪贴板上有大量文本(例如150MB文本文件),我希望能够从流中读取系统剪贴板作为Unicode文本,以避免OutOfMemoryException.这可以通过调整下面的pinvoke示例来实现吗?

对于这些非常大的剪贴板,Clipboard.GetText(TextDataFormat.UnicodeText)将返回一个空字符串而不会抛出异常.

或者,如果我像这里的示例一样使用pinvoke,我将得到一个OutOfMemoryException http://komalmangal.blogspot.ca/2016/04/how-to-get-clipboard-data-and-its-size.html

    [DllImport("user32.dll")]
    static extern IntPtr GetClipboardData(uint uFormat);
    [DllImport("user32.dll")]
    static extern bool IsClipboardFormatAvailable(uint format);
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool OpenClipboard(IntPtr hWndNewOwner);
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool CloseClipboard();
    [DllImport("kernel32.dll")]
    static extern IntPtr GlobalLock(IntPtr hMem);
    [DllImport("kernel32.dll")]
    static extern bool GlobalUnlock(IntPtr hMem);

    const uint CF_UNICODETEXT = 13;
    public static string GetText()
    {
        if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
            return null;
        if (!OpenClipboard(IntPtr.Zero))
            return null;

        string data = null;
        var hGlobal = GetClipboardData(CF_UNICODETEXT);
        if (hGlobal != IntPtr.Zero)
        {
            var lpwcstr = GlobalLock(hGlobal); …
Run Code Online (Sandbox Code Playgroud)

c# clipboard pinvoke winapi stream

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