nedoPC.org

Electronics hobbyists community established in 2002
Atom Feed | View unanswered posts | View active topics It is currently 28 Mar 2024 14:22



Reply to topic  [ 28 posts ]  Go to page Previous  1, 2
Перегруженные функции в C++ 
Author Message
Supreme God
User avatar

Joined: 21 Oct 2009 08:08
Posts: 7777
Location: Россия
Reply with quote
Shaos wrote:
так тебе только адрес передать через файл, а потом все через этот адрес перекидывать

А где я его буду хранить в dll-ке между вызовами? :roll: Она ж "кучу" создает и сама её и "рассыпает" потом...

_________________
iLavr


19 Jan 2018 21:35
Profile
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22412
Location: Silicon Valley
Reply with quote
а у тебя DLL-ка только в момент обращения к порту создается чтоль? и дисплей твой то потухнет, то погаснет? ;)

_________________
:dj: https://mastodon.social/@Shaos


19 Jan 2018 21:54
Profile WWW
Supreme God
User avatar

Joined: 21 Oct 2009 08:08
Posts: 7777
Location: Россия
Reply with quote
Мне кажется, что вызов экспортирумой ф-ции DLL - не в потоке окна, созданного DLL-кой.
Он в потоке ехе-файла, который эту DLL-ку вызвал, поэтому переменные окна недоступны
вызываемой из DLL ф-ции.

_________________
iLavr


19 Jan 2018 22:06
Profile
Supreme God
User avatar

Joined: 21 Oct 2009 08:08
Posts: 7777
Location: Россия
Reply with quote
Lavr wrote:
Есть какие-то специальные области памяти для межпотокового общения.
Давно читал я и не понял и забыл... :roll:

Вот здесь, как мне кажется, излагают эту бадью про "общую область":
Quote:
Article #20132: How to create a shared segment in a dll.
Question:
How do I build a dll that contains a shared data segment? Books I've been reading mention the #pragma data_seg() directive, but this doesn't seem to be supported by Builder.

Answer:
Builder 4 does not support the #pragma data_seg() directive, but there are compiler switches that will, along with the proper .def file, allow you to do this.

You will have to put the data you want shared in it's own source file and use the -zR and -zT compiler switches. These switches change the data segment name and class name for whatever source file they are used in. You will have to initialize the data you want to share, as uninitialized data is automatically moved to the default data segment. You must also create a .def file for your dll that tells the linker to give that segment the shared property.

Example:
There are four files in this example:


Code:
dll.h // foreward declarations for the dll
dllmain.cpp // the CPP file that contains the dll entrypoint
dllshared.cpp // contains the shared data
dlldef.def // module definition file for the dll

#pragma hdrstop
#include
#define __dll__
#include "dll.h"

#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
\{
       return 1;
\}

extern int SharedInteger;

int GetInteger(void)
\{
return SharedInteger;
\}

void SetInteger(int arg)
\{
SharedInteger = arg;
\}
//---- end file dllmain.cpp ----//

//---- begin file dllshared.cpp ----//
#pragma option -zRSHARESEG // sets segment name for this source file to SHARESEG
#pragma option -zTSHARECLS // sets class name for segment to SHARECLS

int SharedInteger = 0;
//---- end file dllshared.cpp ----//


//---- begin file dlldef.def ----//
LIBRARY DLLMAIN

SEGMENTS
SHARESEG CLASS "SHARECLS" SHARED
//---- end file dlldef.def ----//

//---- Last Modified: 10-MAY-00

Честно говоря, опять нифига не понял... :-?

_________________
iLavr


20 Jan 2018 17:55
Profile
Supreme God
User avatar

Joined: 21 Oct 2009 08:08
Posts: 7777
Location: Россия
Reply with quote
И вот здесь ещё излагают похожую историю: Разделяемая память в DLL
Quote:
В Win32 библиотека DLL располагается в области памяти загружающего ее процесса. Каждому процессу предоставляется отдельная копия “глобальной” памяти DLL ( т.е делается отдельная копия всех глобальных переменных, объявленных в исходном коде этой DLL), которая реининиализируется каждый раз, когда новой процесс загружает библиотеку. Это означает, что в Win32 динамическая библиотека, вернее, ее глобальные переменные, не могут использоваться процессами совместно.
И все же, выполнив ряд замысловатых манипуляций над сегментом данных DLL, можно создать общую область памяти для всех процессов, использующих данную библиотеку.

Допустим, имеется массив целых чисел, который должен использоваться всеми процессами, загружающими некоторую библиотеку DLL. Это можно запрограммировать в коде библиотеки следующим образом:
Code:
#pragma data_seg (“.MySeg”)
int sharedInts[5]={0,0,0,0,0}; // переменная общего пользования
... ... ... // другие переменные общего пользования
#pragma data_seg ()

#pragma comment (lib, ”msvcrt” “-SECTION: .MySeg, rws”);

Все инициализированные переменные, объявленные между директивами #pragma data_seg (), размещаются в сегменте .MySeg. Важно специально инициализировать эти переменные, в противном случае компилятор помещает эти переменные вместо области памяти .MySeg в обычную неинициализируемую область.

· Директива #pragma comment () – не обычный комментарий. Она дает указание библиотеке времени выполнения системы C пометить новый раздел как разрешенный для чтения, записи и совместного доступа (rws).

_________________
iLavr


20 Jan 2018 18:11
Profile
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22412
Location: Silicon Valley
Reply with quote
Ну тут по видимому оно должно с обеих сторон быть поддержано, а так как ты "внедряешься" в чужой EXE, то соответственно он со своей стороны это поддержать не может...

_________________
:dj: https://mastodon.social/@Shaos


20 Jan 2018 18:57
Profile WWW
Supreme God
User avatar

Joined: 21 Oct 2009 08:08
Posts: 7777
Location: Россия
Reply with quote
Lavr wrote:
Мне кажется, что вызов экспортирумой ф-ции DLL - не в потоке окна, созданного DLL-кой.
Он в потоке ехе-файла, который эту DLL-ку вызвал, поэтому переменные окна недоступны
вызываемой из DLL ф-ции.

Я тут подумал, надо, видимо, сделать всё несколько иначе...
В вызываемой из DLL функции послать окну сообщение через PostMessage.
Code:
extern "C" VOID __declspec(dllexport) disp(INT arg) 
{
 PostMessage(hwnd, arg ... );
}
и передать ему вот этот (INT arg), который записывается в порт 177714о.

Окно свой hwnd знает всегда, отрисует всё что надо по INT arg в своей очереди сообщений,
а главное - запомнит этот INT arg!
Тогда, когда надо будет возобновить испорченную клиентскую область по сообщению Венды,
вот здесь придется всего лишь повторить последнюю отрисовку по значению INT arg.
Code:
      case WM_PAINT:
           hdc = BeginPaint(hwnd, &ps);
           // отрисовать клиентскую область окна по последнему значению [b]INT arg[/b].
           EndPaint(hwnd, &ps);
      break;

Мне думается, так будет проще. В противном случае где-то надо запоминать всю клиентскую область
как контекст окна и выводить его заново, если окно "испорчено" другими окнами.

Ибо просмотрел я интернет, что-то ни у кого не получлось сделать этот "shared segment in a dll".
Не первый раз я с этим сталкиваюсь, но видимо, время победить эту проблему пока не пришло.
К "инжекции в код" я тоже не раз подступался, но корректно под Вендой получилось впервые... :wink:

_________________
iLavr


21 Jan 2018 14:02
Profile
Supreme God
User avatar

Joined: 21 Oct 2009 08:08
Posts: 7777
Location: Россия
Reply with quote
Shaos, тут такой вот вопрос возник, я не знаю, как это С++ делает...

Ну, скажем, у меня всё та же функция в dll-библиотеке:
Code:
extern "C" VOID __declspec(dllexport) disp(INT arg) 
{
 ...
}

Если я вызываю её из кода, скажем, как обычно:
Code:
disp(0х0000ЕЕАА);

На ассемблере это выглядит вот так:
Code:
                   push      00000eeaa ; аргумент (INT arg)  - в стеек
                   call     .000401020 ; вызов jmp       disp
                   add       esp,004   ; очищаем стек на 4 байта

.00401020:         jmp      disp ;injected.dll

Если я теперь в вызываемой функции напишу:
Code:
extern "C" VOID __declspec(dllexport) disp(INT arg) 
{
 arg =  0х0000ffff // - заношу значение прямо в аргумент
 ...
}

То по выходу из функции значение (INT arg) будет изменено прямо в стеке, где оно передается?

_________________
iLavr


24 Jan 2018 20:48
Profile
Supreme God
User avatar

Joined: 21 Oct 2009 08:08
Posts: 7777
Location: Россия
Reply with quote
Чисто опытным путём получается, что аргумент, переданный по значению вызываемая функция не изменяет.

Написал для теста вот такую функцию:
Code:
extern "C" VOID __declspec(dllexport) disp(INT arg) 
{
  arg += 255;
  Sleep(arg);
}

С++ компилирует её в следующий ассемблерный код :
Code:
.10001000: 8B442404                     mov       eax,[esp][00004]; - это arg из стека
.10001004: 05FF000000                   add       eax,0000000FF ; arg += 255;
.10001009: 50                           push      eax; передаем arg функции Sleep
.1000100A: FF1574D10010                 call      Sleep ;KERNEL32.dll

То есть все манипуляции проводились с копией arg, его значение, переданное в стеке, не изменилось.

_________________
iLavr


25 Jan 2018 08:17
Profile
Supreme God
User avatar

Joined: 21 Oct 2009 08:08
Posts: 7777
Location: Россия
Reply with quote
Lavr wrote:
Чисто опытным путём получается, что аргумент, переданный по значению вызываемая функция не изменяет.
Но если хорошо подумать, то, пожалуй, можно это и сделать... :wink:

Поскольку С++ компилирует функцию с одним аргументом в следующий ассемблерный код :
Code:
.10001000: 8B442404                     mov       eax,[esp][00004]; - это arg из стека
.10001004: 05FF000000                   add       eax,0000000FF ; arg += 255;
.10001009: 50                           push      eax; передаем arg функции Sleep
.1000100A: FF1574D10010                 call      Sleep ;KERNEL32.dll
то всё, что нам надо сделать после манипуляций с копией аргумента в eax - это:
Code:
                     mov       [esp][00004],eax; - arg обратно в стек

Я не знаю, как это сделать в терминах С++, но на ассемблере это делается элементарно.
В крайнем случае можно сделать фиктивную оперцию - ну хоть тот-же Sleep - а потом
пропатчить эту часть кода как mov [esp][00004],eax.

_________________
iLavr


25 Jan 2018 19:08
Profile
Supreme God
User avatar

Joined: 21 Oct 2009 08:08
Posts: 7777
Location: Россия
Reply with quote
Shaos, двумерный массив в С++ можно как-то инициаллизировать сразу при объявлении его одной строкой?
Code:
word keyArray[4][13] = ....... ?

Он мне нужен как глобальный и сразу проинициаллизированный нулями.

_________________
iLavr


29 Jan 2018 22:46
Profile
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22412
Location: Silicon Valley
Reply with quote
Lavr wrote:
Shaos, двумерный массив в С++ можно как-то инициаллизировать сразу при объявлении его одной строкой?
Code:
word keyArray[4][13] = ....... ?

Он мне нужен как глобальный и сразу проинициаллизированный нулями.

Угу:
Code:
word keyArray[4][13] = {
 {0,0,0,0,0,0,0,0,0,0,0,0,0},
 {0,0,0,0,0,0,0,0,0,0,0,0,0},
 {0,0,0,0,0,0,0,0,0,0,0,0,0},
 {0,0,0,0,0,0,0,0,0,0,0,0,0}
};

_________________
:dj: https://mastodon.social/@Shaos


30 Jan 2018 05:33
Profile WWW
Supreme God
User avatar

Joined: 21 Oct 2009 08:08
Posts: 7777
Location: Россия
Reply with quote
Shaos wrote:
Code:
word keyArray[4][13] = {
 {0,0,0,0,0,0,0,0,0,0,0,0,0},
 {0,0,0,0,0,0,0,0,0,0,0,0,0},
 {0,0,0,0,0,0,0,0,0,0,0,0,0},
 {0,0,0,0,0,0,0,0,0,0,0,0,0}
};

Спасибо!... что-то я сам не допер... :wink:

_________________
iLavr


30 Jan 2018 11:38
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 28 posts ]  Go to page Previous  1, 2

Who is online

Users browsing this forum: No registered users and 18 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group
Designed by ST Software.