У меня странная проблема.
Я использую SendMessage для отправки строки всем запущенным экземплярам одного и того же приложения Windows Forms.
Я могу успешно отправить строковое представление числового значения указателя IntPtr, например:
unsafe private void SendString(IntPtr handle, IntPtr myHandle)
{
string s = handle.ToString(); // This will work and the value will be received.
// Try with "123553" which wont work.
// How can that be?
IntPtr lpData = Marshal.StringToHGlobalUni(s);
COPYDATASTRUCT data = new COPYDATASTRUCT();
data.dwData = 0;
data.cbData = s.Length * 2;
data.lpData = lpData;
IntPtr lpStruct = Marshal.AllocHGlobal(
Marshal.SizeOf(data));
Marshal.StructureToPtr(data, lpStruct, false);
int hTarget;
var succes = Int32.TryParse(s, out hTarget);
if (succes)
SendMessage(hTarget, WM_COPYDATA, handle, lpStruct);
}
Приложение-получатель правильно выводит значение типа «123553».
Однако, если я вручную присвою значение s
, ничего не будет получено:
string s = "123553";
Есть ли у кого-нибудь идеи, почему вызов ToString для IntPtr и жесткое кодирование значения не приводят к одинаковому поведению?
Код для самостоятельного запуска приложения находится здесь:
public const int WM_COPYDATA = 0x004a;
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
[MarshalAs(UnmanagedType.I4)]
public int dwData;
[MarshalAs(UnmanagedType.I4)]
public int cbData;
[MarshalAs(UnmanagedType.SysInt)]
public IntPtr lpData;
}
[DllImport("User32.dll")]
private static extern bool SendMessage(int hWnd,
int wMsg, IntPtr wParam, IntPtr lParam);
public Form1()
{
InitializeComponent();
}
unsafe protected override void WndProc(ref Message message)
{
if (message.Msg == WM_COPYDATA)
{
COPYDATASTRUCT data = (COPYDATASTRUCT)
message.GetLParam(typeof(COPYDATASTRUCT));
string str = new string((char*)(data.lpData),
0, data.cbData / 2);
Debug.WriteLine(str);
}
base.WndProc(ref message);
}
unsafe private void SendString(IntPtr handle, IntPtr myHandle)
{
string s = handle.ToString();
IntPtr lpData = Marshal.StringToHGlobalUni(s);
COPYDATASTRUCT data = new COPYDATASTRUCT();
data.dwData = 0;
data.cbData = s.Length * 2;
data.lpData = lpData;
IntPtr lpStruct = Marshal.AllocHGlobal(
Marshal.SizeOf(data));
Marshal.StructureToPtr(data, lpStruct, false);
int hTarget;
var succes = Int32.TryParse(s, out hTarget);
if (succes)
SendMessage(hTarget, WM_COPYDATA, handle, lpStruct);
}
private void button1_Click(object sender, EventArgs e)
{
Process currentProcess = Process.GetCurrentProcess();
var handles = (from process in Process.GetProcesses()
where
process.Id != currentProcess.Id &&
process.ProcessName.Equals(
currentProcess.ProcessName,
StringComparison.Ordinal)
select process.MainWindowHandle).ToList<IntPtr>();
foreach (var handle in handles)
{
SendString(handle, this.Handle);
Debug.WriteLine(string.Format("Sending handle {0} from handle {1}", handle, this.Handle));
}
}
Источники:
Обнаружение, если другой экземпляр приложения уже запущен а>
Использование WM_COPYDATA для межпроцессного взаимодействия (VFP9)
StringToHGlobalHUni
(не должно). Чтобы исключить это, добавьте строкуs = String.Intern(s);
сразу после вашегоhandle.ToString()
звонка. - person Anders Abel   schedule 12.01.2013COPYDATASTRUCT
ожидает IntPtr,Marshal.StringToHGlobalUni
ожидает строку, а параметрhWnd
SendMessage ожидает int, следовательно, все преобразования. Хотя я мог бы использоватьIntPtr.ToInt32()
. @AndersAbel String.Intern не повлиял наStringToGlobalHUni
. Спасибо вам за ваши предложения. - person hlintrup   schedule 13.01.2013SendMessage
инаяCOPYDATASTRUCT
. Я недостаточно разбираюсь в этом, чтобы сказать, почему это работает, но это действительно так. Спасибо, что нашли время оставить отзыв. - person hlintrup   schedule 13.01.2013