Вы можете сопоставить string
в C # с LPCWSTR
в C ++ для lpClassName
параметра CreateWindowEx()
. Они не равны.
- Одно решение:
См. @ Dan04's answer :
C # использует строки UTF-16, поэтому вы предпочтете версию "W"
эти функции. Используйте PdhOpenQueryW. Тогда первый параметр имеет C ++
введите const wchar_t *. Тип C # - [MarshalAs (UnmanagedType.LPWStr)]
строка.
Попробуйте следующий код:
delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
class Win32Window
{
const UInt32 WS_OVERLAPPEDWINDOW = 0xcf0000;
const UInt32 WS_VISIBLE = 0x10000000;
const UInt32 CS_USEDEFAULT = 0x80000000;
const UInt32 CS_DBLCLKS = 8;
const UInt32 CS_VREDRAW = 1;
const UInt32 CS_HREDRAW = 2;
const UInt32 COLOR_WINDOW = 5;
const UInt32 COLOR_BACKGROUND = 1;
const UInt32 IDC_CROSS = 32515;
const UInt32 WM_DESTROY = 2;
const UInt32 WM_PAINT = 0x0f;
const UInt32 WM_LBUTTONUP = 0x0202;
const UInt32 WM_LBUTTONDBLCLK = 0x0203;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct WNDCLASSEX
{
[MarshalAs(UnmanagedType.U4)]
public int cbSize;
[MarshalAs(UnmanagedType.U4)]
public int style;
public IntPtr lpfnWndProc;
public int cbClsExtra;
public int cbWndExtra;
public IntPtr hInstance;
public IntPtr hIcon;
public IntPtr hCursor;
public IntPtr hbrBackground;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpszMenuName;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpszClassName;
public IntPtr hIconSm;
}
private WndProc delegWndProc = myWndProc;
[DllImport("user32.dll")]
static extern bool UpdateWindow(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
static extern bool DestroyWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true, EntryPoint = "CreateWindowExW")]
public static extern IntPtr CreateWindowExW(
int dwExStyle,
[MarshalAs(UnmanagedType.LPWStr)]
string lpClassName,
[MarshalAs(UnmanagedType.LPWStr)]
string lpWindowName,
UInt32 dwStyle,
int x,
int y,
int nWidth,
int nHeight,
IntPtr hWndParent,
IntPtr hMenu,
IntPtr hInstance,
IntPtr lpParam);
[DllImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")]
static extern System.UInt16 RegisterClassExW([In] ref WNDCLASSEX lpWndClass);
[DllImport("kernel32.dll")]
static extern uint GetLastError();
[DllImport("user32.dll")]
static extern IntPtr DefWindowProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern void PostQuitMessage(int nExitCode);
[DllImport("user32.dll")]
static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);
internal bool create()
{
WNDCLASSEX wind_class = new WNDCLASSEX();
wind_class.cbSize = Marshal.SizeOf(typeof(WNDCLASSEX));
wind_class.style = (int)(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS);
wind_class.hbrBackground = (IntPtr)COLOR_BACKGROUND + 1;
wind_class.cbClsExtra = 0;
wind_class.cbWndExtra = 0;
wind_class.hInstance = Marshal.GetHINSTANCE(this.GetType().Module);
wind_class.hIcon = IntPtr.Zero;
wind_class.hCursor = LoadCursor(IntPtr.Zero, (int)IDC_CROSS);
wind_class.lpszMenuName = null;
wind_class.lpszClassName = "myClass";
wind_class.lpfnWndProc = Marshal.GetFunctionPointerForDelegate(delegWndProc);
wind_class.hIconSm = IntPtr.Zero;
ushort regResult = RegisterClassExW(ref wind_class);
if (regResult == 0)
{
uint error = GetLastError();
return false;
}
IntPtr hWnd = CreateWindowExW(0, wind_class.lpszClassName, "Hello Win32", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 300, 400, IntPtr.Zero, IntPtr.Zero, wind_class.hInstance, IntPtr.Zero);
Console.WriteLine($"{hWnd == IntPtr.Zero} {Marshal.GetLastWin32Error()}");
if (hWnd == ((IntPtr)0))
{
return false;
}
ShowWindow(hWnd, 1);
UpdateWindow(hWnd);
return true;
}
private static IntPtr myWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
switch (msg)
{
// All GUI painting must be done here
case WM_PAINT:
break;
case WM_DESTROY:
DestroyWindow(hWnd);
break;
default:
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
}
Обновление:
Примечание: Спасибо @IInspectable за напоминание. Измените код, чтобы использовать Unicode API, например RegisterClassExW и CreateWindowExW, для согласованности в моем ответе.
Но я не предлагаю использовать Unicode API в новом приложении Windows. Вместо этого для всех функций с текстовыми аргументами приложения должны обычно использовать прототипы обобщенных функций и определять UNICODE для компиляции функций в функции Unicode.
См .:
Юникод в Windows API ,
Условные обозначения для функциональных прототипов ,
Маршалинг по умолчанию для строк
- Другое решение:
Параметр lpClassName
метода CreateWindowEx () также принимает атом класса, созданный предыдущим вызовом функции RegisterClass или RegisterClassEx.
Поэтому, если RegisterClassEx () успешно, вы можете использовать его возвращаемое значение (ATOM) в качестве замены имени класса в CreateWindowExW () , чтобы увидеть, работает ли он , В C ++ это будет выглядеть так:
ATOM myClassAtom = RegisterClassExW(&wcex);
HWND hWnd = CreateWindowEx(0, (LPCWSTR)myClassAtom, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
В C #, на основе приведенного выше примера C #, используйте UInt16 вместо ATOM, это будет выглядеть так:
//...
[DllImport("user32.dll", SetLastError = true, EntryPoint = "CreateWindowExW")]
public static extern IntPtr CreateWindowExW(
int dwExStyle,
UInt16 lpClassName, // <---
[MarshalAs(UnmanagedType.LPWStr)]
string lpWindowName,
UInt32 dwStyle,
int x,
int y,
int nWidth,
int nHeight,
IntPtr hWndParent,
IntPtr hMenu,
IntPtr hInstance,
IntPtr lpParam);
//...
UInt16 regResult = RegisterClassExW(ref wind_class);
if (regResult == 0)
{
uint error = GetLastError();
return false;
}
IntPtr hWnd = CreateWindowExW(0, regResult, "Hello Win32", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 300, 400, IntPtr.Zero, IntPtr.Zero, wind_class.hInstance, IntPtr.Zero);