Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
18-05-2006 02:37
Будет ли являться выходом из данной "проблемы" замена типа string на WideString?
Будет, так как по сути используется тот же "ShareMem", только от Microsoft.
Хочется сделать какой-нибудь Вывод в данной дискуссии:
Опишу небольшой примерчик. Имеется класс, который описан в DLL и реализует некий интерфейс. У класс есть поле FOnTagEvent: TX12TagsEvent, которое предназначено для хранения ссылки на "объектную процедуру" для обрабоки некоторого события (данный класс изначально был компонентом, и соответсвенно наследовался от TComponent, но при переводе его в DLL наследник соответсвенно стал TObject, а точнее TInterfacedObject)! Пример типа метода для обработки события:
TX12TagsEvent = procedure (const Sender: TObject; const TagName: String; var ReplaceText: string) of object;
Соответсвенно для данного класса описан интерфейс с описанием основных методов и свойств. Меня интересует вопрос, корректно ли будет передаваться параметр ReplaceText: string при обработке события OnTagEvent обратно в класс, который находится в DLL и доступен, соотвественно, чере _интерфейс_???
Если из описания примера смысл не ясен, прошу простить...
А типа соглашения о вызове у методов интерфейса указать, разве не прокатит?? safecall, OleVariant, WideString... и поехали - "Белое не надевать", делфийские стринги и обьекты не передавать..
Или мы о разном толкуем?
Да, о разном. Я, вообще-то, имел ввиду вот что: пусть у нас есть интерфейс с методами A и B, а у класса, который его реализует - поле FS:string. И пусть в методе A есть код FS:='ABC', а в B - FS:=FS+'CDE'. Тогда, если мы вызываем из программы метод A, потом передаём интерфейс в DLL и вызываем там метод B, получается, что в DLL перераспределяется память, выделенная в основной программе.
Однако по зрелому размышлению я понял, что я тут неправ: то, какой менеджер памяти будет использован при работе B, определяется на этапе компиляции и не зависит от того, откуда B вызывается. Следовательно, перераспределением памяти в данном случае будет заниматься тот же менеджер, который её выделил, и, следовательно, проблем не будет.
Сейчас я не могу придумать ситуацию, когда передача в DLL интерфейсов могла бы привести к тем проблемам, которые решаются с помощью ShareMem. Весьма вероятно, что таких ситуаций вообще не существует, и интерфейсы можно безопасно передавать и без ShareMem.
Мне кажется, что соглашения о вызове методов могут гарантировать "корректный" обмен параметрами между модулями не более. А вот пробдемы перераспределения памяти из одного модуля в другом остаются теже. Или я все же не так что то понимаю?
17-05-2006 09:41 | Комментарий к предыдущим ответам
Ребяты! Может я торможу, но если уж делать нормальные _интерфейсы_ нормальным путем, то никаких ShareMem не нужно.
To Антон Григорьев:
>>>что его методы при своей работе не перераспределяют выделенную ранее память
А типа соглашения о вызове у методов интерфейса указать, разве не прокатит?? safecall, OleVariant, WideString... и поехали - "Белое не надевать", делфийские стринги и обьекты не передавать..
Или мы о разном толкуем?
Ну есть всякие способы обойтись без библиотеки, можно например поставить http://fastmm.sourceforge.net/ или использовать вместо ShareMem такой модуль (не тестировал):
unit FastShareMem;
interface
var
GetHeapStatus:function:THeapStatus;
GetAllocMemCount:function:Integer;
GetAllocMemSize:function:Integer;
type
TFastSharememPack=record
MemMgr:TMemoryManager;
GetHeapStatus:function:THeapStatus;
GetAllocMemSize:function:Integer;
GetAllocMemCount:function:Integer;
end;
function _GetAllocMemCount:Integer;
begin
Result:=System.AllocMemCount;
end;
function _GetAllocMemSize:Integer;
begin
Result:=System.AllocMemSize;
end;
var
MemPack:TFastSharememPack=(GetHeapStatus:System.GetHeapStatus;GetAllocMemSize:_GetAllocMemSize;GetAllocMemCount:_GetAllocMemCount);
WndClass:TWndClass=(style:CS_GLOBALCLASS;lpfnWndProc:@MemPack;lpszClassName:ClassName);
OldMemMgr:TMemoryManager;
IsFirst:Boolean;
initialization
IsFirst:=not GetClassInfo(HInstance,ClassName,WndClass);
if IsFirst then begin
GetMemoryManager(MemPack.MemMgr);
GetHeapStatus:=System.GetHeapStatus;
GetAllocMemCount:=@_GetAllocMemCount;
GetAllocMemSize:=@_GetAllocMemSize;
WndClass.hInstance:=hInstance;
if RegisterClass(WndClass)=0 then begin
MessageBox(0,'Shared Memory Allocator setup failed: Cannot register class.','FastShareMem',MB_ICONERROR or MB_TASKMODAL);
Halt;
end;
end
else begin
GetMemoryManager(OldMemMgr);
GetHeapStatus:=TFastSharememPack(WndClass.lpfnWndProc^).GetHeapStatus;
GetAllocMemCount:=TFastSharememPack(WndClass.lpfnWndProc^).GetAllocMemCount;
GetAllocMemSize:=TFastSharememPack(WndClass.lpfnWndProc^).GetAllocMemSize;
SetMemoryManager(TFastSharememPack(WndClass.lpfnWndProc^).MemMgr);
end;
finalization
if IsFirst then
UnregisterClass(ClassName,HInstance)
else
SetMemoryManager(OldMemMgr);
end.
Нет, если уж вы начали передавать классы, то позаботьтесь и об использовании ShareMem - классы могут перераспределять память и помимо использования вами свойств.
Значит если в классе изначально были свойства типа String, то соотвественно при переносе класса в DLL желательно свойства переопределить в тип, напрмер, PChar, чтоб передавать адрес на выделенный программой буфер памяти под строку, и соотвествено также возвращать данные из DLL?
Лучше придерживаться, хотя иногда можно обойтись и без них. Опасность представляет та ситуация, когда память, выделенная в одном модуле, освобождается или перераспределяется в другом. А класс - это чёрный ящик, в общем случае вы не можете гарантировать, что его методы при своей работе не перераспределяют выделенную ранее память. Это не зависит от того, используются ли для доступа к объекту интерфейсы, или нет.
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.