昨天我一直在搜索高低,寻找如何快速获得msi数据库的ProductVersion.大多数情况下,我发现使用WindowsInstaller COM包装器,虽然这完成了工作,我想通过pinvoke使用msi.dll实现相同的结果.
我试图调用一个看起来像这样的非托管函数(DATA是我的C#结构):
[DllImport("data.dll")]
internal static unsafe extern int MyExternalFunction(DATA* pData, uint numElements);
Run Code Online (Sandbox Code Playgroud)
这就是我从C#调用函数的方式:
DATA[] data = new DATA[64];
fixed (DATA* pData = data )
{
MyExternalFunction(pData, 64);
}
[StructLayout(LayoutKind.Sequential)]
internal struct DATA
{
internal uint a;
internal uint b;
internal uint c;
internal POINT pos;
}
[StructLayout(LayoutKind.Sequential)]
internal struct POINT
{
internal int x;
internal int y;
}
Run Code Online (Sandbox Code Playgroud)
不幸的是我收到了这个错误:"无法编组'参数#1':指针不能引用封送结构."
如果它有任何区别,我的DATA结构中有嵌套的结构.我无法控制外部方法的设计方式.调用此函数并接收结构数组的正确方法是什么?
如何将此Clarion过程声明转换为C#?它是用C编写的第三方DLL的一部分,没有太多的文档。我已经在Clarion中列出了可以正常工作的方法的原型。在C#中,我不确定要使用哪种类型来替换*CString。我尝试char[]像@DanielC建议的那样,但是没有用。我还发现Clarion long是32位的(感谢@ shf301)。
号角:
SendRequest Procedure(*CString xData,Long DataLen,Long xTimeout),Byte,Virtual
Run Code Online (Sandbox Code Playgroud)
C#(我尝试过的方法不起作用):
[DllImport("3RD_PARTY_API.dll")]
private static extern long SendRequest(ref string xData, int DataLen, int xTimeout);
Run Code Online (Sandbox Code Playgroud)
当我SendRequest在C#中调用该方法时,我从VS2010 获取标准的PInvokeStackImbalance被检测到错误。我认为它的参数类型的问题,而不是像CharSet或EntryPoint在的DllImport声明。我真的只是停留在如何转换*CString为有效的C#类型上。
考虑一个典型的P/Invoke声明,如下所示:
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool LookupAccountName(
string SystemName,
string accountName,
IntPtr pSid,
ref uint cbSid,
[MarshalAs(UnmanagedType.LPWStr)] StringBuilder ReferencedDomainName,
ref uint ReferencedDomainNameCount,
out SID_NAME_USE SIDUse);
Run Code Online (Sandbox Code Playgroud)
LookupAccountName的MSDN文档说明了这一点,pSid并且ReferencedDomainName可能是nullptr客户希望的.传递nullptr的pSid是容易的; 只是通过IntPtr.Zero.但是应该通过什么StringBuilder呢?
我不想传递空StringBuilder,因为我不希望这个调用失败ERROR_INSUFFICIENT_BUFFER.
VS代码分析器抛出此警告:
CA2101为P/Invoke字符串参数指定编组要降低安全风险,请将参数'buffer'编组为Unicode,方法是将DllImport.CharSet设置为CharSet.Unicode,或者将参数显式封送为UnmanagedType.LPWStr.如果需要将此字符串封送为ANSI或系统相关,请明确指定MarshalAs,并设置BestFitMapping = false; 为了增加安全性,还要设置ThrowOnUnmappableChar = true.Reg2Bat CenteredMSGBox.vb 20
这里:
<DllImport("user32.dll")> _
Shared Function GetClassName(hWnd As IntPtr, buffer As System.Text.StringBuilder, buflen As Integer) As Integer
End Function
Run Code Online (Sandbox Code Playgroud)
我需要使用ANSI编码,但我不明白我需要做什么,所以我需要如何编组呢?
我知道C#允许使用PInvoke与本机代码进行互操作(管理/非托管代码互操作性概述)
我们正计划开发新代码,并正在考虑两个选项:
我想知道这个互操作是否有任何记录的限制?(例如 - 某些类型无法在托管/本机之间来回编组等)
这些限制可能会影响我们决定使用(或不使用)选项#1.
这是我的C代码:
LIBRARY_API bool __cdecl Initialize(void (*FirstScanForDevicesDoneFunc)(void));
Run Code Online (Sandbox Code Playgroud)
这是使用此DLL的C#PINvoke代码:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void FirstScanForDevicesDoneFunc();
[DllImport("Native.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern bool Initialize(FirstScanForDevicesDoneFunc);
Run Code Online (Sandbox Code Playgroud)
当我这样调用这个方法时:
static public void Init() {
Initialize(FirstScanForDevicesDone);
}
static public void FirstScanForDevicesDone() {
//do something
}
Run Code Online (Sandbox Code Playgroud)
在Init()回调结束时,我得到NullReferenceException.所以我使用Thread来保持它并且一切正常,但我对这个解决方案不满意:
static public bool Working = true;
static public void Init() {
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
Initialize(FirstScanForDevicesDone);
while (Working)
{
Thread.Sleep(1000);
}
}).Start();
}
Run Code Online (Sandbox Code Playgroud)
是否有更复杂的方法来保持这种工作?
我工作的一个开源的.NET克隆的(GitHub的)DeskPins由埃利亚斯Fotinis(直接下载谷歌关闭驱动器).它的主要功能是使其他窗户永远在顶部.当它们位于顶部时,标题栏中会添加一个图钉图标,如下所示:
在拖放过程中,图钉图标随窗口移动,看起来就像是它的一部分.它甚至响应click事件,它会始终取消最高状态并从显示中删除图标.
题.是否有可能在C#中实现这样的东西(和p/invoke,我假设)?
研究
我试图运行这个项目.
这是一个WPF演示,它应该为标题栏添加一个自定义控件.似乎不适用于Windows 7 x64.不确定是操作系统还是其他操作系统.问题 - z顺序不一致,标题栏也出现在其他窗口的顶部,并且它不随窗口移动,它会尝试,但是很多视觉伪像和闪烁.
试图将此解决方案应用于#1:
基本上用这种模式替换对SetWindowLong的相关调用:
SetWindowLong(guestHandle, GWL_STYLE, GetWindowLong(guestHandle, GWL_STYLE) | WS_CHILD);
SetParent(guestHandle, hostHandle);
Run Code Online (Sandbox Code Playgroud)
此更改打破了所有内容,因此标题栏中未添加任何内容.可能是它不适用于标题栏,仅适用于表单的用户区域.
无论如何,如果有一个简单的解决方案,请分享你的智慧.如果没有,我将非常感谢任何提示和/或链接,以便我进一步调查该主题.
我正在尝试使用PInvoke来调用非托管C++ DLL,我遇到了错误(见下文).使用depends.exe我可以在导出的函数列表中看到错位的名称,因此是奇怪的EntryPoint名称.虽然出现此异常,但如果我继续进行Step Over调试,则函数返回并ptr等于1并打印"成功".
我已经尝试了其他帖子中的一些建议,但没有任何效果.我认为这uint32_t是非常自我解释的.我已经尝试更改要使用的C#PInvoke签名long,ulong但是仍然抛出异常并且值ptr非常大.我也试过了属性的设置CharSet和ExactSpelling属性,DllImport但这似乎也没有用.
我的问题是,我在做什么导致异常,如果我不能/不应该忽略异常 - 如何做到这一点?
MyClass.h
class __declspec(dllexport) MyClass
{
public:
uint32_t runCommand(uint32_t start);
};
Run Code Online (Sandbox Code Playgroud)
MyClass.cpp
uint32_t MyClass::runCommand(uint32_t start);
{
uint32_t status = 1;
return status;
}
Run Code Online (Sandbox Code Playgroud)
P/Invoke签名
[DllImport("myClass.dll",
EntryPoint = "?runCommand@MyClass@myClass@@QAEII@Z",
CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 runCommand(UInt32 baseAddress);
Run Code Online (Sandbox Code Playgroud)
用法
public static void Do()
{
UInt32 a = 0xA000;
UInt32 ptr = …Run Code Online (Sandbox Code Playgroud) RegSetValueEx 具有以下P/Invoke签名:
[DllImport("advapi32.dll", SetLastError = true)]
static extern uint RegSetValueEx(
UIntPtr hKey,
[MarshalAs(UnmanagedType.LPStr)]
string lpValueName,
int Reserved,
RegistryValueKind dwType,
IntPtr lpData,
int cbData);
Run Code Online (Sandbox Code Playgroud)
该IntPtr的lpData参数可以一起工作有疼痛感.要传递一个字符串值,我需要调用其中一个Marshall.StringToHGlobal函数,然后在完成后释放它.如果我将lpData参数类型更改为,我的代码可以更简单[MarshalAs(UnmanagedType.LPStr)]String lpData.这似乎工作,我可以想象在幕后,编组代码正在做我要做的事情IntPtr.如果这是合法的,我无法找到任何明确的陈述.任何人都可以提供吗?
[是的,我知道有托管代码与注册表连接.在我的特殊情况下,我不能使用它,即使我可以,我仍然会对一般的答案感兴趣]