none
cannot convert from 'uint[]' to 'System.IntPtr' RRS feed

  • Question

  • " Argument '2': cannot convert from 'uint[]' to 'System.IntPtr' " How to do this in a marshalas attribute in C#??

    My method is this

     

    public static extern bool EnumProcessModules(IntPtr hProcess,

            [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U4)] [In][Out] uint[] lphModule, uint cb, [MarshalAs(UnmanagedType.U4)] out uint lpcbNeeded);

     

    the value lphModule I ve to pass it in the the second method second arguement hmodule

    static extern uint GetModuleBaseName(IntPtr hProcess,[MarshalAs(UnmanagedType.LPArray,ArraySubType= UnmanagedType.U4)][In][Out]IntPtrhModule, out StringBuilder lpBaseName, uint nSize);

     

    the error as mentioned above  i m not able to convert the uint[] to IntPtr so that i could pass it in the second method


    Robin Karriottu Rajan
    Friday, February 11, 2011 12:34 AM

Answers

  • uint[] value = ...

     

    fixed(uint* temp = &value[0])

    {

        IntPtr intPtr = new IntPtr((void*)temp);

       // use intPtr here...
    }

     

     

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    • Marked as answer by Johncy1 Friday, February 11, 2011 1:23 AM
    Friday, February 11, 2011 1:12 AM
    Moderator
  • You need to edit your project settings to allow unsafe code, and mark the method "unsafe", ie:

     

    private unsafe void MyMethod()

    {

     //...

    }


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    • Marked as answer by Johncy1 Saturday, February 12, 2011 3:42 PM
    Friday, February 11, 2011 2:11 AM
    Moderator
  • Hello Robin,

     

    1. From the way EnumProcessModules() and GetModuleBaseName() are declared in the OP, it looks likely that you are trying to use the EnumProcessModules() and GetModuleBaseName() APIs exported from Psapi.dll. The discussions that follow will assume this.

    1.1 The problems appears to be the way the two APIs are declared in managed code via DllImport. These are explained below.

     

    2. Let's study the EnumProcessModules() API.

    2.1 The declaration for this API is as follows :

    BOOL WINAPI EnumProcessModules
    (
      HANDLE hProcess,
      HMODULE* lphModule,
      DWORD cb,
      LPDWORD lpcbNeeded
    );

    2.2 Hence a more appropriate DllImport decl for this API would be :

            [DllImport("Psapi.dll", CallingConvention=CallingConvention.StdCall)]
            public static extern int EnumProcessModules
                (
                  IntPtr hProcess,
                  [Out] IntPtr lphModule,
                  uint cb,
                  out uint lpcbNeeded
                );


    2.2.1 The second parameter is a pointer to a HMODULE (HMODULE* lphModule) and it is documented as being intended to be "An array that receives the list of module handles." From the point of view of managed code it need only be declared as an IntPtr. Later I will demonstrate how to transform a managed array of "HMODULE"s into an address that can be passed to this API.

    2.2.2 The second parameter can also be marshaled as [Out] only. There is no need for the [In] marshal attribute because the API will not be interested in the incoming values of the HMODULE array. It will only set values into this array.

    2.2.3 There is also no need to declare the 4th parameter lpcbNeeded with the [MarshalAs(UnmanagedType.U4)] attribute. The unmanaged DWORD type is already equivalent to the C# uint type (for 32-bit systems, which I assume to be applicable for your case).

    2.2.4 Finally, the return type for this API is the unmanaged BOOL which is an integer type. Hence I declared the return type for this API in managed code as int instead of System.Boolean.

    2.3 To use this API in managed code, especially with regards to the second parameter, you need to declare an array of IntPtr's to server as the array of HMODULEs. Unmanaged HANDLEs and HMODULEs are usually represented as IntPtr's in managed code. For example :

                 IntPtr [] hMods = new IntPtr [1024];

    2.4 Then, before calling the EnumProcessModules() API, allocate a GC Handle and pin the array in memory, e.g. :

                GCHandle gch = GCHandle.Alloc(hMods, GCHandleType.Pinned);
                IntPtr pModules = gch.AddrOfPinnedObject();


    It is the IntPtr returned from the GCHandle.AddrOfPinnedObject() method call that we pass to the EnumProcessModules() API as the second parameter :

                EnumProcessModules(hProcess, pModules, uiSize, out cbNeeded);

    After the API call, we need to free the GCHandle by calling its Free() method :

               gch.Free();

    I have declared "hProcess", "uiSize" and "cbNeeded" as follows :

                IntPtr hProcess = GetCurrentProcess();
                uint uiSize = (uint)(Marshal.SizeOf(typeof(IntPtr)) * (hMods.Length));
                uint cbNeeded = 0;


    I have used the GetCurrentProcess() Windows API to obtain a handle to the current process. It is declares as :

            [DllImport("Kernel32.dll", CallingConvention=CallingConvention.StdCall)]
            public static extern IntPtr GetCurrentProcess();

     


    3. Next let's study the GetModuleBaseName() API.

    3.1 The declaration for this API is :

    DWORD WINAPI GetModuleBaseName
    (
      HANDLE hProcess,
      HMODULE hModule,
      LPTSTR lpBaseName,
      DWORD nSize
    );

    3.2 Hence a more appropriate DllImport decl for this API would be :

            [DllImport("Psapi.dll", CallingConvention = CallingConvention.StdCall, CharSet=CharSet.Unicode)]
            static extern uint GetModuleBaseName
                (
                  IntPtr hProcess,
                  IntPtr hModule,
                  [Out] StringBuilder lpBaseName,

                  uint nSize
                );


    3.2.1 The second parameter should not be declared with the marshaling attributes :

    [MarshalAs(UnmanagedType.LPArray,ArraySubType= UnmanagedType.U4)][In][Out]IntPtr hModule

    The marshaling attributes above implies that hModule points to an array of 4-byte unsigned integers. The GetModuleBaseName() API expects only one HMODULE data. This creates a mismatch between the data marshaled from managed code and the data expected from the unmanaged API.

    There is also no need to declare the parameter as being marshaled as both [In] and [Out]. The API ony uses this parameter's value and will not be modifying it in any way and so an [In] parameter (the default) will do.

    3.2.2 The third parameter is declared very incorrectly in the OP :

    out StringBuilder lpBaseName

    It should intead be declared as :

    [Out] StringBuilder lpBaseName

    The first "out" declaration indicates that GetModuleBaseName() will actually return a StringBuilder object after the API call or that it will return something that can be converted by the CLR into a StringBuilder object.

    The API in fact, expects a character buffer into which it can copy the base name. A StringBuilder object should be declared in managed code with its Capacity set to an appropriate size and then passed into the GetModuleBaseName() call. It is the buffer of the StringBuilder that gets passed into the API.

    Note further that the StringBuilder type is always marshaled as both [In] and [Out] by default. Hence the original contents of the StringBuilder buffer is by default passed into a target API. By specifically using only the [Out] marshaling attribute, we can achieve optimization since we know that the GetModuleBaseName() API only sets character values into the buffer and does not read it.

     

    4. The code below demonstrate how the above information can be put to action :

            [DllImport("Kernel32.dll", CallingConvention=CallingConvention.StdCall)]
            public static extern IntPtr GetCurrentProcess();

            [DllImport("Psapi.dll", CallingConvention=CallingConvention.StdCall)]
            public static extern int EnumProcessModules
                (
                  IntPtr hProcess,
                  [Out] IntPtr lphModule,
                  uint cb,
                  out uint lpcbNeeded
                );

            [DllImport("Psapi.dll", CallingConvention = CallingConvention.StdCall, CharSet=CharSet.Unicode)]
            static extern uint GetModuleBaseName
                (
                  IntPtr hProcess,
                  IntPtr hModule,
                  [Out] StringBuilder lpBaseName,
                  uint nSize
                );

            static void Main(string[] args)
            {
                IntPtr hProcess = GetCurrentProcess();
                IntPtr [] hMods = new IntPtr [1024];
                uint uiSize = (uint)(Marshal.SizeOf(typeof(IntPtr)) * (hMods.Length));
                uint cbNeeded = 0;

                GCHandle gch = GCHandle.Alloc(hMods, GCHandleType.Pinned);
                IntPtr pModules = gch.AddrOfPinnedObject();

                if (EnumProcessModules(hProcess, pModules, uiSize, out cbNeeded) == 1)
                {
                    Int32 uiTotalNumberOfModules = (Int32)(cbNeeded / (Marshal.SizeOf(typeof(IntPtr))));

                    for (int i = 0; i < (int)uiTotalNumberOfModules; i++)
                    {
                        StringBuilder strbld = new StringBuilder(1024);
                       
                        GetModuleBaseName(hProcess, hMods[i], strbld, (uint)(strbld.Capacity));

                        Console.WriteLine("{0:S}", strbld.ToString());
                    }
                }

                gch.Free();
            }


    Hope the above will be useful to you.

     

    - Bio.

     

    • Marked as answer by Johncy1 Sunday, February 13, 2011 1:54 PM
    Sunday, February 13, 2011 10:11 AM
  • Hello Robin,

     

    There are several errors in your last code listing. I shall list them below together with some comments.

     

    1. Observe your call to the OpenProcess() API :

    IntPtr hProcess = OpenProcess(ProcessAccessFlags.QueryInformation & ProcessAccessFlags.VMRead, true, (uint)processIds[index]);

    I do not know how you have defined the entity named ProcessAccessFlags but the first parameter to OpenProcess() should be coded such that "ProcessAccessFlags.QueryInformation" is OR'ed with "ProcessAccessFlags.VMRead", e.g. :

    IntPtr hProcess = OpenProcess((ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VMRead), true, (uint)processIds[index]);

    AND'ing any 2 distinct bit flag values will result in a 0 value. For example :

    Let's say ProcessAccessFlags.QueryInformation is 0x0400, and ProcessAccessFlags.VMRead is 0x0010. Because each has a distinct bit flag set, AND'ing them will result in 0x0000.

    However, if you OR them, you get the value 0x0410.

     

    2. Soon after the call to OpenProcess(), there is an "if" statement testing the current value of "hProcess" :

    if (null != hProcess)...

    This is incorrect. This "if" condition will always evaluate to true because "hProcess" has been set to some value (the return value of the OpenProcess() API) hence it is not null.

    If I understood your intentions correctly, the above "if" statement should be coded as :

    if (IntPtr.Zero != hProcess)...

     

    3. The call to EnumProcessModules() has two mistakes :

    if (EnumProcessModules(hProcess, pModules, sizeof(UInt32), out lpcbNeeded) == 0)

    3.1 The 3rd parameter should be "uiSize" instead of "sizeof(UInt32)", where "uiSize" is :

    uint uiSize = (uint)(Marshal.SizeOf(typeof(IntPtr)) * (lphModule.Length));

    (revisit my code listed in my post dated Sunday February 13th).

    3.2 The correct return value to watch out for is "1" and not "0". Look up the documentation for EnumProcessModules() in MSDN.

    However, the documentation did state that the return value is nonzero if the call is successful and zero if the call is a failure. Hence the best way to code is :

    if (EnumProcessModules(hProcess, pModules, /*sizeof(UInt32)*/ uiSize, out lpcbNeeded) > 0) ...

     

    4. The second parameter in the call to GetModuleBaseName() must also be changed :

    Original code :

    GetModuleBaseName(hProcess, pModules, lpBaseName, (uint)lpBaseName.Capacity);

    Corrected code :

    GetModuleBaseName(hProcess, /*pModules*/ lphModule[i], lpBaseName, (uint)lpBaseName.Capacity);

    The second parameter takes an HMODULE value (represented by an IntPtr) from an element of the "lphModule" array. It should not take "pModules" which is a pointer to the "lphModule" array.

    Note that when we call EnumProcessModules(), we pass "pModules" (pointer to the "lphModule" array) and EnumProcessModules() will fill in values into the array via "pModules". Then, when EnumProcessModules() has done its job, the "lphModule" array is filled with HMODULE values and each is accessed via an index.

     

    - Bio.

     

    • Marked as answer by Johncy1 Monday, February 14, 2011 8:40 PM
    Monday, February 14, 2011 6:33 PM

All replies

  • You could use fixed to get a unit*, and create an IntPtr from the pointer.
    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Friday, February 11, 2011 12:46 AM
    Moderator
  • Thanks for you reply.

    If you could give me more detailed information.

    about using fixed and how to a uint * to IntPtr it would be great.


    Robin Karriottu Rajan
    Friday, February 11, 2011 1:02 AM
  • uint[] value = ...

     

    fixed(uint* temp = &value[0])

    {

        IntPtr intPtr = new IntPtr((void*)temp);

       // use intPtr here...
    }

     

     

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    • Marked as answer by Johncy1 Friday, February 11, 2011 1:23 AM
    Friday, February 11, 2011 1:12 AM
    Moderator

  • Thanks for your reply.

    Now I am getting the following error for the temp pointer.


    Error 2 Pointers and fixed size buffers may only be used in an unsafe context


    Robin Karriottu Rajan
    Friday, February 11, 2011 1:38 AM
  • You need to edit your project settings to allow unsafe code, and mark the method "unsafe", ie:

     

    private unsafe void MyMethod()

    {

     //...

    }


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    • Marked as answer by Johncy1 Saturday, February 12, 2011 3:42 PM
    Friday, February 11, 2011 2:11 AM
    Moderator
  • Thank you for your reply

    Unfortunately after doing all those things that you told i am still getting an exception

    I  don't understand this exception since the second parameter was IntPtr in the Import signature  and now also in the method. Then how is it coming  Int in this exception

    it is coming like this.

     

    Cannot marshal 'parameter #2': Invalid managed/unmanaged type combination (Int/UInt must be paired with SysInt or SysUInt).


    Robin Karriottu Rajan
    Saturday, February 12, 2011 4:47 PM
  • Hello Robin,

     

    1. From the way EnumProcessModules() and GetModuleBaseName() are declared in the OP, it looks likely that you are trying to use the EnumProcessModules() and GetModuleBaseName() APIs exported from Psapi.dll. The discussions that follow will assume this.

    1.1 The problems appears to be the way the two APIs are declared in managed code via DllImport. These are explained below.

     

    2. Let's study the EnumProcessModules() API.

    2.1 The declaration for this API is as follows :

    BOOL WINAPI EnumProcessModules
    (
      HANDLE hProcess,
      HMODULE* lphModule,
      DWORD cb,
      LPDWORD lpcbNeeded
    );

    2.2 Hence a more appropriate DllImport decl for this API would be :

            [DllImport("Psapi.dll", CallingConvention=CallingConvention.StdCall)]
            public static extern int EnumProcessModules
                (
                  IntPtr hProcess,
                  [Out] IntPtr lphModule,
                  uint cb,
                  out uint lpcbNeeded
                );


    2.2.1 The second parameter is a pointer to a HMODULE (HMODULE* lphModule) and it is documented as being intended to be "An array that receives the list of module handles." From the point of view of managed code it need only be declared as an IntPtr. Later I will demonstrate how to transform a managed array of "HMODULE"s into an address that can be passed to this API.

    2.2.2 The second parameter can also be marshaled as [Out] only. There is no need for the [In] marshal attribute because the API will not be interested in the incoming values of the HMODULE array. It will only set values into this array.

    2.2.3 There is also no need to declare the 4th parameter lpcbNeeded with the [MarshalAs(UnmanagedType.U4)] attribute. The unmanaged DWORD type is already equivalent to the C# uint type (for 32-bit systems, which I assume to be applicable for your case).

    2.2.4 Finally, the return type for this API is the unmanaged BOOL which is an integer type. Hence I declared the return type for this API in managed code as int instead of System.Boolean.

    2.3 To use this API in managed code, especially with regards to the second parameter, you need to declare an array of IntPtr's to server as the array of HMODULEs. Unmanaged HANDLEs and HMODULEs are usually represented as IntPtr's in managed code. For example :

                 IntPtr [] hMods = new IntPtr [1024];

    2.4 Then, before calling the EnumProcessModules() API, allocate a GC Handle and pin the array in memory, e.g. :

                GCHandle gch = GCHandle.Alloc(hMods, GCHandleType.Pinned);
                IntPtr pModules = gch.AddrOfPinnedObject();


    It is the IntPtr returned from the GCHandle.AddrOfPinnedObject() method call that we pass to the EnumProcessModules() API as the second parameter :

                EnumProcessModules(hProcess, pModules, uiSize, out cbNeeded);

    After the API call, we need to free the GCHandle by calling its Free() method :

               gch.Free();

    I have declared "hProcess", "uiSize" and "cbNeeded" as follows :

                IntPtr hProcess = GetCurrentProcess();
                uint uiSize = (uint)(Marshal.SizeOf(typeof(IntPtr)) * (hMods.Length));
                uint cbNeeded = 0;


    I have used the GetCurrentProcess() Windows API to obtain a handle to the current process. It is declares as :

            [DllImport("Kernel32.dll", CallingConvention=CallingConvention.StdCall)]
            public static extern IntPtr GetCurrentProcess();

     


    3. Next let's study the GetModuleBaseName() API.

    3.1 The declaration for this API is :

    DWORD WINAPI GetModuleBaseName
    (
      HANDLE hProcess,
      HMODULE hModule,
      LPTSTR lpBaseName,
      DWORD nSize
    );

    3.2 Hence a more appropriate DllImport decl for this API would be :

            [DllImport("Psapi.dll", CallingConvention = CallingConvention.StdCall, CharSet=CharSet.Unicode)]
            static extern uint GetModuleBaseName
                (
                  IntPtr hProcess,
                  IntPtr hModule,
                  [Out] StringBuilder lpBaseName,

                  uint nSize
                );


    3.2.1 The second parameter should not be declared with the marshaling attributes :

    [MarshalAs(UnmanagedType.LPArray,ArraySubType= UnmanagedType.U4)][In][Out]IntPtr hModule

    The marshaling attributes above implies that hModule points to an array of 4-byte unsigned integers. The GetModuleBaseName() API expects only one HMODULE data. This creates a mismatch between the data marshaled from managed code and the data expected from the unmanaged API.

    There is also no need to declare the parameter as being marshaled as both [In] and [Out]. The API ony uses this parameter's value and will not be modifying it in any way and so an [In] parameter (the default) will do.

    3.2.2 The third parameter is declared very incorrectly in the OP :

    out StringBuilder lpBaseName

    It should intead be declared as :

    [Out] StringBuilder lpBaseName

    The first "out" declaration indicates that GetModuleBaseName() will actually return a StringBuilder object after the API call or that it will return something that can be converted by the CLR into a StringBuilder object.

    The API in fact, expects a character buffer into which it can copy the base name. A StringBuilder object should be declared in managed code with its Capacity set to an appropriate size and then passed into the GetModuleBaseName() call. It is the buffer of the StringBuilder that gets passed into the API.

    Note further that the StringBuilder type is always marshaled as both [In] and [Out] by default. Hence the original contents of the StringBuilder buffer is by default passed into a target API. By specifically using only the [Out] marshaling attribute, we can achieve optimization since we know that the GetModuleBaseName() API only sets character values into the buffer and does not read it.

     

    4. The code below demonstrate how the above information can be put to action :

            [DllImport("Kernel32.dll", CallingConvention=CallingConvention.StdCall)]
            public static extern IntPtr GetCurrentProcess();

            [DllImport("Psapi.dll", CallingConvention=CallingConvention.StdCall)]
            public static extern int EnumProcessModules
                (
                  IntPtr hProcess,
                  [Out] IntPtr lphModule,
                  uint cb,
                  out uint lpcbNeeded
                );

            [DllImport("Psapi.dll", CallingConvention = CallingConvention.StdCall, CharSet=CharSet.Unicode)]
            static extern uint GetModuleBaseName
                (
                  IntPtr hProcess,
                  IntPtr hModule,
                  [Out] StringBuilder lpBaseName,
                  uint nSize
                );

            static void Main(string[] args)
            {
                IntPtr hProcess = GetCurrentProcess();
                IntPtr [] hMods = new IntPtr [1024];
                uint uiSize = (uint)(Marshal.SizeOf(typeof(IntPtr)) * (hMods.Length));
                uint cbNeeded = 0;

                GCHandle gch = GCHandle.Alloc(hMods, GCHandleType.Pinned);
                IntPtr pModules = gch.AddrOfPinnedObject();

                if (EnumProcessModules(hProcess, pModules, uiSize, out cbNeeded) == 1)
                {
                    Int32 uiTotalNumberOfModules = (Int32)(cbNeeded / (Marshal.SizeOf(typeof(IntPtr))));

                    for (int i = 0; i < (int)uiTotalNumberOfModules; i++)
                    {
                        StringBuilder strbld = new StringBuilder(1024);
                       
                        GetModuleBaseName(hProcess, hMods[i], strbld, (uint)(strbld.Capacity));

                        Console.WriteLine("{0:S}", strbld.ToString());
                    }
                }

                gch.Free();
            }


    Hope the above will be useful to you.

     

    - Bio.

     

    • Marked as answer by Johncy1 Sunday, February 13, 2011 1:54 PM
    Sunday, February 13, 2011 10:11 AM
  • Thank you for reply Bio

     

    Through my EnumProcess API i get a series of processIds from the unmanaged code. For each of these processIds i call the EnumProcessModules

    API and then the GetModuleBaseName API to get the Name of the module name  but in my project the

    "if" statement that is done to confirm  EnumProcessModules is succesful, always returns 0 , which means it never enters the if statement and hence my code to run the GetModuleProcess never runs. Hence I never get the output. I follow the same kind of coding that you mentioned above.

     

    Here is my code


    [DllImport("psapi.dll",SetLastError=true)]

            private static extern bool EnumProcesses([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U4)] [In][Out] UInt32[] processIds,UInt32 arraySizeBytes,[MarshalAs(UnmanagedType.U4)] out UInt32 bytesCopied);


            [DllImport("psapi.dll", SetLastError = true,CallingConvention = CallingConvention.StdCall)]

            public static extern int EnumProcessModules(IntPtr hProcess,

            [Out] IntPtr lphModule, uint cb, out uint lpcbNeeded);


            [DllImport("kernel32.dll", SetLastError = true)]

            static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, UInt32 dwProcessId);


            [DllImport("psapi.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall,CharSet= CharSet.Unicode)]

            static extern uint GetModuleBaseName(IntPtr hProcess,[In]IntPtr hModule,[In] [Out] StringBuilder lpBaseName, uint nSize);


                

            public static string GetProcessId()

            {

                UInt32 arraySize = 120;

                UInt32 arrayBytesSize = arraySize * sizeof(UInt32);

                UInt32[] processIds = new UInt32[arraySize];

                UInt32 bytesCopied;


                bool success = EnumProcesses( processIds, arrayBytesSize,out bytesCopied);

                if (!success)

                {

                    MessageBox.Show("EnumProcess is unsuccessful");

                    return "0";

                }

                if (0 == bytesCopied)

                {

                    MessageBox.Show("No Processes");

                    return "1";

                }

                UInt32 numIdsCopied = bytesCopied >> 2;

                if (0 != (bytesCopied & 3))

                {

                    UInt32 partialDwordBytes = bytesCopied & 3;


                    MessageBox.Show("EnumProcesses copied {0} and {1}/4th DWORDS...  Please ask it for the other {2}/4th DWORD"+

                        numIdsCopied+""+ partialDwordBytes+""+(4 - partialDwordBytes));

                    return "0";

                }

                for (UInt32 index = 0; index < numIdsCopied; index++)

                {


                    

                    UInt32 lpcbNeeded = 0;

                    String ModuleName = null;

                    IntPtr[] lphModule = new IntPtr[1024];

                    uint uiSize = (uint)(Marshal.SizeOf(typeof(IntPtr)) * (lphModule.Length));

                    // Get a handle to the process

                    IntPtr hProcess = OpenProcess(ProcessAccessFlags.QueryInformation & ProcessAccessFlags.VMRead, true, (uint)processIds[index]);

                    GCHandle gch = GCHandle.Alloc(lphModule, GCHandleType.Pinned);

                    IntPtr pModules = gch.AddrOfPinnedObject();


                    if (null != hProcess)

                    {

                        if (EnumProcessModules(hProcess, pModules, sizeof(UInt32), out lpcbNeeded) == 0)

                        {

                            Int32 uiTotalNumberOfModules = (Int32)(lpcbNeeded / (Marshal.SizeOf(typeof(IntPtr))));

                            for (int i = 0; i <= (int)uiTotalNumberOfModules; i++)

                            {

                                StringBuilder lpBaseName = new StringBuilder(1024);

                                GetModuleBaseName(hProcess, pModules, lpBaseName, (uint)lpBaseName.Capacity);

                                MessageBox.Show("\n ProcessIds[{0}] = hi i am robin i am process name" + lpBaseName);

                                // use intPtr here...

                                ModuleName = lpBaseName.ToString();

                               

                            }

                           

                        }

                        MessageBox.Show("\n ProcessIds[{0}] = {1}" + index + "\n" + ModuleName + "\n Process Names" + processIds[index]);

                    }

                    gch.Free();


                   

                }

                return "end";

            }


            


            

     

     

     


    Robin Karriottu Rajan
    Monday, February 14, 2011 1:23 AM
  • Hello Robin,

     

    There are several errors in your last code listing. I shall list them below together with some comments.

     

    1. Observe your call to the OpenProcess() API :

    IntPtr hProcess = OpenProcess(ProcessAccessFlags.QueryInformation & ProcessAccessFlags.VMRead, true, (uint)processIds[index]);

    I do not know how you have defined the entity named ProcessAccessFlags but the first parameter to OpenProcess() should be coded such that "ProcessAccessFlags.QueryInformation" is OR'ed with "ProcessAccessFlags.VMRead", e.g. :

    IntPtr hProcess = OpenProcess((ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VMRead), true, (uint)processIds[index]);

    AND'ing any 2 distinct bit flag values will result in a 0 value. For example :

    Let's say ProcessAccessFlags.QueryInformation is 0x0400, and ProcessAccessFlags.VMRead is 0x0010. Because each has a distinct bit flag set, AND'ing them will result in 0x0000.

    However, if you OR them, you get the value 0x0410.

     

    2. Soon after the call to OpenProcess(), there is an "if" statement testing the current value of "hProcess" :

    if (null != hProcess)...

    This is incorrect. This "if" condition will always evaluate to true because "hProcess" has been set to some value (the return value of the OpenProcess() API) hence it is not null.

    If I understood your intentions correctly, the above "if" statement should be coded as :

    if (IntPtr.Zero != hProcess)...

     

    3. The call to EnumProcessModules() has two mistakes :

    if (EnumProcessModules(hProcess, pModules, sizeof(UInt32), out lpcbNeeded) == 0)

    3.1 The 3rd parameter should be "uiSize" instead of "sizeof(UInt32)", where "uiSize" is :

    uint uiSize = (uint)(Marshal.SizeOf(typeof(IntPtr)) * (lphModule.Length));

    (revisit my code listed in my post dated Sunday February 13th).

    3.2 The correct return value to watch out for is "1" and not "0". Look up the documentation for EnumProcessModules() in MSDN.

    However, the documentation did state that the return value is nonzero if the call is successful and zero if the call is a failure. Hence the best way to code is :

    if (EnumProcessModules(hProcess, pModules, /*sizeof(UInt32)*/ uiSize, out lpcbNeeded) > 0) ...

     

    4. The second parameter in the call to GetModuleBaseName() must also be changed :

    Original code :

    GetModuleBaseName(hProcess, pModules, lpBaseName, (uint)lpBaseName.Capacity);

    Corrected code :

    GetModuleBaseName(hProcess, /*pModules*/ lphModule[i], lpBaseName, (uint)lpBaseName.Capacity);

    The second parameter takes an HMODULE value (represented by an IntPtr) from an element of the "lphModule" array. It should not take "pModules" which is a pointer to the "lphModule" array.

    Note that when we call EnumProcessModules(), we pass "pModules" (pointer to the "lphModule" array) and EnumProcessModules() will fill in values into the array via "pModules". Then, when EnumProcessModules() has done its job, the "lphModule" array is filled with HMODULE values and each is accessed via an index.

     

    - Bio.

     

    • Marked as answer by Johncy1 Monday, February 14, 2011 8:40 PM
    Monday, February 14, 2011 6:33 PM
  • Hello Bio,

     

    By now you may have understand my level of skill in programming Unmanaged Code, If you could suggest me tips how to improve my

    basic foundational knowledge for this kind of programming that would be great.

    I could use only those resources that are available in net, msdn and the pinvoke.net website but these sources are not consistent enough that is y there are so many errors in my code. I am very grateful for your help.

    Thank you.

     


    Robin Karriottu Rajan
    Monday, February 14, 2011 8:45 PM
  • Hello Robin,

     

    1. You are most welcome.

     

    2. >> If you could suggest me tips how to improve my basic foundational knowledge for this kind of programming that would be great...

    2.1 For this, I highly recommend getting hold of :

    .NET and COM: The Complete Interoperability Guide

    by Adam Nathan.

    Available from Amazon : http://www.amazon.com/exec/obidos/ASIN/067232170x/thecodeprojec-20

    2.2 It is by far the most comprehensive book of this topic.

     

    3. Best of luck, Robin.

     

    - Bio.

     

    Tuesday, February 15, 2011 5:01 PM