Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > C# и WinAPI


Автор: erm0l0v 12.1.2011, 16:07
Мне нужно отправить сообщение.

Загружаю SendMessage
Код

[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, int Msg, string wParam, string lParam);


Отправляю сообщение
Код

str = "Hello World!\0";
SendMessage(hWnd, MsgId.PrintReport, str, null);


Сообщение приходит, но вот значение параметра wParam Совершенно не предсказуемо.

В чем может быть ошибка?

Автор: erm0l0v 12.1.2011, 17:32
Кстати, забыл добавить сообщение ловит программа написанная на Delphi

Только что попробовал отправить сообщение WM_SETTEXT все сработало нормально.

Есть предположение что косяк в преобразовании из string C# в String Delphi.

Пробовал слать это же сообщение из C++ все работает нормально.

(Доступа к исходным кодам на Delphi нет) единственно что нашел в документации есть пример как отправлять это сообщение из Delphi там у них строка преобразуется так:

Код

WParam:=Integer(PChar(RepList.Text)); 

Автор: Любитель 12.1.2011, 17:52
Цитата(erm0l0v @  12.1.2011,  17:32 Найти цитируемый пост)
Пробовал слать это же сообщение из C++ все работает нормально.

Покажите код на C++. Скорей всего там у вас анси строк, а здесь юникод (по дефолту). В дельфийской проге кастится к анси строке (указателю, но не суть).

Автор: erm0l0v 12.1.2011, 18:00
На C++ отправляю так:
Код

SendMessage(hWinPost, RegMessage::wm_winpost_printreport, (WPARAM)"\nHello world!!!", 0);


Я не думаю что проблема с кодировкой, он каждый раз выдает разные символы. Если бы проблема была с кодировкой то думаю что символы были бы одни и теже

Автор: Любитель 12.1.2011, 18:23
Попробуй маршалинг как анси строки для начала.

Автор: jonie 12.1.2011, 19:59
Правильная сигнатура должна быть такой: (http://www.pinvoke.net/default.aspx/user32.sendmessage)
Код

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

там же примеры как маршалить автоматически

Автор: Любитель 12.1.2011, 20:54
Что значит "правильная"? wParam/lParam на практике интерпретируются по разному. В принципе - делать вызовы Marshal.XxxToXxx в коде или прописать нужные типы и пр. сразу - не суть важно.

Вопрос собственно в том, как интерпретируются параметры в приложении, принимающем сообщения.

Автор: erm0l0v 13.1.2011, 09:44
wparam по сути это ни что иное как ссылка на тип PCHAR. Именно к этому C# должен преобразовать string в конечном итоге, что он успешно делает при отправке сообщения WM_SETTEXT

Код

const int WM_SETTEXT = 0xC;

str = "New title\0";
IntPtr result = SendMessage(hWnd, WM_SETTEXT, null, str);


А при отправке сообщения WM_WINPOST_PRINTREPORT в WinPost (и есть та самая программа на Delphi) все вместо того текста который нужен отображается что то непонятное. Чаще всего пустое поле, или 2 - 3 символа. Причем отображает каждый раз разные символы при одинаковых начальных условиях. Такое впечатление что ссылка которая дошла в WinPost указывает куда угодно, но только не на мою строку.

Автор: Любитель 13.1.2011, 14:38
Цитата(erm0l0v @  13.1.2011,  09:44 Найти цитируемый пост)
wparam по сути это ни что иное как ссылка на тип PCHAR

Не. Вообще говоря это просто 32-битный параметр. Как он интерпретируется - другой вопрос smile

Попробуй всё-таки явно прописать маршаллинг как LPStr.

Автор: erm0l0v 13.1.2011, 17:01
Я сделал так:

Код

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SendMessage(IntPtr hWnd, int Msg, [MarshalAs(UnmanagedType.LPStr)] string wParam, [MarshalAs(UnmanagedType.LPStr)] string lParam);


лучше не стало, пробовал преобразовать так Marshal.StringToXxx тоже не получилось.

Может я просто не правильно использую Marshal?

Автор: Любитель 13.1.2011, 18:44
Хм. Тогда не знаю точно :(
А есть возможность выложить/прислать клинетское приложение?

Автор: erm0l0v 14.1.2011, 09:41
Вот мой код.

Код

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Runtime.InteropServices;

namespace WinTest
{

    public partial class MainForm : Form
    {
        [MarshalAs(UnmanagedType.LPStr)] string str;

        static IntPtr hWnd; 

        const int WM_CLOSE = 0x0010;

        const int WM_SETTEXT = 0xC;

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindow(string className, string windowTitle);
        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern int GetWindowText(int hWnd, StringBuilder lpString, int nMaxCount);
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern int RegisterWindowMessage(string lpString);

        [DllImport("User32.DLL", EntryPoint = "SendMessageA", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        static extern IntPtr SendMessage(IntPtr hWnd, int Msg, [MarshalAs(UnmanagedType.LPStr)] string wParam, IntPtr lParam);
        [DllImport("User32.DLL", EntryPoint = "SendMessageA", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPStr)] string lParam);
        [DllImport("User32.DLL", EntryPoint = "SendMessageA", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr SendMessage(IntPtr hWnd, int Msg, [MarshalAs(UnmanagedType.LPStr)] string wParam, [MarshalAs(UnmanagedType.LPStr)] string lParam);

        public static class MsgId
        {
            public static int ModHandle =    RegisterWindowMessage("WM_WINPOST_MODWNDHANDLE");
            public static int SQLFree =        RegisterWindowMessage("WM_WINPOST_SQLEXEC");
            public static int SetProp =        RegisterWindowMessage("WM_WINPOST_SETPROP");
            public static int GetProp =        RegisterWindowMessage("WM_WINPOST_GETPROP");
            public static int Detach =        RegisterWindowMessage("WM_WINPOST_DETACH");
            public static int Post =        RegisterWindowMessage("WM_WINPOST_POST");
            public static int WinPostOk =    RegisterWindowMessage("WM_WINPOST_OK");
            public static int PrintReport = RegisterWindowMessage("WM_WINPOST_PRINTREPORT");
        }

        

        public MainForm()
        {
            InitializeComponent();
            hWnd = FindWindow("TfmSession", null);
            textBoxHWND.Text = hWnd.ToString("x");
            while (textBoxHWND.Text.Length < 8)
            {
                textBoxHWND.Text = "0" + textBoxHWND.Text;
            }
            textBoxHWND.Text = "0x" + textBoxHWND.Text;

            IntPtr hMyWnd = this.Handle;

            textBoxMyHWND.Text = hMyWnd.ToString("x");

            while (textBoxMyHWND.Text.Length < 8)
            {
                textBoxMyHWND.Text = "0" + textBoxMyHWND.Text;
            }
            textBoxMyHWND.Text = "0x" + textBoxMyHWND.Text;

            IntPtr result = SendMessage(hWnd, MsgId.ModHandle, hMyWnd, IntPtr.Zero);

            if (result.ToInt64() == 1)
            {
                textBoxType.Text = "Услуги";
            }
            if (result.ToInt64() == 2)
            {
                textBoxType.Text = "Просмотр";
            }
        }

        

        private void button1_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void buttonPrintreport_Click(object sender, EventArgs e)
        {
            str = textBoxPrintreport.Text + '\0';

            IntPtr result = SendMessage(hWnd, MsgId.PrintReport, str, IntPtr.Zero);
            MessageBox.Show(result.ToString());
        }

        private void buttonCloseWinPost_Click(object sender, EventArgs e)
        {
            if (SendMessage(hWnd, WM_CLOSE, (string)null, null) == IntPtr.Zero)
            {
                textBoxHWND.Text = "0x00000000";
            }
        }

        private void buttonTitle_Click(object sender, EventArgs e)
        {
            str = textBoxTitle.Text + '\0';

            IntPtr result = SendMessage(hWnd, WM_SETTEXT, null, str);
            MessageBox.Show(result.ToString());
        }
    }
}



Он запускается из dll для WinPosta как процесс.

Сам WinPost 107 MB можно взять http://content6-n.files.mail.ru/GR572S/017e578d21750db0c33b2a719781f3a1?from=win.mail.ru

Программу можно протестировать так:

В WinPost: Новый Клиент -> Услуги -> Внешний Модуль -> Пример подключаемого модуля

После этого можно запустить программу, по идеи будет работать так же как если бы она была запущена из dll.

Во вложении я скинул свою программку, исходный код которой приведен выше.

Автор: erm0l0v 14.1.2011, 16:03
Все проблему решил.

Я переделал C# код в dll (правда очень корява, путём пере компилирования dll в il и обратно)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)