martedì 9 dicembre 2008

String & P/Invoke with C#

Sometime I hear about c# problem with the P/Invoke and string.
Here I add a very simple usage of it, it describe C++ CString and c# String.

1. SetWindowText
First I begin with a sample really simple. How to set a string of a dialog. I invoke the SetWindowTextW.
You can define this for mobile app
[DllImport ("coredll.dll", EntryPoint="SetWindowTextW")]
private static extern void SetWindowText(IntPtr hWnd, string lpString);
You can define this for desktop app
[DllImport("user32.dll"), EntryPoint="SetWindowTextW")]
private static extern bool SetWindowText(IntPtr hWnd, string lpString);

Call the function with this code snippet
public bool SetText(IntPtr hWnd, String text)
{
System.text.StringBuilder NewWindowText = new System.text.StringBuilder(text);
return (SetWindowText(hWnd, NewWindowText) != 0);
}
GetWindowText
The second example is one that creates more problems. The fault probably is derived from the fact that many people use the String for these conversions instead of the StringBuild. To do this I need two P/Invoke the first for retrieve the lenght the second to retrieve the text.

You can define this for mobile app
[DllImport("coredll.dll", CharSet = CharSet.Auto, SetLastError = true), EntryPoint="GetWindowTextW")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("coredll.dll", SetLastError = true, EntryPoint="GetWindowTextLength")]
static extern int GetWindowTextLength(IntPtr hWnd);

You can define this for desktop app
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true), EntryPoint="GetWindowTextW")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, EntryPoint="GetWindowTextLength")]
static extern int GetWindowTextLength(IntPtr hWnd);
Call the function with this code snippet
public string GetText(IntPtr hWnd)
{
int length = GetWindowTextLength(hWnd);
StringBuilder TheWindowText = new StringBuilder(length + 1);
GetWindowText(hWnd, TheWindowText, TheWindowText.Capacity);
return TheWindowText.ToString();
}
If anybody knows any more graceful solution, I'd like to know it.
I hope my suggestions are useful to someone.

2 commenti:

id ha detto...

Hola!

Thanks for sharing your info.

In the last case, do you think you need to used the fixed statement for the StringBuilder object that is passed?

For example:

GetText(IntPtr hWnd)
{
int length = GetWindowTextLength(hWnd);
StringBuilder TheWindowText = new StringBuilder(length + 1);
fixed(TheWindowText)
{
GetWindowText(hWnd, TheWindowText, TheWindowText.Capacity);
}
return TheWindowText.ToString();
}

Dr.Luiji ha detto...

First of all thanks for the comment, but I don't think is necessary.

Becouse with the StringBuilder constructor I already fixed the size.

If you think to use the fixed statement to prevent the garbage collector this isn't the case, it isn't a movable variable.

Regards
Dr.Luiji