2011-08-03 198 views
9

私は動的にWindows APIを呼び出しています。私はこれを行うことができるいくつかのコードをオンラインで見つけました、そして、私はそれに大いに関心を持っていました。アイデア自体は控えめに言えば華麗です。しかし、私は自分のコードのためにそれを動作させるように見えることはできません。ダイナミックコールのパラメータは、タイプstring,stringint[]のとおりであり、パラメータpInfo.hThredref ctx(下に表示)を使用してAPI GetThreadContextを使用したいと考えています。C#IntPtrをintに変換する

上記のコードは、(それは私のプロジェクトの中で宣言されていることを与えられた)GetThreadContextのAPIへの呼び出しを行います

GetThreadContext(pInfo.hThread, ref ctx); 

API呼び出し - とは完全に正常に動作します。しかし、動的呼び出しの美しさは、宣言は必要ないということです。だから、動的な呼び出しで私の試みは:

ctx = new CONTEXT {ContextFlags = 0x10007}; 
PROCESS_INFORMATION pInfo; 

CInvokeAPI.Invoke("kernel32","GetThreadContext",pInfo.hThread, ctx); 

ここでの問題は、私は、私はそれが構造体であるという事実与えられたint型としてパラメータCTXを渡すことができる方法についての手掛かりを持っていないということです。

[StructLayout(LayoutKind.Sequential)] 
    struct CONTEXT 
    { 
     public uint ContextFlags; 
     unsafe fixed byte unused[160]; 
     public uint Ebx; 
     public uint Edx; 
     public uint Ecx; 
     public uint Eax; 
     unsafe fixed byte unused2[24]; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    struct PROCESS_INFORMATION 
    { 
     public IntPtr hProcess; 
     public IntPtr hThread; 
     public int dwProcessId; 
     public int dwThreadId; 
    } 

コールAPIを動的にクラス

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

/* 
* Title: CInvokeAPI.cs 
* Description: Call API by name implementation in purely managed C# (no 'unsafe' mess here). 
* 
* Developed by: affixiate 
* Comments: If you use this code, I require you to give me credits. 
*/ 

public static class CInvokeAPI 
{ 
    /// <summary> 
    /// Generates a new, non-garbage collectable string in memory. Use this with Unicode "W" API. 
    /// </summary> 
    /// <param name="theString">A Unicode string.</param> 
    /// <returns>Address of newly allocated string in memory. Remember to free it after use.</returns> 
    public static int StringToPtrW(string theString) 
    { 
     return StringToPtr(Encoding.Unicode.GetBytes(theString)); 
    } 

    /// <summary> 
    /// Generates a new, non-garbage collectable string in memory. Use this with ANSI "A" API. 
    /// </summary> 
    /// <param name="theString">An ANSII string.</param> 
    /// <returns>Address of newly allocated string in memory. Remember to free it after use.</returns> 
    public static int StringToPtrA(string theString) 
    { 
     return StringToPtr(Encoding.ASCII.GetBytes(theString)); 
    } 

    /// <summary> 
    /// Internal method used to allocate memory. 
    /// </summary> 
    /// <param name="buf">A byte buffer.</param> 
    /// <returns>Address of newly allocated memory. Remember to free it after use.</returns> 
    private static int StringToPtr(byte[] buf) 
    { 
     return (int)GCHandle.Alloc(buf, GCHandleType.Pinned).AddrOfPinnedObject(); 
    } 

    /// <summary> 
    /// Invokes the specified Windows API. 
    /// </summary> 
    /// <param name="libraryName">Name of the library.</param> 
    /// <param name="functionName">Name of the function.</param> 
    /// <param name="args">The arguments.</param> 
    /// <returns>True if function succeeds, otherwise false.</returns> 
    public static bool Invoke(string libraryName, string functionName, params int[] args) 
    { 
     /* Sanity checks. */ 
     IntPtr hLoadLibrary = LoadLibrary(libraryName); 
     if (hLoadLibrary == IntPtr.Zero) return false; 

     IntPtr hGetProcAddress = GetProcAddress(hLoadLibrary, functionName); 
     if (hGetProcAddress == IntPtr.Zero) return false; 

     // Allocates more than enough memory for an stdcall and the parameters of a WinAPI function 
     IntPtr hMemory = VirtualAlloc(IntPtr.Zero, 1024 * 1024, MEM_COMMIT | MEM_RESERVE, MEM_EXECUTE_READWRITE); 
     if (hMemory == IntPtr.Zero) 
      return false; 

     IntPtr hMemoryItr = hMemory; 

     // Prepends the stdcall header signature 
     Marshal.Copy(new byte[] {0x55, 0x89, 0xE5}, 0, hMemoryItr, 0x3); 
     hMemoryItr = (IntPtr)((int)hMemoryItr + 0x3); 

     // Loop through the passed in arguments and place them on the stack in reverse order 
     for (int i = (args.Length - 1); i >= 0; i--) 
     { 
      Marshal.Copy(new byte[] {0x68}, 0, hMemoryItr, 0x1); 
      hMemoryItr = (IntPtr)((int)hMemoryItr + 0x1); 
      Marshal.Copy(BitConverter.GetBytes(args[i]), 0, hMemoryItr, 0x4); 
      hMemoryItr = (IntPtr)((int)hMemoryItr + 0x4); 
     } 

     Marshal.Copy(new byte[] {0xE8}, 0, hMemoryItr, 0x1); 
     hMemoryItr = (IntPtr)((int)hMemoryItr + 0x1); 
     Marshal.Copy(BitConverter.GetBytes((int)hGetProcAddress - (int)hMemoryItr - 0x4), 0, hMemoryItr, 0x4); 
     hMemoryItr = (IntPtr)((int)hMemoryItr + 0x4); 

     // Cleaning up the stack 
     Marshal.Copy(new byte[] {0x5D, 0xC2, 0x4, 0x0 /* <= I made a LOL. */}, 0, hMemoryItr, 0x4); 
     // Don't forget to increment if you are adding more ASM code here: hMemoryItr = (IntPtr)((int)hMemoryItr + 0x4); 

     try 
     { 
      var executeAsm = (RunAsm) Marshal.GetDelegateForFunctionPointer(hMemory, typeof (RunAsm)); 
      executeAsm(); 
     } 
     catch { return false; } 

     // Clean up the memory we allocated to do the dirty work 
     VirtualFree(hMemory, 0, MEM_RELEASE); 
     return true; 
    } 

    // ReSharper disable InconsistentNaming 
    private const uint MEM_RELEASE = 0x8000; 
    private const uint MEM_COMMIT = 0x1000; 
    private const uint MEM_RESERVE = 0x2000; 
    private const uint MEM_EXECUTE_READWRITE = 0x40; 
    // ReSharper restore InconsistentNaming 

    // My own sexy delegate: 
    [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)] 
    private delegate void RunAsm(); 

    // WinAPI used: 
    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern bool VirtualFree(IntPtr lpAddress, UInt32 dwSize, uint dwFreeType); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern IntPtr VirtualAlloc(IntPtr lpAddress, UInt32 dwSize, uint flAllocationType, uint flProtect); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern IntPtr LoadLibrary(string lpFileName); 

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] 
    private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName); 
} 
+0

myVoidが期待するREALパラメータをアンマネージド側に提供できますか?それは本当にハンドルと文脈*ですか?はいの場合は、このためにいくつかの管理されていないメモリを割り当てる必要があります。その中にCONTEXTインスタンスをコピーしてください。代わりにhttp://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.structuretoptr.aspxを参照してください。 PROCESS_INFORMATION *が必要なハンドルの場合は、このパラメータに対して同じ処理を行う必要があります。 –

+0

@VirtualBlackFox Updated ... –

+0

64ビットにご注意ください – SLaks

答えて

6

あなたはIntPtr.ToInt32メソッドを使用することができ、追加のコードは以下を参照してください?それは最初のパラメータで動作するはずです。しかし、構造体の変換についてはわかりません。

structを整数に変換する方法については、this postをご覧ください。

UPDATE:

ありC#でVarPtr関数のは直接C#の同等はありませんが、私はそれが何をしているかの説明と一緒にhereを(参照マニュアルを見つけた... VarPtr関数の説明でに似て聞こえますthis post)。これはコードの抜粋です。それはあなたのために有用である可能性があります

public static int VarPtr(object e) 
{ 
    GCHandle GC = GCHandle.Alloc(e, GCHandleType.Pinned); 
    int gc = GC.AddrOfPinnedObject().ToInt32(); 
    GC.Free(); 
    return gc; 
} 

注:このpostで述べたように、いくつかの電位の欠陥は、この関数にあります。

+0

最初のオブジェクトが渡された可能性はありますが、Contextオブジェクトでは機能しません。 –

+0

@エヴァン:あなたが正しい方向に(構造変換のために)始める可能性のあるポストへのリンクを追加しました。 –

+0

@エヴァン:午前中にもっと助けてもいいかもしれない...非常に疲れている。 –

関連する問題