GillyTheTaffy
asked on
Pointers in C#
Hi there - I am accessing a 3rd party database product via its api (written in C++). One of the functions returns a pointer to a string value. Is there an easy way to use pointers in C#.
I just need the string value. I've never really messed around with pointers before.
The api declaration is as follows
[DllImport("myThirdPartyDl l.dll")] private static extern char * TM1ValStringGet ( int hUser, int vString) ;
thanks in advance
Graham
I just need the string value. I've never really messed around with pointers before.
The api declaration is as follows
[DllImport("myThirdPartyDl
thanks in advance
Graham
In c# the best way to use pointers is by using the "ref" keyword in front of the variable, also I think you can use the ampersand im not sure about this though.
strings are immutable objects ... you can either use an IntPtr and then marshal yourself or you can pass a stringbuilder (I know that sounds odd:) )
http://www.dotnet247.com/247reference/msgs/49/246277.aspx has an example but I will put it here for PAQ.
// DLL import in my "UnsafeNativeMethods" class.
[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet =
CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int MSG, int wParam,
System.Text.StringBuilder lParam);
....
// Here we get the text from a text box.
int length = (int)UnsafeNativeMethods.S endMessage (this.Hand le,
UnsafeNativeMethods.WM_GET TEXTLENGTH , IntPtr.Zero, IntPtr.Zero);
if (length > 0)
{
StringBuilder sb = new StringBuilder(length + 1);
UnsafeNativeMethods.SendMe ssage(this .Handle,
UnsafeNativeMethods.WM_GET TEXT, sb.Capacity, sb);
buffer = sb.ToString();
}
if your input string will not be modified by the dll use
string as the parameter type. For output strings, use the
System.Text.StringBuilder class. Either way, the parameter should be
passed by value, leave out the "ref".
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpcondefaultmarshalingforstrings.asp is worth taking a look at.
http://www.dotnet247.com/247reference/msgs/49/246277.aspx has an example but I will put it here for PAQ.
// DLL import in my "UnsafeNativeMethods" class.
[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet =
CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int MSG, int wParam,
System.Text.StringBuilder lParam);
....
// Here we get the text from a text box.
int length = (int)UnsafeNativeMethods.S
UnsafeNativeMethods.WM_GET
if (length > 0)
{
StringBuilder sb = new StringBuilder(length + 1);
UnsafeNativeMethods.SendMe
UnsafeNativeMethods.WM_GET
buffer = sb.ToString();
}
if your input string will not be modified by the dll use
string as the parameter type. For output strings, use the
System.Text.StringBuilder class. Either way, the parameter should be
passed by value, leave out the "ref".
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpcondefaultmarshalingforstrings.asp is worth taking a look at.
ASKER
ok - I'm a bit confused with a couple of things here
Is the second parameter to the SendMessage function the pointer returned from my api call - eg presuming all is in the same class
// Database provided api that returns a pointer in its documentation
[DllImport("myThirdPartyDl l.dll")] private static extern char * TM1ValStringGet ( int hUser, int vString) ;
// Send message to populate string builder
DllImport("user32.dll", EntryPoint = "SendMessage", CharSet =
CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int MSG, int wParam,
System.Text.StringBuilder lParam);
// Presume that hUser and hString are correct parameters for the api to return a valid pointer
unsafe{
char* myPointer=TM1ValStringGet( hUser,hStr ing);
// Documentation provides us with the max length of any strings returned
// by the database 256
System.Text.StringBuilder sb=new System.Text.Stringbuilder( 256);
SendMessage(This.Handle,my Pointer,sb .Capacity, sb);
string myVal=sb.ToString();
}
What is the first handle being passed to the SendMessage api (this.handle) - as I am not using a form to display the data (just compiling an xml document) therefore there is no handle property in This.
Otherwise am I on the right track ?
TIA
Is the second parameter to the SendMessage function the pointer returned from my api call - eg presuming all is in the same class
// Database provided api that returns a pointer in its documentation
[DllImport("myThirdPartyDl
// Send message to populate string builder
DllImport("user32.dll", EntryPoint = "SendMessage", CharSet =
CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int MSG, int wParam,
System.Text.StringBuilder lParam);
// Presume that hUser and hString are correct parameters for the api to return a valid pointer
unsafe{
char* myPointer=TM1ValStringGet(
// Documentation provides us with the max length of any strings returned
// by the database 256
System.Text.StringBuilder sb=new System.Text.Stringbuilder(
SendMessage(This.Handle,my
string myVal=sb.ToString();
}
What is the first handle being passed to the SendMessage api (this.handle) - as I am not using a form to display the data (just compiling an xml document) therefore there is no handle property in This.
Otherwise am I on the right track ?
TIA
it was just an example ... but yes you would be looking to use a stringbuilder ... it is explained in fairly good detail in the link above.
ASKER
thanks for your help. I have found an alternative for what I need
if I change the return type to a Stringbuilder then yes it works - however some of the string values have odd characters like { _ , - etc so it falls over when I try and populate the string builder. So - I did some more reading and all I needed to do was make the return type IntPtr and then use the Marshal.Class To convert it to ANSI text
see below
[DllImport("myThirdPartyDl l.dll")] private static extern IntPtr TM1ValStringGet ( int hUser, int vString) ;
IntPtr myHandle = TM1ValStringGet(hUser,hVal ue);
String myVal = Marshall.PtrToStringAnsi(m yHandle);
thanks again
Graham
if I change the return type to a Stringbuilder then yes it works - however some of the string values have odd characters like { _ , - etc so it falls over when I try and populate the string builder. So - I did some more reading and all I needed to do was make the return type IntPtr and then use the Marshal.Class To convert it to ANSI text
see below
[DllImport("myThirdPartyDl
IntPtr myHandle = TM1ValStringGet(hUser,hVal
String myVal = Marshall.PtrToStringAnsi(m
thanks again
Graham
"you can either use an IntPtr and then marshal yourself or you can pass a stringbuilder"
ASKER
ah! Now you first post makes sense! lol
cheers
cheers
ASKER
Hello again Gregory
I've got a similar issue when some the unamanaged api's are expecting char * as input parameters
eg
[DllImport("myThirdPartyDl l.dll")] private static extern int TM1SystemServerHandle( int hUser, char * vString) ;
I thought I would just reverse what I did when retrieving pointer values using the Marshall class. I had been previously passing a string but have started getting spurious results like I was before you fixed my previous issue
eg
change the api call to
[DllImport("myThirdPartyDl l.dll")] private static extern int TM1SystemServerHandle( int hUser, intPnt vString) ;
than call using
string s="myString"
int iRet=IntPnt x=Marshall.PtrToStringAnsi (s)
this produces the same results as if I was still passing in the string direct. I have alos tried the other Marshall.PtrTo...... functions with no joy and also tried passing in a StringBuilder object
the equiv C++ code reads as follows
//Header file
typedef TM1_INDEX * TM1V; // value handle
TM1IMPORT TM1V TM1API TM1SystemServerHandle( TM1U hUser, CHAR * szName );
LPSTR sMyString="myString";
// assume huser is a valid handle
TM1SystemServerHandle( hUser, sMyString );
any help would be greatly appreciated
graham
I've got a similar issue when some the unamanaged api's are expecting char * as input parameters
eg
[DllImport("myThirdPartyDl
I thought I would just reverse what I did when retrieving pointer values using the Marshall class. I had been previously passing a string but have started getting spurious results like I was before you fixed my previous issue
eg
change the api call to
[DllImport("myThirdPartyDl
than call using
string s="myString"
int iRet=IntPnt x=Marshall.PtrToStringAnsi
this produces the same results as if I was still passing in the string direct. I have alos tried the other Marshall.PtrTo...... functions with no joy and also tried passing in a StringBuilder object
the equiv C++ code reads as follows
//Header file
typedef TM1_INDEX * TM1V; // value handle
TM1IMPORT TM1V TM1API TM1SystemServerHandle( TM1U hUser, CHAR * szName );
LPSTR sMyString="myString";
// assume huser is a valid handle
TM1SystemServerHandle( hUser, sMyString );
any help would be greatly appreciated
graham
ASKER
think I've got it but won't know for sure till tomorrow when I can test it
change the api call to....
[DllImport("myThirdPartyDl l.dll")] private static extern int TM1SystemServerHandle (int hUser ,[MarshalAs(UnmanagedType. LPStr)] StringBuilder ipntName );
thanks if you even read this
Graham
change the api call to....
[DllImport("myThirdPartyDl
thanks if you even read this
Graham
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
doh - didn't work.