Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.82/11: Рейтинг темы: голосов - 11, средняя оценка - 4.82
0 / 0 / 0
Регистрация: 27.11.2011
Сообщений: 18
1

GetMailslotInfo завершается с ошибкой

27.12.2011, 07:47. Просмотров 2234. Ответов 17
Метки нет (Все метки)

Здравствуйте! Продолжаю осваивать работу с почтовыми ящиками в Windows. Не знаю, может быть стоило выбрать именованный канал для передачи сообщений между процессами, но хотелось бы довести тему с ящиками до конца. Короче говоря, создаю я ящик API функцией CreateMailslot, и пытаюсь получить информацию о нем с помощью GetMailslotInfo. В результате Marshal.GetLastWin32Error возвращает ошибку 6. Код CreateMailslot и GetMailslotInfo, соответственно. Кто может, объясните, пожалуйста, что делаю не так.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using System;
using System.Runtime.InteropServices;
 
namespace createms
{
    class Program
    {
        //Создание почтового ящика процессом-сервером.
        [DllImport("kernel32.dll",SetLastError=true)]
        static extern IntPtr CreateMailslot(
            string lpName,         //имя почтового ящика.
            uint nMaxMessageSize,  //максимальная длина сообщения.
            uint lReadTimeout,     //интервал ожидания.
            IntPtr lpSecurityAttributes);  //атрибуты безопасности.
 
 
        static void Main()
        {
            //Создаю почтовый ящик.
            IntPtr d;
            d=CreateMailslot (
                "\\\\.\\mailslot\\mymail", //имя почтового ящика.
                0,                       //длина сообщения произвольна.
                0,
                IntPtr.Zero
                );
            Console.WriteLine(d);
            if (Marshal.GetLastWin32Error() != 0)
            {
                Console.WriteLine("Почтовый ящик не создан" + Marshal.GetLastWin32Error());
            }
            else
            {
                Console.WriteLine("Почтовый ящик создан");
            }
            Console.ReadKey();
        }
    }
}
и
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using System;
using System.Runtime.InteropServices;
 
namespace GetInfo
{
    class Program
    {
        [DllImport("KERNEL32.DLL",SetLastError=true)]
        static extern bool GetMailslotInfo(
               IntPtr hMailslot,      // дескриптор почтового ящика
               int lpMaxMessageSize,  // максимальная длина сообщения
               ref int lpNextSize,    // длина следующего сообщения
               IntPtr lpMessageCount, // количество сообщений
               IntPtr lpReadTimeout   // интервал ожидания сообщения
            );
        static void Main()
        {
            IntPtr hMailslot;
            int x;
            x = int.Parse(Console.ReadLine()); //сюда ввожу дескриптор ящика, полученный в предыдущем коде.
            hMailslot = (IntPtr)x;
            int lpMaxMessageSize;
            int lpNextSize;
            IntPtr lpMessageCount;
            IntPtr lpReadTimeout;
 
            lpMaxMessageSize = 0;
            lpNextSize = 0;
            lpMessageCount = (IntPtr)0;
            lpReadTimeout = (IntPtr)0;
 
            GetMailslotInfo(
                hMailslot,
                lpMaxMessageSize,
                ref lpNextSize,
                lpMessageCount,
                lpReadTimeout
                );
            if (Marshal.GetLastWin32Error()!=0)
            {
                Console.WriteLine("Ошибка " + Marshal.GetLastWin32Error());
            }
            else 
            {
                Console.WriteLine("Информация полученна");
            }
            Console.ReadKey();
        }
    }
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
27.12.2011, 07:47
Ответы с готовыми решениями:

Импорт данных из Excel-файла завершается с ошибкой
Пишу вот: public void GetDataTableExcel(string fileName) { ...

Авторизация через twitter api завершается с ошибкой 403
Не могу авторизоваться в твиттере Uri uri = new...

Выборка из БД по ID завершается с ошибкой
Появилась след проблема: есть таблица в БД назовем ее USER, в неи первичный ключ - CODE(varchar)....

Поиск файлов в системных директориях завершается с ошибкой доступа
Здравствуйте. Есть некоторая задача: просканировать некоторую область на диске и затем выполнить...

17
Почетный модератор
Эксперт .NET
8672 / 3624 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9
27.12.2011, 10:23 2
Цитата Сообщение от MSDN, GetMailslotInfo
hMailslot [in]
A handle to a mailslot. The CreateMailslot function must create this handle.
Нельзя передавать дескрипторы между процессами просто как число - это ссылки на объекты, в одном процессе объект существует в другом нет, потому и ошибка.

Читайте MSDN, там всё подробно расписано:
http://msdn.microsoft.com/en-u... S.85).aspx
http://msdn.microsoft.com/en-u... S.85).aspx
http://msdn.microsoft.com/en-u... S.85).aspx

p.s. И у Вас неверно составлен прототип GetMailslotInfo, все LPDWORD нужно заменить на out uint или out int.
1
0 / 0 / 0
Регистрация: 27.11.2011
Сообщений: 18
27.12.2011, 13:44  [ТС] 3
Спасибо. Что есть прототип? Описание функций брал с http://www.pinvoke.net/. Если нельзя передавать как число, значит нужен указатель или лучше использовать IntPtr? Посмотрю на mdsn, да вот только с английским не очень.

Добавлено через 37 минут
Возникает вопрос: а как тогда передать дескриптор между процессами? Опять же нужно какое-то средство передачи сообщений.

Добавлено через 4 минуты
А может быть воспользоваться разделяемой памятью? В C# даже есть пространство имен System.IO.MemoryMappedFiles для этого.
0
Почетный модератор
Эксперт .NET
8672 / 3624 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9
27.12.2011, 13:54 4
nikWnik, значение полученное от CreateMailsot (дескриптор) нельзя просто передавать между процессами, оно действительно только для процесса вызвавшего CreateMailslot. Для передачи нужно использовать механизм наследования от родительского процесса.

Принцип работы Mailslots (перевод с MSDN):
Only the process that creates a mailslot or has obtained the handle by some other mechanism (such as inheritance) can read from the mailslot.
Только процесс создавший mailslot или получивший его дескриптор каким-нибудь способом, типа наследования, может читать данные с mailslot.
A mailslot client is a process that writes a message to a mailslot. Any process that has the name of a mailslot can put a message there.
mailslot клиент - это процесс, который пишет данные в mailslot. Любой процесс который имеет имя mailslot может помещать (писать) в него сообщения.
Т.е. принцип таков: сервер - читатель, клиенты - писатели.

2 другие ссылки показывают примеры общения клиентов с сервером.

Прототип - это описание сигнатуры функции (имя, параметры).
C#
1
2
3
[DllImport("...", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetMailslotInfo(IntPtr ..., out uint ..., out uint ..., out uint ..., out uint ...);
Вместо ... подставьте названия.

p.s. Я б кодом помог, да нет сейчас такой возможности...

Add:

Не надо Вам никуда передавать полученный от CreateMailslot дескриптор, открывайте уже существующий с помощью CreateFile (прочитайте 2 последние ссылки).
0
0 / 0 / 0
Регистрация: 27.11.2011
Сообщений: 18
27.12.2011, 14:01  [ТС] 5
Насчет кода спасибо. А вот можно ли использовать разделяемую память (пространство имен System.IO.MemoryMappedFiles) для передачи дескриптора или для передачи сообщений?
0
Почетный модератор
Эксперт .NET
8672 / 3624 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9
27.12.2011, 14:07 6
Цитата Сообщение от nikWnik Посмотреть сообщение
А вот можно ли использовать разделяемую память (пространство имен System.IO.MemoryMappedFiles) для передачи дескриптора или для передачи сообщений?
Для сообщений можно, для передачи дескриптора - нет смысла. Прочитайте на MSDN что такое HANDLE (со стороны ОС), иначе Вы не представляете с чем работаете.
1
0 / 0 / 0
Регистрация: 27.11.2011
Сообщений: 18
27.12.2011, 14:53  [ТС] 7
Вообщем, посмотрел код по ссылкам, так вроде бы понятно, но вот как handle передается-нет. Вы говорили про "наследование", а если, к примеру, процесс, где создается почтовый ящик и тот где происходит чтение ни как не связаны между собой, т.е один не является для другого родительским, то получается handle не передашь? .Дескриптор это и есть handle?
0
Почетный модератор
Эксперт .NET
8672 / 3624 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9
27.12.2011, 17:40 8
nikWnik, не надо Вам никуда передавать дескриптор (он же HANDLE), не надо. Это нарушает принцип mailslot.
Вам нужно:
1) Создать сервер с помощью CreateMailslot;
2) Подключаться клиентами к серверу, вызывая CreateFile("\\\\\.\\mailslot\\your_mail", ...);
3) Далее, используя межпроцессорную синхронизацию (события, к примеру), общаться с сервером. Клиент пишет с помощью WinAPI WriteFile или FileStream, далее переключает событие (чтобы сообщить серверу что произошла запись), далее сервер читает с помощью WinAPI ReadFile или опять же FileStream. Сервер всё прочитав возвращает событие в исходное состояние. Всё.

Если же Вам хочется нарушать принцип, то копируете дескриптор в процессе клиента вызывая DuplicateHandle. В этом случае Вам надо получить значение дескриптора (то как Вы это пытаетесь делать в первом сообщении, к примеру) и это значение предоставить DuplicateHandle (более подробно в MSDN). В случае успешного копирования, Ваш клиент превратится по своим возможностям в сервера. Далее скопированный дескриптор используете в GetMailslotInfo.
0
0 / 0 / 0
Регистрация: 27.11.2011
Сообщений: 18
27.12.2011, 18:22  [ТС] 9
Спасибо Вам большое за помощь. Не понятен такой момент.CreateFile использует для своей работы имя почтового ящика, но ведь WriteFile использует как раз handle. В примере по ссылкам он называется hSlot и в него записывает значение CreateMailslot. Потом его использует WriteFile, и это, я так понимаю, уже другой процесс. Так вот, как попадает handle созданный в одном процессе (CreateMailslot) в другой (WriteFile)?
0
Почетный модератор
Эксперт .NET
8672 / 3624 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9
27.12.2011, 18:41 10
nikWnik, WriteFile использует handle полученный от CreateFile, просмотрите примеры внимательней (link). То что handle от CreateFile и от CreateMailslot одного типа (в Win32), не должно Вам говорить что это одно и тоже, это ссылки на разные объекты ОС.

p.s. Да, Вы правильно поняли что эти примеры относятся к разным приложениям, т.е. это отдельные EXE.
Так вот, как попадает handle созданный в одном процессе (CreateMailslot) в другой (WriteFile)?
handle полученный CreateMailslot является ссылкой на глобальный объект (в ОС), а CreateFile просто как-бы подключается к этому объекту, но не является его копией.
0
0 / 0 / 0
Регистрация: 27.11.2011
Сообщений: 18
27.12.2011, 18:53  [ТС] 11
Да, я не заметил. Таким образом, сейчас надо разобраться как работать в C# с handle? Или его использование остается в рамках API? И вот еще такая мысль: не лучшим ли вариантом будет реализовать работу с почтовыми ящиками как библиотеку целиком на C, а уже ее одну вызывать в проекте на C#, вместо вызова кучи API-функций в нем?
0
Почетный модератор
Эксперт .NET
8672 / 3624 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9
27.12.2011, 19:04 12
Таким образом, сейчас надо разобраться как работать в C# с handle?
Также как и с HANDLE в C, только в шарпе VOID* это IntPtr (managed object) или тот же void* (unsafe object).
Или его использование остается в рамках API?
Не понял вопроса, возможно ответил на него чуть выше...
не лучшим ли вариантом будет реализовать работу с почтовыми ящиками как библиотеку целиком на C, а уже ее одну вызывать в проекте на C#, вместо вызова кучи API-функций в нем?
Как Вам удобней так и делайте
0
0 / 0 / 0
Регистрация: 27.11.2011
Сообщений: 18
27.12.2011, 19:19  [ТС] 13
Цитата Сообщение от SSTREGG Посмотреть сообщение
Также как и с HANDLE в C, только в шарпе VOID* это IntPtr (managed object) или тот же void* (unsafe object).
Т.е. IntPtr hSlot или void* hSlot?
0
Почетный модератор
Эксперт .NET
8672 / 3624 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9
27.12.2011, 19:28 14
nikWnik, да, только во втором случае нужно включить возможность использования Unsafe в свойствах проекта (Properties - Build - Allow unsafe code). Опять таки, кому как удобно, кто-то работает с указателями напрямую, а кто-то использует обертку в виде IntPtr.
1
0 / 0 / 0
Регистрация: 27.11.2011
Сообщений: 18
27.12.2011, 19:36  [ТС] 15
Да, или компилировать с параметром /unsafe. Спасибо огромное за помощь, Вы мне очень помогли. У Вас отличный форум. Теперь сам попытаюсь сделать. Как получиться/не получиться напишу.
0
0 / 0 / 0
Регистрация: 27.11.2011
Сообщений: 18
05.01.2012, 02:45  [ТС] 16
SSTREGG, здравствуйте, я продолжаю тему. Более или менее разобрался с примерами c MSDN. Пытаюсь реализовать все это на C#. Сейчас проблема в следующем, и она опять с GetMailslotInfo:параметры lpNextSize и lpMessageCount возвращают -1 и 0, несмотря на то, что сообщение я записываю. Пробовал запускать сервер на Си, из примера с MSDN, а писать своей программой на C#. В этом случае все работает, длину сообщения я получаю. Еще не знаю чем заменить MAILSLOT_WAIT_FOREVER, может быть как все из-за этого. Хотя я пробовал устанавливать очень большие значения интервала ожидания, но это не чего не меняло. Вот сам код:
Сервер:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
using System;
using System.Threading;
using System.Runtime.InteropServices;
 
namespace createms
{
    class Program
    {
        //Создание почтового ящика процессом-сервером.
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr CreateMailslot(
            string lpName,         //имя почтового ящика.
            uint nMaxMessageSize,  //максимальная длина сообщения.
            uint lReadTimeout,     //интервал ожидания.
            IntPtr lpSecurityAttributes ////атрибуты безопасности.
            );
 
        [DllImport("kernel32.dll")]
        static extern bool GetMailslotInfo(IntPtr hMailslot,
            out int lpMaxMessageSize,
            out int lpNextSize,
            out int lpMessageCount,
            out int lpReadTimeout);
 
 
        static void Main()
        {
            IntPtr hSlot;
            int lpMaxMessageSize; //для GetMailslotInfo.
            int lpNextSize;
            int lpMessageCount;
            int lpReadTimeout;
            bool fResult;
 
            //Создаю почтовый ящик.
            hSlot = CreateMailslot(
                "\\\\.\\mailslot\\mymail", //имя почтового ящика.
                0,                       //длина сообщения произвольна.
                500,
                IntPtr.Zero
                );
 
            if (Marshal.GetLastWin32Error() != 0)
            {
                Console.WriteLine("Почтовый ящик не создан" + Marshal.GetLastWin32Error());
            }
            else
            {
                Console.WriteLine("Почтовый ящик создан");
            }
 
            fResult = GetMailslotInfo(hSlot, //получаю информацию о почтовом ящике.
                out lpMaxMessageSize, 
                out lpNextSize, 
                out lpMessageCount, 
                out lpReadTimeout); 
 
            if (!fResult) { Console.WriteLine("Failed"); }
            else { Console.WriteLine("Ok"); }
 
            for (int i = 0; i < 20; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine("{0} {1}", lpNextSize, lpMessageCount);
            }
 
            Console.ReadKey();
        }
    }
}
Запись сообщения:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
using System;
using System.IO;
using System.Threading;
using System.Runtime.InteropServices;
 
namespace ConsoleApplication1
{
    
    class Program
    {
        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern IntPtr CreateFile(
           string fileName,
           [MarshalAs(UnmanagedType.U4)] FileAccess fileAccess,
           [MarshalAs(UnmanagedType.U4)] FileShare fileShare,
           IntPtr securityAttributes,
           [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
           int flags,
           IntPtr template);
 
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool WriteFile(
            IntPtr hFile,
            byte[] lpBuffer,
            uint nNumberOfBytesToWrite,
            out uint lpNumberOfBytesWritten,
            [In] ref System.Threading.NativeOverlapped lpOverlapped);
 
        static void Main()
        {
            IntPtr hFile;
            bool flag;
            byte[] marray={1,2,3,4,5};
            uint lpNumberOfBytesWritten;
            lpNumberOfBytesWritten = 0;
            NativeOverlapped stnOverlap = new NativeOverlapped();
            flag = false;
 
            hFile=CreateFile(
                "\\\\.\\mailslot\\mymail", 
                FileAccess.Write, 
                FileShare.Read, 
                IntPtr.Zero, 
                FileMode.Open, 
                0,
                IntPtr.Zero
                );
            if (Marshal.GetLastWin32Error() != 0)
            {
                Console.WriteLine("Файл не создан." + Marshal.GetLastWin32Error());
            }
            else
            {
                Console.WriteLine("Файл создан.");
            }
 
            for (int i = 0; i < 5; i++)
            {
                flag = WriteFile(
                    hFile,
                    marray,
                    (uint)marray.Length,
                    out lpNumberOfBytesWritten,
                    ref stnOverlap
                    );
            }
            Console.WriteLine(lpNumberOfBytesWritten);
            Console.WriteLine(flag);
            Console.ReadKey();
        }
    }
}
Так что, если не сложно, помогите пожалуйста разобраться.
0
Почетный модератор
Эксперт .NET
8672 / 3624 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9
05.01.2012, 18:21 17
В архиве пример клиента и сервера.
Запускаете сервер, задаете имя, далее сервер будет ждать ответа от клиентов.
Запускаете клиентов, задаете имя сервера, пишите сообщения, сервер будет их обрабатывать.
1
Вложения
Тип файла: rar Mailslots.rar (13.2 Кб, 5427 просмотров)
0 / 0 / 0
Регистрация: 27.11.2011
Сообщений: 18
05.01.2012, 21:53  [ТС] 18
Спасибо! Все работает!
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
05.01.2012, 21:53

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

GET запрос на сайт (https) завершается с ошибкой "запрещено"
Всем привет! Я бы хотел написать простенькую утилиту для проверки баланса моего аккаунта (интернет...

Подключение к базе данных и вывод данных в DataGridView завершается с ошибкой
Подскажите что не так с кодом выкидывает разные ошибки Сейчас пишет:Error: .Net SqlClient Data...

Программа завершается с ошибкой
#include &lt;stdio.h&gt; #include &lt;conio.h&gt; #include &lt;stdlib.h&gt; const int size = 20; const int...

Запуск джоба завершается с ошибкой
Всем привет! Сегодня столкнулся с ситуёвиной - при инициализации пакета выполняется запрос,...

Программа завершается с ошибкой Killed
Программа завершается с ошибкой Killed, когда я выделяю очень много динамической памяти, но меньше...

Собранное приложение завершается с ошибкой
Здравствуйте. Подскажите пожалуйста новичку. Взял приложение из учебника, переписал в Visual...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.