WinAPI SendMessage из .NET

У меня есть пример кода winapi:

struct CommunicationInfo {
    long internalMsg;
    const TCHAR * srcModuleName;
    void * info; 
  };

...

const TCHAR* szText = _T("Hello from my plugin!\n(test message)");
    CommunicationInfo ci = { 0x0401, cszMyPlugin, (void *) szText };
    ::SendMessage( hNppWnd, 0x111, (WPARAM) _T("NppExec.dll"), (LPARAM) &ci );

Я хочу сделать тот же вызов из .net, и я написал такую ​​​​оболочку:

[StructLayout(LayoutKind.Sequential)]
    public struct CommunicationInfo
    {
        public Int64 internalMsg;
        [MarshalAs(UnmanagedType.LPWStr)]
        public StringBuilder srcModuleName;
        [MarshalAs(UnmanagedType.LPWStr)]
        public StringBuilder data;
    };

...

[DllImport("user32")]
public static extern IntPtr SendMessage(IntPtr hWnd, 
    NppMsg Msg, IntPtr wParam, 
    [MarshalAs(UnmanagedType.Struct)] CommunicationInfo communicationInfo);

...

SendMessage(hNppWnd, 0x111, 
    Marshal.StringToHGlobalUni("NppExec.dll"), 
    new CommunicationInfo 
    { 
        data = new StringBuilder("test test"),
        internalMsg = 0x0401,
        srcModuleName = new StringBuilder("ModuleName")
    });

Но этот код не работает. Где я сделал ошибку?


person Eugene Gluhotorenko    schedule 20.05.2012    source источник


Ответы (2)


Как указывает Виктор, C/C++ long имеет размер 32 бита, поэтому его необходимо сопоставить с C# int. Кроме того, передача структуры обрабатывается неправильно. Кроме того, происходит утечка вызова StringToHGlobalUni, поскольку вы никогда не вызываете FreeHGlobal.

Я бы, вероятно, справился с сортировкой примерно так:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct CommunicationInfo
{
    public int internalMsg;
    public string srcModuleName;
    public string data;
};
....
[DllImport("user32")]
public static extern IntPtr SendMessage(
    IntPtr hWnd, 
    uint Msg, 
    [MarshalAs(UnmanagedType.LPWStr)] string wParam, 
    ref CommunicationInfo communicationInfo
);
....
CommunicationInfo communicationInfo = new CommunicationInfo 
{ 
    internalMsg = 0x0401,
    srcModuleName = "ModuleName",
    data = "test test"
};
SendMessage(hNppWnd, 0x111, "NppExec.dll", ref communicationInfo);
person David Heffernan    schedule 21.05.2012
comment
hNppWnd — это окно в том же процессе, что и исполняемый код. В любом случае ваш код работает нормально. Спасибо! - person Eugene Gluhotorenko; 21.05.2012
comment
Отлично. Я просто хотел охватить все базы! - person David Heffernan; 21.05.2012

Я полагаю, что поле «long» в структуре CommunicationInfo является 32-битным в WinAPI. Поэтому попробуйте определить «internalMsg» как System.Int32 в C#.

Чтобы быть уверенным, попробуйте вызвать printf("%d\n", sizeof(CommunicationInfo)) в C/C++, чтобы узнать фактический размер. Если это (4 + 4 + 4) в 32-разрядной системе, то структура C# также должна иметь размер 12 байт.

Указатель "char*" также должен быть указателем на неуправляемую память, поэтому StringBuilder просто не подойдет.

См. эту ошибку PInvoke при маршаллинге структуры со строкой в ​​ней. для примера сортировки

person Viktor Latypov    schedule 20.05.2012
comment
Попробовал с Int32 - то же самое. А чтобы проверить printf(%d\n, sizeof(CommunicationInfo)) нету компилятора под рукой. в любом случае, в естественном реальном размере - person Eugene Gluhotorenko; 21.05.2012
comment
[MarshalAs(UnmanagedType.LPWStr)] public StringBuilder srcModuleName; также создает проблемы. Попробуйте поискать в SO ответ о том, как маршалировать указатели на строки. StringBuilder не поможет. Вы должны выделить неуправляемую память для каждого из полей. - person Viktor Latypov; 21.05.2012
comment
stackoverflow.com/questions/1223690/ - person Viktor Latypov; 21.05.2012
comment
Да, в Windows long составляет 32 бита как в C, так и в C++ как для 32-битных, так и для 64-битных процессов. - person David Heffernan; 21.05.2012
comment
Просто указал на проблему ОП. Конечно, long — это 32-разрядная версия Windows. Список режимов адресации/int находится здесь unix.org/version2/whatsnew/lp64_wp.html. - person Viktor Latypov; 21.05.2012