LPWSTR in C#
-
This is the API I want to use:
long LoginDlg ( long lDSType, **LPTSTR** lptstrDataSource, long lDSLength, **LPCTSTR** lpctstrUsername, **LPCTSTR** lpctstrPassword, )
I wrap it like this: [DllImport("user.dll")]int LoginDlg ( int lDSType, **string**lptstrDataSource, int lDSLength, **string**lpctstrUsername, **string**lpctstrPassword, )
Now I got the new version of this api, the only difference is using LPWSTR instead of LPTSTRlong LoginDlg ( long lDSType, **LPWSTR** lptstrDataSource, long lDSLength, **LPCWSTR** lpctstrUsername, **LPCWSTR** lpctstrPassword, )
I use the same wrapper, it doesn't work as usual. Do you have any ideas what's wrong with my wrapper? Thanks in advance. -
This is the API I want to use:
long LoginDlg ( long lDSType, **LPTSTR** lptstrDataSource, long lDSLength, **LPCTSTR** lpctstrUsername, **LPCTSTR** lpctstrPassword, )
I wrap it like this: [DllImport("user.dll")]int LoginDlg ( int lDSType, **string**lptstrDataSource, int lDSLength, **string**lpctstrUsername, **string**lpctstrPassword, )
Now I got the new version of this api, the only difference is using LPWSTR instead of LPTSTRlong LoginDlg ( long lDSType, **LPWSTR** lptstrDataSource, long lDSLength, **LPCWSTR** lpctstrUsername, **LPCWSTR** lpctstrPassword, )
I use the same wrapper, it doesn't work as usual. Do you have any ideas what's wrong with my wrapper? Thanks in advance.First, understand how the unmanaged code (i.e., native code) looks (essentially):
typedef char CHAR;
typedef CHAR* LPSTR;
typedef wchar_t WCHAR;
typedef WCHAR* LPWSTR;
#ifdef UNICODE
typedef WCHAR TCHAR;
typedef WCHAR* LPTSTR;
#else
typedef CHAR TCHAR;
typedef CHAR* LPSTR;
#endifThat means that any Unicode strings use "W" as a convention (this is true with most Microsoft APIs - as well as others' APIs - that take strings as parameters; they end with either "A" for ANSI or "W" for Unicode and are #define'd without either "A" or "W", which is the one you typically call). When you use P/Invoke or COM interop (both are interop features), you must dictate which string encoding to use. By default in C#,
CharSet.Ansi
is used. In most cases when calling Microsoft APIs (and others - those I mentioned above), you will want to useCharSet.Auto
. Where do you use those? When declaring P/Invoke methods, you use them in theDllImportAttribute
like so:// Note: following is only anexample.
// You can more easily get the computer name by using Environment.MachineName.
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static extern bool GetComputerName([Out] string name, ref int size);When you're declaring a struct with string members, you do the same in the
StructLayoutAttribute
. In both cases, you can override the string encoding using theMarshalAsAttribute
. Lets say, for some reason, you had a struct with ANSI and Unicode versions, except for one string member that must always be ANSI:[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct Example
{
public string Field1;
public string Field2;
[MarshalAs(UnmanagedType.LPStr)] public string Field3;
}We default to
CharSet.Auto
(saves typing and is easier to maintain) but override the unmanaged type asUnmanagedType.LPStr
(as opposed toUnmanagedType.LPWStr
), so that it's always ANSI. You can do the same with P/Invoke declarations. Just make sure you understand the unmanaged code well enough to know whether it's always ANSI or Unicode, or if it is platform dependent (i.e., ANSI on Windows, Unicode on Windows NT). This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [ -
First, understand how the unmanaged code (i.e., native code) looks (essentially):
typedef char CHAR;
typedef CHAR* LPSTR;
typedef wchar_t WCHAR;
typedef WCHAR* LPWSTR;
#ifdef UNICODE
typedef WCHAR TCHAR;
typedef WCHAR* LPTSTR;
#else
typedef CHAR TCHAR;
typedef CHAR* LPSTR;
#endifThat means that any Unicode strings use "W" as a convention (this is true with most Microsoft APIs - as well as others' APIs - that take strings as parameters; they end with either "A" for ANSI or "W" for Unicode and are #define'd without either "A" or "W", which is the one you typically call). When you use P/Invoke or COM interop (both are interop features), you must dictate which string encoding to use. By default in C#,
CharSet.Ansi
is used. In most cases when calling Microsoft APIs (and others - those I mentioned above), you will want to useCharSet.Auto
. Where do you use those? When declaring P/Invoke methods, you use them in theDllImportAttribute
like so:// Note: following is only anexample.
// You can more easily get the computer name by using Environment.MachineName.
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static extern bool GetComputerName([Out] string name, ref int size);When you're declaring a struct with string members, you do the same in the
StructLayoutAttribute
. In both cases, you can override the string encoding using theMarshalAsAttribute
. Lets say, for some reason, you had a struct with ANSI and Unicode versions, except for one string member that must always be ANSI:[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct Example
{
public string Field1;
public string Field2;
[MarshalAs(UnmanagedType.LPStr)] public string Field3;
}We default to
CharSet.Auto
(saves typing and is easier to maintain) but override the unmanaged type asUnmanagedType.LPStr
(as opposed toUnmanagedType.LPWStr
), so that it's always ANSI. You can do the same with P/Invoke declarations. Just make sure you understand the unmanaged code well enough to know whether it's always ANSI or Unicode, or if it is platform dependent (i.e., ANSI on Windows, Unicode on Windows NT). This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [According to my understanding, the new method is using Unicode all the time. So I wrap it like this now:
[DllImport("user.dll", CharSet = CharSet.Unicode)] int LoginDlg ( int lDSType, string lptstrDataSource, int lDSLength, string lpctstrUsername, string lpctstrPassword, )
But why it still doesn't work? -
According to my understanding, the new method is using Unicode all the time. So I wrap it like this now:
[DllImport("user.dll", CharSet = CharSet.Unicode)] int LoginDlg ( int lDSType, string lptstrDataSource, int lDSLength, string lpctstrUsername, string lpctstrPassword, )
But why it still doesn't work?Since the function is defined externally, you have to modify it as such, and all P/Invoke functions are static (i.e., they aren't defined by a class). Your signature should look like this:
[DllImport("user.dll", CharSet=CharSet.Unicode)]
extern static int LoginDlg(
int lDSType,
string lptstrDataSource,
int lDSLength,
string lpctstrUsername,
string lpctstrPassword);Drop the comma after
lpctstrPassowrd
and add a semi-colon after the declaration, as well. BTW, since the parameter names begin with eitherlp**t**str
orlpc**t**str
, they are most likely using platform-dependent string encodings. You best check your API documentation and thoroughly examine your headers. Using "t" typically means that a string is platform dependent, although thiscould be just a different naming convention for your APIs. If these are Microsoft APIs, I assure you they're platform-dependent strings and you should useCharSet.Auto
. This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles]