Link to home
Start Free TrialLog in
Avatar of derekthornton
derekthornton

asked on

Casting to IntPtr

I need to make an implicit cast to IntPtr from an int *, but I can't do anything within either class. How can I do this?
Avatar of Kyle Abrahams, PMP
Kyle Abrahams, PMP
Flag of United States of America image

You can't.  The .NET environment doesn't allow direct access to memory variables.  It helps to protect against buffer overruns.  

You can't.  The .NET environment doesn't allow direct access to memory variables.  It helps to protect against buffer overruns.  

Avatar of derekthornton
derekthornton

ASKER

That isn't true in the slightest. You can use pointers in C#.
And buffer overruns has nothing to do with it. Unsafe code is restricted for memory disposal reasons. You must compile code with an unsafe switch to use memory variables. But they work just fine in C# code. And for the task I need to perform, I have to use them. But I need to cast to and from an IntPtr, but the IntPtr library is sealed and cannot be inherited, so I cannot add an operator overload to it's class.
Please show your code. If int* points to managed object, such conversion may be dangerous because this object may be move by garbage collector.
Can you post the code so that we see how you use int* and in what kind of block?
Post your code and describe what problem do you try to solve. .NET makes impossible getting unmanaged pointer to managed object because managed object may be moved by GC making unmanaged pointer invalid. To get unmanaged pointer (IntPtr) for API which points to some data, we need to use Marshal allocation functions like Marshal.AllocHGlobal Method.
See also this thread:

https://www.experts-exchange.com/questions/20932459/Importing-a-C-style-dll-AND-marshalling-confusing-data-types.html
ASKER CERTIFIED SOLUTION
Avatar of TheAvenger
TheAvenger
Flag of Switzerland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Err.. I have the casting conversion working just fine. The problem is with library access. I can't make an implicit operator to IntPtr because IntPtr is a .NET class and I cannot access it, and casting operators have to be within the class they modify. I already know how to do the conversion, I'm trying to figure out how to make it easier by providing an implicit cast to it.
i.e.

int * UnmanagedObject = // ...
IntPtr lpMyCoolStuff = ( Sturcture )  Marshal.PtrToStructure(  (IntPtr) UnmanagedObject , Structure );

This conversion works just fine. I just want to be able to type ...

IntPtr lpMyCoolStuff = UnmanagedObject instead though.
OK, if you don't want to share the code, try this: in C# you can convert without any loss the IntPtr to int like this:

int i;
IntPtr iptr;
....
iptr = (IntPtr)i;
i = (int)iptr;

Then you can move the value as if it's an int (which is also compatible with any kind of pointers in C/C++ for example)
I can post the code. It's just very long. Give me a few moments to gather up all that it requires.
using System;
using System.Runtime;
using System.Runtime.InteropServices;

namespace TOCR
{

      unsafe public abstract class TOCRGetResults
      {

            #region Instance Fields

            /// <summary> The Starting Point of the Items </summary>
            private static IntPtr AddressOfItems;

            #endregion

            #region Constructor

            /// <summary> Retrieves the Results for a specific OCR Job </summary>
            /// <param name="JobNo"></param>
            /// <param name="ResultsStr"></param>
            public static void GetResults ( ref int JobNo , ref string ResultsStr )
            {
                  // The Size of the Results
                  int ResultsInf = 0;
                  // The Actual Results
                  int * TOCRResults = (int *)0;
                  // The Structured Results
                  TOCR.TOCRResults OCRResults = new TOCRResults();
                  // The Location of The Items Within the results
                  AddressOfItems = IntPtr.Zero;

                  // Allocate Memory for the Results
                  AllocateMemory ( ref JobNo, ref ResultsInf );
                  // Allocate the Results
                  AllocateResults ( ref JobNo, ref ResultsInf,ref TOCRResults );
                  // Determine the Difference between the Items and the Header
                  AllocateItemAddress ( TOCRResults , ref AddressOfItems );
                  // Allocate the Header
                  AllocateHeader ( TOCRResults, ref OCRResults );
                  // Allocate the Items
                  AllocateItems ( TOCRResults, ref OCRResults );
                  // Build the Results String
                  BuildString ( ref OCRResults, ref ResultsStr );

            }

            #endregion

            #region Private Methods

            #region Memory Allocation

            /// <summary> Allocates the memory needed for the OCR Job Results </summary>
            /// <param name="JobNo"></param>
            /// <param name="ResultsInf"></param>
            private static void AllocateMemory ( ref int JobNo, ref int ResultsInf )
            {
                  // Determine the needed memory size
                  API.TOCRGetJobResults ( JobNo, ref ResultsInf, IntPtr.Zero );
            }

            /// <summary> Allocates the OCR Results to the correct memory address </summary>
            /// <param name="JobNo"></param>
            /// <param name="ResultsInfo"></param>
            /// <param name="TOCRResults"></param>
            private static void AllocateResults ( ref int JobNo, ref int ResultsInf, ref int * TOCRResults )
            {
                  // Allocate the memory
                  TOCRResults = (int *)Marshal.AllocHGlobal ( (int) ResultsInf );
                  // Allocate the OCR Results to the reserved memory address
                  API.TOCRGetJobResults ( JobNo, ref ResultsInf, TOCRResults );
            }

            #endregion

            #region Memory Shifting

            /// <summary> Determines where the Header ends and the items begin </summary>
            /// <param name="TOCRResults"></param>
            /// <param name="ItemAddress"></param>
            private static void AllocateItemAddress ( int * TOCRResults, ref IntPtr ItemAddress )
            {
                  ItemAddress = ( IntPtr )
                        ( (int) ( TOCRResults ) +
                        Marshal.SizeOf ( typeof ( TOCRResultsHeader ) ) );
            }

            /// <summary> Allocate the Header Data </summary>
            /// <param name="TOCRResults"></param>
            /// <param name="OCRResults"></param>
            private static void AllocateHeader ( int * TOCRResults , ref TOCRResults OCRResults )
            {
                  // Convert the appropriate parts of the memory to a TOCRResultsHeader object
                  OCRResults.Hdr = ( TOCRResultsHeader )
                        Marshal.PtrToStructure ( (IntPtr) TOCRResults , typeof ( TOCRResultsHeader ) );
            }

            /// <summary> Allocate the Item Data </summary>
            /// <param name="TOCRResults"></param>
            /// <param name="OCRResults"></param>
            private static void AllocateItems ( int * TOCRResults, ref TOCRResults OCRResults )
            {
                  OCRResults.Item = ( TOCRResultsItem )
                        Marshal.PtrToStructure (
                        AddressOfItems,
                        typeof ( TOCRResultsItem ) );
            }

            #endregion

            #region Item Assignment

            /// <summary> Increment the Item Location </summary>
            /// <param name="Item"></param>
            /// <param name="Offset"></param>
            private static void OffsetItem ( ref TOCRResultsItem Item, int Offset )
            {
                  Item = ( TOCRResultsItem )
                        Marshal.PtrToStructure (
                        (IntPtr)( (int) AddressOfItems + Offset * Marshal.SizeOf(typeof ( TOCRResultsItem ) ) ) ,
                        typeof( TOCRResultsItem ) );
            }

            /// <summary> Builds the complete string to return </summary>
            /// <param name="OCRResults"></param>
            /// <param name="ResultsStr"></param>
            private static void BuildString ( ref TOCRResults OCRResults, ref string ResultsStr )
            {
                  for ( int i = 0; i < OCRResults.Hdr.NumItems ; i++ )
                  {
                        OffsetItem ( ref OCRResults.Item, i );
                        ResultsStr += OCRResults.Item.ToString();
                  }
            }
            
            #endregion

            #endregion

      }

}
What happens if you use directly:

IntPtr lpMyCoolStuff = (IntPtr)UnmanagedObject;
It doesn't work. See the code above. I have to seperate the pointer out into two objects.
TOCRGetResults takes a JobNumber, and two other variables. If the third parameter is null or 0, then it sets the second parameter equal to the number of bytes needed to allocate in memory for OCR Results. If the third parameter is a pointer to a memory address,it allocates the Results to that memory Address. I've done this same code with IntPtr, and It works, but there is very heavy data loss in between.

I have to then split the int * up into a TOCRResultsHeader and Multiple TOCRResultsItem structures from there, using the Size of a TOCRResultsHeader as an offset with the Item Number to get the appropriate memory address. The code WORKS fine, I just want ot make it CLEANER.
OK, I see. I don't think however that you have another chance to make it. In the best case you can make a method that will execute the same and then call

IntPtr lpMyCoolStuff = MyMethod (UnmanagedObject);

and inside MyMethod do exactly the same you are making at the moment. This will just simplify the sintax a little bit
Of course. But making the syntax more simple is a considerable thing, since difficult to read code is just a breeding ground for more bugs.
I'd basically like to be able to do an implicit cast through IntPtr/int *.
And yes, I know this code may be messed up by the garbage collector. However it's the only way to make this thing work right.
( IntPtr ) ( (int) (lpItem) + Marshal.SizeOf( typeof ( TOCRResultsHeader ) )

this code here is more or less what I'm looking to simplify.
Unfortunately I am not sure I can help you with something else :-(( Hope somebody else helps...
derekthornton, maybe you can write simple prototype which shows what you want to do, what version works and what version doesn't work. I don't understand your code, maybe simple code which demonstrates the problem without unnecessary details can help.
Hello! It seems that you two are very good at this thing, could you please have a look at my question:
https://www.experts-exchange.com/questions/20949171/From-managed-Object-to-unmanaged-IUnknown.html

It has been here for 21 days without an answer :-(
AlexFM. I'm sorry I haven't replied. I sort of gave up hope on this question, but your answers were all very helpful for a lot of things. I'm not sure what to do. Should I still give the points and close the question?
If you got satisfactory answer, accept it. If not, ask Community Support to close this question.