Перегруженные функции в C++

Использование и разработка софта (преимущественно на ПЦ)

Moderator: Shaos

User avatar
Lavr
Supreme God
Posts: 16720
Joined: 21 Oct 2009 08:08
Location: Россия

Re: Перегруженные функции в C++

Post by Lavr »

Shaos wrote:так тебе только адрес передать через файл, а потом все через этот адрес перекидывать
А где я его буду хранить в dll-ке между вызовами? :roll: Она ж "кучу" создает и сама её и "рассыпает" потом...
iLavr
User avatar
Shaos
Admin
Posts: 24128
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Перегруженные функции в C++

Post by Shaos »

а у тебя DLL-ка только в момент обращения к порту создается чтоль? и дисплей твой то потухнет, то погаснет? ;)
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Lavr
Supreme God
Posts: 16720
Joined: 21 Oct 2009 08:08
Location: Россия

Re: Перегруженные функции в C++

Post by Lavr »

Мне кажется, что вызов экспортирумой ф-ции DLL - не в потоке окна, созданного DLL-кой.
Он в потоке ехе-файла, который эту DLL-ку вызвал, поэтому переменные окна недоступны
вызываемой из DLL ф-ции.
iLavr
User avatar
Lavr
Supreme God
Posts: 16720
Joined: 21 Oct 2009 08:08
Location: Россия

Re: Перегруженные функции в C++

Post by Lavr »

Lavr wrote:Есть какие-то специальные области памяти для межпотокового общения.
Давно читал я и не понял и забыл... :roll:
Вот здесь, как мне кажется, излагают эту бадью про "общую область":
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: Select all

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
User avatar
Lavr
Supreme God
Posts: 16720
Joined: 21 Oct 2009 08:08
Location: Россия

Re: Перегруженные функции в C++

Post by Lavr »

И вот здесь ещё излагают похожую историю: Разделяемая память в DLL
В Win32 библиотека DLL располагается в области памяти загружающего ее процесса. Каждому процессу предоставляется отдельная копия “глобальной” памяти DLL ( т.е делается отдельная копия всех глобальных переменных, объявленных в исходном коде этой DLL), которая реининиализируется каждый раз, когда новой процесс загружает библиотеку. Это означает, что в Win32 динамическая библиотека, вернее, ее глобальные переменные, не могут использоваться процессами совместно.
И все же, выполнив ряд замысловатых манипуляций над сегментом данных DLL, можно создать общую область памяти для всех процессов, использующих данную библиотеку.

Допустим, имеется массив целых чисел, который должен использоваться всеми процессами, загружающими некоторую библиотеку DLL. Это можно запрограммировать в коде библиотеки следующим образом:

Code: Select all

#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
User avatar
Shaos
Admin
Posts: 24128
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Перегруженные функции в C++

Post by Shaos »

Ну тут по видимому оно должно с обеих сторон быть поддержано, а так как ты "внедряешься" в чужой EXE, то соответственно он со своей стороны это поддержать не может...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Lavr
Supreme God
Posts: 16720
Joined: 21 Oct 2009 08:08
Location: Россия

Re: Перегруженные функции в C++

Post by Lavr »

Lavr wrote:Мне кажется, что вызов экспортирумой ф-ции DLL - не в потоке окна, созданного DLL-кой.
Он в потоке ехе-файла, который эту DLL-ку вызвал, поэтому переменные окна недоступны
вызываемой из DLL ф-ции.
Я тут подумал, надо, видимо, сделать всё несколько иначе...
В вызываемой из DLL функции послать окну сообщение через PostMessage.

Code: Select all

extern "C" VOID __declspec(dllexport) disp(INT arg)  
{
 PostMessage(hwnd, arg ... );
}
и передать ему вот этот (INT arg), который записывается в порт 177714о.

Окно свой hwnd знает всегда, отрисует всё что надо по INT arg в своей очереди сообщений,
а главное - запомнит этот INT arg!
Тогда, когда надо будет возобновить испорченную клиентскую область по сообщению Венды,
вот здесь придется всего лишь повторить последнюю отрисовку по значению INT arg.

Code: Select all

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

Ибо просмотрел я интернет, что-то ни у кого не получлось сделать этот "shared segment in a dll".
Не первый раз я с этим сталкиваюсь, но видимо, время победить эту проблему пока не пришло.
К "инжекции в код" я тоже не раз подступался, но корректно под Вендой получилось впервые... :wink:
iLavr
User avatar
Lavr
Supreme God
Posts: 16720
Joined: 21 Oct 2009 08:08
Location: Россия

Re: Перегруженные функции в C++

Post by Lavr »

Shaos, тут такой вот вопрос возник, я не знаю, как это С++ делает...

Ну, скажем, у меня всё та же функция в dll-библиотеке:

Code: Select all

extern "C" VOID __declspec(dllexport) disp(INT arg)  
{
 ...
}
Если я вызываю её из кода, скажем, как обычно:

Code: Select all

disp(0х0000ЕЕАА); 
На ассемблере это выглядит вот так:

Code: Select all

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

.00401020:         jmp      disp ;injected.dll
Если я теперь в вызываемой функции напишу:

Code: Select all

extern "C" VOID __declspec(dllexport) disp(INT arg)  
{
 arg =  0х0000ffff // - заношу значение прямо в аргумент
 ...
}
То по выходу из функции значение (INT arg) будет изменено прямо в стеке, где оно передается?
iLavr
User avatar
Lavr
Supreme God
Posts: 16720
Joined: 21 Oct 2009 08:08
Location: Россия

Re: Перегруженные функции в C++

Post by Lavr »

Чисто опытным путём получается, что аргумент, переданный по значению вызываемая функция не изменяет.

Написал для теста вот такую функцию:

Code: Select all

extern "C" VOID __declspec(dllexport) disp(INT arg)  
{
  arg += 255;
  Sleep(arg);
}
С++ компилирует её в следующий ассемблерный код :

Code: Select all

.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
User avatar
Lavr
Supreme God
Posts: 16720
Joined: 21 Oct 2009 08:08
Location: Россия

Re: Перегруженные функции в C++

Post by Lavr »

Lavr wrote:Чисто опытным путём получается, что аргумент, переданный по значению вызываемая функция не изменяет.
Но если хорошо подумать, то, пожалуй, можно это и сделать... :wink:

Поскольку С++ компилирует функцию с одним аргументом в следующий ассемблерный код :

Code: Select all

.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: Select all

                     mov       [esp][00004],eax; - arg обратно в стек
Я не знаю, как это сделать в терминах С++, но на ассемблере это делается элементарно.
В крайнем случае можно сделать фиктивную оперцию - ну хоть тот-же Sleep - а потом
пропатчить эту часть кода как mov [esp][00004],eax.
iLavr
User avatar
Lavr
Supreme God
Posts: 16720
Joined: 21 Oct 2009 08:08
Location: Россия

Re: Перегруженные функции в C++

Post by Lavr »

Shaos, двумерный массив в С++ можно как-то инициаллизировать сразу при объявлении его одной строкой?

Code: Select all

word keyArray[4][13] = ....... ?
Он мне нужен как глобальный и сразу проинициаллизированный нулями.
iLavr
User avatar
Shaos
Admin
Posts: 24128
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Перегруженные функции в C++

Post by Shaos »

Lavr wrote:Shaos, двумерный массив в С++ можно как-то инициаллизировать сразу при объявлении его одной строкой?

Code: Select all

word keyArray[4][13] = ....... ?
Он мне нужен как глобальный и сразу проинициаллизированный нулями.
Угу:

Code: Select all

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}
};
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Lavr
Supreme God
Posts: 16720
Joined: 21 Oct 2009 08:08
Location: Россия

Re: Перегруженные функции в C++

Post by Lavr »

Shaos wrote:

Code: Select all

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