Heredes — библиотека для разработчиков


Heredes — библиотека для облегчения решения ряда конкретных задач, связанных с прямым обменом данных в сети без использования ipv6.


Из встроенных возможностей можно выделить:

  • облегченная установка соединения между двумя ПК не зависимо от того есть ли у них «белые» адреса или они за NAT;
  • гарантированная (с подтверждением) прямая передача файлов с одного ПК на другой;
  • реалтайм аудиосвязь между ПК за NAT;
  • реалтайм демонстрация экрана ПК за NAT;
  • проброс мыши и клавиатуры между ПК;
  • прямая передача произвольных пользовательских данных между ПК за NAT;
  • запись звука с удаленного ПК и сохранение скрина с удаленного монитора на локальной машине.

Тема пробоя NAT, на самом деле, не нова. Но она требует от разработчика определенных навыков, наличие STUN сервера, а лучше двух, и времени для реализации.
Heredes берет на себя вышеописанную часть, облегчая тем самым разработку приложений и позволяя сосредоточиться на задаче, будь-то прямой файлообмен, мессенджер или функционал удаленного администрирования, встроенный в Ваше приложение.


Скептики в целом могут возразить — зачем Heredes если есть WebRTC с крайне широкими возможностями.


Тем не менее, если звезды зажигают, значит это кому нибудь нужно.


Прежде всего Heredes не нацелен на межбраузерное взаимодействие и в этом его преимущество в десктопных приложениях. А именно — простота использования при написании «настольных» приложений, неприхотливость в вопросах ресурсов и да, мы постарались облегчить работу с тем, что не стандартизовано в WebRTC.


Разумеется, примеры реализации с помощью WebRTC найдутся и для нашего функционала (например, Screen Capture API реализует захват экрана частично или полностью) и может показаться что нет разницы, чье готовое решение использовать. Попробуйте, выберите наиболее удобное при разработке десктопного приложения решение именно для Вас.


Мы нацелены не на WEB — в приоритете именно десктоп и использование библиотеки в приложениях не требующих установки, экономичность в ресурсах и скорость выполнения задач.



Перейдем к краткому обзору?



Как писать с использованием Heredes

Часть 1. Прямая передача файлов за NAT это просто. Или 9 строк кода для передачи 8 эксабайт данных… или чуть более?


Рассмотрим как просто установить прямое соединение на примере вполне жизнеспособной задачи — передача фала между двумя ПК за NAT без использования облачных хранилищ, торрентов, файлообменных ресурсов, личных промежуточных серверов и других вспомогательных средств.


Ситуация вполне жизненная, кому из нас никогда не требовалось передать несколько эксабайт по сети? Задача даже при наличии промежуточного облачного хранилища еще та… ускорим ее в 2 раза, как минимум, за несколько минут...



Пример реализации на С++ ниже



//обмен файлами почти неограниченного размера между клиентами за NAT
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\WORK\\P2P\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\WORK\P2P\HEREDES\heredes.h>


int main(void)
{
	InitIONLibrary();	//инициализация библиотек и интерфейсов HEREDES
	DWORD Valid = 0;
	DWORD Id = 0;
	DWORD HightDword = 0;

	RegIONId(&Valid, &Id);	//регистрация нового пользователя
	//запуск асинхроннго сервера для ожидания входящих соединений
	HANDLE hConn = IONWaitConnection(&Valid, &Id, NULL); 

	//запуск синхронного интерфейса для передачи файла
	DWORD lowDword =IONSendFileToId(&Valid, &Id, NULL, &HightDword); 

	IONTerminate(hConn); //прерывание ожидания входящих соединений
	CloseIONHandle(hConn);
	return 0;
}

Не правда ли, очень лаконично вышло?


Есть явные недостатки, такие как:

  • Heredes не нацелен на установление прямого коннекта между двумя ПК из одной локальной сети;
  • могут возникнуть сложности в случае если оба ПК за симметричным NAT;
  • данный пример не предусматривает передачу нескольких файлов за раз.

Тем не менее есть и очевидный плюс — это вполне рабочий пример с функционалом применимым даже в виде «как есть из коробки». Как минимум удобно перекинуть на край света файл размером… в пределах 8 ЭБт, хотя я лично и не пробовал пробросить такой файл — попробуете Вы и расскажите чем закончилось ))…

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


Скачать пример

Часть 2. Простой UDP сервер и UDP клиент за NAT


Предположим наличие вполне жизненной ситуации — есть некий ПК, находящийся за NAT и мы хотим что б он периодически принимал входящие соединения из внешнего мира, а конкретно миром для него будет наш же UDP клиент. От слов к делу.


Пример реализации на С++ ниже


//UDP сервер, который в течении минуты слушает сеть и ожидает входящих соединений
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>

int main(void)
{
	InitIONLibrary();	//инициализация библиотек и интерфейсов HEREDES
	DWORD Valid = 0;
	DWORD Id = 0;
	DWORD HightDword = 0;

	RegIONId(&Valid, &Id);	//регистрация нового пользователя

	//запуск асинхроннго сервера для ожидания входящих соединений
	HANDLE hConn = IONWaitConnection(&Valid, &Id, NULL); 
	HANDLE hEv=CreateEventA(NULL,1,NULL,NULL);
	
	WaitForSingleObject(hEv,60000);
	CloseHandle(hEv);

	IONTerminate(hConn); //прерывание ожидания входящих соединений
	CloseIONHandlw(hConn); //прерывание ожидания входящих соединений
	
	return 0;
}

//простейший UDP клиент, который ничего не делает
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>

int main(void)
{
	InitIONLibrary();		//инициализация библиотек и интерфейсов HEREDES
	CHAR SecKey[8];		//8-ми байтный массив с ключем шифрования
	DWORD Valid = 0;
	DWORD Id = 0;
	HANDLE hConn;
	RegIONId(&Valid, &Id);	//регистрация нового пользователя
	
	
	hConn=CreateIONHandle();
		if (IONConnectToId(hConn, NULL, &Valid, &Id, &SecKey, NULL, NULL, NULL)==TRUE){
				MessageBoxA(NULL,"коннет установлен","состояние подключения", 48);
				HANDLE hEv=CreateEventA(NULL,1,NULL,NULL);
				WaitForSingleObject(hEv,60000);
				CloseHandle(hEv);

		}else{
				MessageBoxA(NULL,"ошибка соединения","состояние подключения", 48);
		};

	IONDisconnect(hConn); //прерывание ожидания входящих соединений
	CloseIONHandle(hConn); //прерывание ожидания входящих соединений
	return 0;
}

Данный пример очень бесполезен. Причина в том что такой сервер будет тихо реагировать на входящие соединения и обрабатывать все «по умолчанию», то есть игнорировать )), а клиент так же тихо удерживать соединение.

Часть 3. МФУ или клиент и сервер в одном лице


Бывает нужно, что бы приложение могло как реагировать на входящие, так и инициировать исходящие подключение. Такой подход кажется где то даже более универсальным. Напишем еще один бестолковый пример, но на этот раз толк от него будет — в дальнейшем этот код мы будем использовать как каркас, на который вешать всех собак.



//клиент-сервер over NAT
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>


int main(void)
{
	InitIONLibrary();			//инициализация библиотек и интерфейсов HEREDES

	CHAR SecKey[8];			//8-ми байтный массив с ключем шифрования
	DWORD Valid = 0;
	DWORD Id = 0;
	RegIONId(&Valid, &Id);		//регистрация нового пользователя


	HANDLE hCON_IN=IONWaitConnection(&Valid, &Id, NULL);
	HANDLE hCON_OUT=CreateIONHandle();


	if (IONConnectToId(hCON_OUT, NULL, &Valid, &Id, &SecKey, NULL, NULL, NULL==TRUE)){

				



		}else{
		MessageBoxA(NULL,"ошибка соединения","состояние подключения", 48);
		};

		IONTerminate(hCON_IN);
		IONDisconnect(hCON_OUT);
		CloseIONHandle(hCON_IN); 
		CloseIONHandle(hCON_OUT); 
	FreeConsole();
	return 0;
}

Часть 4. Простой консольный мессенджер за NAT


После примера бесполезного будет очень полезно написать что то наглядное. В предыдущих примерах и функция сервера IONWaitConnection и функция клиента IONConnectToId содержат параметр CBUserData установленный в NULL. тем не менее это не обязано быть так и должно так не быть если клиент-сервер обмениваются данными нестандартного формата. При передаче пользовательских данных это должна быть функция обработчик уведомления о пользовательских данных



//написать за NAT
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>

HANDLE hOutput;
CBUDATA __stdcall UserDataProc(HANDLE hConn, LPVOID pAddrUserData, int datSize)
{
	DWORD inSize;
	WriteConsoleA(hOutput,pAddrUserData, datSize, &inSize, NULL);
	return 0;
}

int main(void)
{
	InitIONLibrary();				//инициализация библиотек и интерфейсов HEREDES

	CHAR buffer[0x3E0];			//максимальный размер блока пользовательских данных 0х3Е0
	DWORD bSize=0;

	CHAR SecKey[8];			//8-ми байтный массив с ключем шифрования
	DWORD Valid = 0;
	DWORD Id = 0;
	RegIONId(&Valid, &Id);		//регистрация нового пользователя

	AllocConsole();
	HANDLE hInput=GetStdHandle(-10);
	hOutput=GetStdHandle(-11);


	HANDLE hCON_IN=IONWaitConnection(&Valid, &Id, (CBUDATA) &UserDataProc);
	HANDLE hCON_OUT=CreateIONHandle();


	if (IONConnectToId(hCON_OUT, NULL, &Valid, &Id, &SecKey, \
			NULL, NULL, (CBUDATA) &UserDataProc)==TRUE){


			while (bSize!=-1){
				ReadConsoleA(hInput,&buffer,0x3E0,&bSize,NULL);
				if (IONGetStatus(hCON_OUT)==6) {SendUserData(hCON_OUT,&buffer,bSize);};
				if (IONGetStatus(hCON_IN)==6) {SendUserData(hCON_IN,&buffer,bSize);};
						}
				
		}else{
				MessageBoxA(NULL,"ошибка соединения","состояние подключения", 48);
		};

		IONTerminate(hCON_IN);
		IONDisconnect(hCON_OUT);
		CloseIONHandle(hCON_IN); 
		CloseIONHandle(hCON_OUT); 
	FreeConsole();
	return 0;
}

Пусть интерфейс и неказист и прост, но это уже кое-что не оторванное от жизни.


Скачать пример

Часть 5. А поговорить? Попробуем реализовать простую звонику за NAT


Притянем за уши потребность — пусть нам нужно не много и не мало а позвонить другу в деревню за NAT.
Heredes реализует передачу PCM аудио почти так же просто как и пользовательские данные.


//поговорить за NAT
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>


int main(void)
{
	InitIONLibrary();			//инициализация библиотек и интерфейсов HEREDES

	CHAR SecKey[8];			//8-ми байтный массив с ключем шифрования
	DWORD Valid = 0;
	DWORD Id = 0;
	RegIONId(&Valid, &Id);		//регистрация нового пользователя


	HANDLE hCON_IN=IONWaitConnection(&Valid, &Id, NULL);
	HANDLE hCON_OUT=CreateIONHandle();

	
	IONSetAudioParam(hCON_OUT,3,"aud_in.wav","aud_sp.wav",NULL);
	IONSetAudioParam(hCON_IN,3,"aud_in.wav","aud_sp.wav",NULL);


		if (IONConnectToId(hCON_OUT, NULL, &Valid, &Id, &SecKey, NULL, NULL, NULL)==TRUE){

			IONStartAudioStream(hCON_OUT,11025);
			HANDLE hEv=CreateEventA(NULL,1,NULL,NULL);
			WaitForSingleObject(hEv,60000);
			CloseHandle(hEv);

				
		}else{
				MessageBoxA(NULL,"ошибка соединения","состояние подключения", 48);
		};
		IONStopAudioStream(hCON_IN);
		IONStopAudioStream(hCON_OUT);
		IONTerminate(hCON_IN);
		IONDisconnect(hCON_OUT);
		CloseIONHandle(hCON_IN); 
		CloseIONHandle(hCON_OUT); 
	return 0;
}

Скачать пример

Часть 6. От разговоров к администрированию или CMD over NAT


Еще один относительно быстро реализуемый пример это командная строка за NAT или удаленное перенаправление ввода/вывода. Приступим?



//CMD за NAT
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>

CHAR buffer[0x3E0];			//максимальный размер блока пользовательских данных 0х3Е0
HANDLE hOutput;
HANDLE outpipe;
HANDLE inpipe;
HANDLE hEv;
HANDLE hCON_IN;
HANDLE hCON_OUT;

CBUDATA __stdcall UserDataProc(HANDLE hConn, LPVOID pAddrUserData, int datSize)
{
	
	DWORD cRcv=1;
	if (IONGetStatus(hCON_IN)==6){
		SendCommandLine(outpipe,pAddrUserData);
		WaitForSingleObject(hEv,2000);
		
			while(cRcv!=0){
				PeekNamedPipe(inpipe,NULL,NULL,NULL,&cRcv,NULL);
				if (cRcv!=0){
					ReadFile(inpipe,&buffer,cRcv,&cRcv,NULL);
					}
				SendUserData(hCON_IN,&buffer,cRcv);
				}
	};

	if (IONGetStatus(hCON_OUT)==6){
				WriteConsoleA(hOutput,pAddrUserData,datSize,&cRcv,NULL);
			
	};



	DWORD inSize;
	WriteConsoleA(hOutput,pAddrUserData, datSize, &inSize, NULL);
	return 0;
}

int main(void)
{
	HANDLE hInCons;
	HANDLE hOutCons;
		
	hEv=CreateEventA(NULL,1,NULL,NULL);
	StartHiddenConsoleProcess("cmd.exe",&outpipe, &inpipe, &hOutCons, &hInCons);

	InitIONLibrary();			//инициализация библиотек и интерфейсов HEREDES

	DWORD bSize=0;

	CHAR SecKey[8];			//8-ми байтный массив с ключем шифрования
	DWORD Valid = 0;
	DWORD Id = 0;
	RegIONId(&Valid, &Id);		//регистрация нового пользователя



	hCON_IN=IONWaitConnection(&Valid, &Id, (CBUDATA) &UserDataProc);
	hCON_OUT=CreateIONHandle();


	if (IONConnectToId(hCON_OUT, NULL, &Valid, &Id, &SecKey, \
			NULL, NULL, (CBUDATA) &UserDataProc)==TRUE){

			
			AllocConsole();
			HANDLE hInput=GetStdHandle(-10);
			hOutput=GetStdHandle(-11);
			WriteConsoleA(hOutput,"REMOTE CMD >",12,&bSize,NULL);


			while (bSize!=-1){
				ReadConsoleA(hInput,&buffer,0x3E0,&bSize,NULL);
				SendUserData(hCON_OUT,&buffer,bSize);
						}
				
			FreeConsole();

		}else{
				MessageBoxA(NULL,"ошибка соединения","состояние подключения", 48);
		};

		IONTerminate(hCON_IN);
		IONDisconnect(hCON_OUT);
		CloseIONHandle(hCON_IN); 
		CloseIONHandle(hCON_OUT); 
	return 0;
}

Из новенького и интересненького здесь функции StartHiddenConsoleProcess и SendCommandLine. Для деталей смотрите документацию (ссылки внизу).


Скачать пример

Часть 7. Займемся фотографией. Сфоткаем часть экрана удаленного рабочего стола


Вот мы и приблизились к названию библиотеки и, собственно, к чему все шло до этого. Удаленный рабочий стол без головы. Все слышали про безголовые хромы, проекты вроде селениум, но в памяти не всплывает всадник безголовы — Бил в виде Windows отрисованный на виртуальном DC.


Библиотека так же содержит функционал имитации действий мышей и клавиатур на удаленном ПК, но в данном примере мы ограничимся отрисовкой на виртуальном DC рабочего стола удаленной машины. После чего сохраним содержимое DC в BMP-файл.

Со времени выхода первой статьи кое-что изменилось. Теперь мы все же заморачиваемся с указанием не только координат и размера пробрасываемого прямоугольника, но и указанием DC с которого мы срисовываем. Опустив ностальгические размышления о том, как мы докатились до обезглавливания Windows перейдем к делу.



//безголовый скрин
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>


int main(void)
{
	InitIONLibrary();			//инициализация библиотек и интерфейсов HEREDES

	CHAR SecKey[8];			//8-ми байтный массив с ключем шифрования
	DWORD Valid = 0;
	DWORD Id = 0;
	RegIONId(&Valid, &Id);		//регистрация нового пользователя

	HDC hCDC;
	HDC hDC=GetDC(NULL);
	HANDLE hCON_IN=IONWaitConnection(&Valid, &Id, NULL);
	HANDLE hCON_OUT=CreateIONHandle();
	SetINVISTParam(hCON_IN,hDC,64, 64, 256, 256,NULL);//установим параметры прямоугольника 
																		//разрешенного для отправки по сети


	if (IONConnectToId(hCON_OUT, NULL, &Valid, &Id, &SecKey, NULL, NULL, NULL)==TRUE)
		{
			hCDC=CreateCompatibleDC(hDC);
			StartRemoteINVIST(hCON_OUT,hCDC,512, 512, 1);	//размеры изображения 
										//я решил увеличить, 
																		//но можно было оставить и оригинальные или напротив уменьшить
			
	for (int i=0; i<3; i++){GetRemoteINVISTService(hCON_OUT);};	//получаю видео из 3х кадра 
										//из за специфики кодека
			int sB=SaveINVISTtoBPM(hCON_OUT,"screen.bmp");


		}else{
		MessageBoxA(NULL,"ошибка соединения","состояние подключения", 48);
		};
		DeleteDC(hCDC);
		IONTerminate(hCON_IN);
		IONDisconnect(hCON_OUT);
		CloseIONHandle(hCON_IN); 
		CloseIONHandle(hCON_OUT); 

	return 0;
}

В данном примере я получил несколько кадров для будущего битмепа. Вы можете получить 1,2 и сделать выводы из того что выйдет — лучше один раз пощупать чем 10 раз посмотреть.


Скачать пример

Часть 8. И в заключение статьи — напишем свой маленький TeamViewer.


Графические приложения для удаленного управления Windows посредством еще более графического интерфейса — прочно засели в быту. Попробуем реализовать этот функционал в нашем маленьком приложении RDP over NAT


//свой маленький TeamViewer
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>

HANDLE hEv;
WNDPROC __stdcall ProcClose(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){

	SetEvent(hEv);

	return 0;
}

int main(void)
{
	hEv=CreateEventA(NULL,1,NULL,NULL);
	InitIONLibrary();			//инициализация библиотек и интерфейсов HEREDES

	CHAR SecKey[8];			//8-ми байтный массив с ключем шифрования
	DWORD Valid = 0;
	DWORD Id = 0;
	RegIONId(&Valid, &Id);		//регистрация нового пользователя

	HDC hCDC;
	HDC hDC=GetDC(NULL);
	HANDLE hCON_IN=IONWaitConnection(&Valid, &Id, NULL);
	HANDLE hCON_OUT=CreateIONHandle();
	SetINVISTParam(hCON_IN,hDC,64, 64, GetSystemMetrics(0), GetSystemMetrics(1),NULL);					//установим параметры прямоугольника 
									
	if (IONConnectToId(hCON_OUT, NULL, &Valid, &Id, &SecKey, NULL, NULL, NULL)==TRUE)
		{
	hCDC=CreateCompatibleDC(hDC);
	StartRemoteINVIST(hCON_OUT,hCDC,512, 512, 1);	//размеры изображения я решил увеличить, 
																		//но можно было оставить и оригинальные или напротив уменьшить
			HWND hWin;
			CreateINPRT(hCON_OUT, 64, 32, 512, 300, 0x00CF0000, NULL, &hWin, 1, (WNDPROC) ProcClose);

			WaitForSingleObject(hEv,-1);

		}else{
		MessageBoxA(NULL,"ошибка соединения","состояние подключения", 48);
		};
		
		CloseHandle(hEv);
		IONTerminate(hCON_IN);
		IONDisconnect(hCON_OUT);
		CloseIONHandle(hCON_IN); 
		CloseIONHandle(hCON_OUT); 

	return 0;
}

Скачать пример

В данном случае мы познакомились с функцией CreateINPRT — это по сути встроенный интерактивный плейер реального времени. Этот же пример можно было реализовать посредством отрисовки на DC какого либо окна и использовать функции передачи мыши и клавиатуры библиотеки Heredes, но так, по моему, даже удобнее.



Ссылки: на проект, скачать архив, документация.

Комментарии (14)


  1. netricks
    30.08.2021 23:44

    А как это работает внутри? Как heredes конектится к машине за NAT?


    1. Brodilla Автор
      31.08.2021 00:09

      Старый добрый stun.

      Каждый пользователь имеет свой идентификатор, получить который можно вызовом RegIONId.

      Приложение, которое вызывает WaitIONConnection регулярно уведомляет stun-сервер о том, что ожидает подключений, указывая свой идентификатор.

      Вызов IONConnectToId инициирует появление окна, в котором можно ввести идентификатор сервера.

      Далее клиент запрашивает stun: "а где ж сидит сервер с таким ID?" Серверу и клиенту в ответ на такой запрос клиента отправляются данные для прямого подключения.

      Для удобства не рекомендуется вызывать RegIONId каждый раз, а получив идентификатор сохранить его. Тогда не придется гадать какой Id у клиента и у сервера, а просто его в дальнейшем использовать.

      Пример 2 наглядно демонстрирует различия между кодом клиента и кодом сервера. А в примере 3 - возможный, но не обязательный каркас (клиент и сервер в одном приложении). Все остальные примеры используют именно этот каркас в основе.

      Обратите внимание, что мы не участвуем в дальнейшей передаче данных - все идет р2р, мы просто соединяем. А в случае невозможности прямого обмена данными функция IONConnectToId вернет 0 и на этом все закончится.


  1. MGSpace
    31.08.2021 08:29

    В примере 6 используется функция StartHiddenConsoleProcess . исходя из того что она вызывается до установки коннекта, есть подозрения что это запуск консоли локально. Это так? если да, то есть ли удаленный вариант запуска консоли? в документации не нашел. спасибо.


    1. Brodilla Автор
      31.08.2021 08:49

      Да, на данный момент процесс запускается по ряду причин только локально, более того, данная функция ориентирована именно на консольные приложения и перенаправление ввода/вывода консоли. Хуже того - несмотря на то что консольное приложение запускается локально, его завершение работы управляется только удаленно.

      Когда библиотека перейдет из бетты в версию, мы скорее всего еще раз пересмотрим работу с консольными приложениями запущенными в фоновом режиме. На данный момент не до конца понятно общественное мнение и предпочтительное направление развития.


  1. Kotofay
    31.08.2021 13:59

    Пример собранный с вашей библиотекой валится с исключением в IONConnectToId.


    1. MGSpace
      31.08.2021 16:00

      у меня тоже была такая проблема. потом разобрался.

      IONConnectToId(hCON_OUT, NULL, &Valid, &Id, &SecKey, NULL, NULL, NULL)

      все кроме hCON_OUT - указатели на переменные. при том SecKey это указатель на 8 байтный массив. я пробовал поставить вместо него NULL - валится, вместо других указателей на переменные ставить переменные - тоже валится.

      а в остальном, у меня заработало


      1. MGSpace
        31.08.2021 16:07

        хотя в документации у авторов расхождение с примерами - пришел импирическим путем рассматривая примеры. будем надеяться исправят доки


      1. Brodilla Автор
        31.08.2021 16:32

        Спасибо за ваш ответ.


        1. Kotofay
          31.08.2021 17:12

          В указанном примере внутри IONConnectToId первый же вызов CreateThread некорректный -- третий параметр lpStartAddress равен нулю.

          push ebx ; lpThreadId

          push ebx ; dwCreationFlags

          push edi ; lpParameter

          mov eax, dword_100070BD

          push dword ptr [eax] ; lpStartAddress

          push ebx ; dwStackSize

          push ebx ; lpThreadAttributes

          call ds:CreateThread


          1. Brodilla Автор
            31.08.2021 21:42

            Heredes состоит из двух DLL. Предполагалось, что один будет заведовать графическим интерфейсом, а другой функционалом без GUI. На данный момент это не так и использование отдельно heredes.dll невозможно. Ваша ошибка относится к случаю, когда не удалось зарегистрировать необходимые классы окон или загрузить gui_her.dll. Проследите что бы он был так же в каталоге с программой.


            1. Kotofay
              01.09.2021 00:14

              Да, всё заработало. NAT действительно пробивается.

              Нужно работать над API библиотеки, то что есть сейчас совершенно не годится.


              1. Brodilla Автор
                01.09.2021 00:36

                Спасибо за тест.

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


    1. Brodilla Автор
      31.08.2021 16:21

      Спасибо!

      Да, в документации была допущена неточность.

      Исправлена. https://brodilla.com/ru/heredes/about#IONConnectToId

      Будем признательны за любые указания на наши недостатки.


      1. MGSpace
        31.08.2021 16:36

        было б удобна не только отправка файла а загрузка инициированная клиентом. содержимое каталога то консоль показывает и как то можно в фрновом режиме дерево каталогов составлять, хотя и не удобно..

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

        возьмите пожалуйста на карандаш/на голосование или как там учитываются пожелания