преобразовать код C ++ в C #: SendMessageTimeout ()

Прежде всего, документ для SendMessageTimeout:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644952%28v=vs.85%29.aspx

У меня есть этот код C ++, и я хочу преобразовать его в C #:

LRESULT success = SendMessageTimeout(
HWND_BROADCAST,
WM_SETTINGCHANGE,
0,
(LPARAM) "Environment",
SMTO_ABORTIFHUNG,
5000,
NULL
);

Что я сделал в C #:

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd,
uint Msg,
UIntPtr wParam,
IntPtr lParam,
uint fuFlags,
uint uTimeout,
out UIntPtr lpdwResult
);

SendMessageTimeout(
(IntPtr)0xFFFFFFFF,    //HWND_BROADCAST
0x001A,                //WM_SETTINGCHANGE
(UIntPtr)0,
(IntPtr)"Environment", // ERROR_1: can't convert string to IntPtr
0x0002,                // SMTO_ABORTIFHUNG
5000,
out UIntPtr.Zero       // ERROR_2: a static readonly field can not be passed ref or out
);

2

Решение

Для ваших вопросов.

  1. HWND_BROADCAST является 0xFFFF не 0xFFFFFFFF
  2. Вы должны будете выделить память для значения LPARAM вручную, используя Marshal.StringToHGlobalUni а затем освободить его после вызова с помощью Marshal.FreeHGlobal. Вы должны освободить эту память, иначе она протечет. Память маршала не мусор.
  3. За lpdwResult просто создайте IntPtr переменная и передать это. Вы можете просто игнорировать его значение.

Код должен быть примерно таким:

IntPtr result = IntPtr.Zero;
IntPtr setting = Marshal.StringToHGlobalUni("Environment");

SendMessageTimeout(
(IntPtr)0xFFFF,        //HWND_BROADCAST
0x001A,                //WM_SETTINGCHANGE
(UIntPtr)0,
(IntPtr)setting,
0x0002,                // SMTO_ABORTIFHUNG
5000,
out result
);

Marshal.FreeHGlobal(setting);

В общем, вы должны быть осторожны при освобождении памяти, которую вы передаете SendMessage вызов, так как вы не знаете, что получающее окно будет делать с указателем, который вы передаете ему. С тех пор WM_SETTINGCHANGE является встроенным сообщением Windows, Windows будет обрабатывать этот указатель для вас.

5

Другие решения

SendMessage немного болезненен из-за не дескриптивных типов аргументов, которые он использует. Необходимо, потому что для этого нужно много работы. Необходимо на языке C, но не на C #. Здесь вы хотите воспользоваться перегрузками, поддерживающими язык C #. Аргументы IntPtr могут быть просто ссылочными ссылочными типами, маршаллер pinvoke будет правильно преобразовывать их в указатель и заботиться о проблемах управления памятью. Так что просто создайте другой, совместимый с тем, как вы хотите его использовать:

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd,
int Msg,
IntPtr wParam,
string lParam,
int fuFlags,
int uTimeout,
IntPtr lpdwResult
);

Теперь вы можете использовать:

 SendMessageTimeout((IntPtr)0xffff, 0x001A, IntPtr.Zero, "Environment",
2, 5000, IntPtr.Zero);
5

По вопросам рекламы [email protected]