Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Потрепаться";
Текущий архив: 2002.03.21;
Скачать: [xml.tar.bz2];

Вниз

Ну тогда еще задачка:   Найти похожие ветки 

 
Алексей Петров   (2002-02-06 12:21) [0]

Напишите код, который определяет имя модуля, в котором он находится.

модуль читаем двояко (2 раздельнх задачи)

1. Модуль = unit - нужно получить полное имя исходного pas файла.
2. Модуль = module - получтьб полное имя exe, dll или bpl в котором код сидит в run-time


 
McSimm   (2002-02-06 12:27) [1]

Исходный pas файл?
Какой из?
Тот, в котором происходит выполнения кода в данный момент?

А какие ограничения?

Настройки компилятора и компоновщика меняем как хотим?
:)


 
Алексей Петров   (2002-02-06 12:31) [2]

function MyPasFileName: string;
и
function MyModuleName: string;

Ограничения? Настройки проекта менять и попадать в зависимость от них не стоит. А применять директивы компилятора - почему бы и нет.


 
Алексей Петров   (2002-02-06 12:34) [3]

Еще в догонку задача из той-же оперы:

В приложении, скомпелированном с run-time packages определить в каком BPL-е или exe описан данный класс:

function GetClassPackageFileName(aClass: TClass): string;


 
troits   (2002-02-06 12:53) [4]

По поводу второго вопроса:
GetModuleFileName(HInstance, ... подойдет?


 
Алексей Петров   (2002-02-06 12:56) [5]

> troits © (06.02.02 12:53)
вполне.
А для класса?


 
McSimm   (2002-02-06 12:58) [6]

Не даешь .map файл генерить, тогда:

const
ThisUnitName = "MyUnit.pas";

function MyPasFileName: string;
begin
Result := ThisUnitName
end

Нигде условия не нарушил? Все в рамках?
При изменении имени файла константу тоже поменять можно.
:)


 
Алексей Петров   (2002-02-06 13:03) [7]

> McSimm © (06.02.02 12:58)
Формально, конечно, удовлетворяет моей формулировке :)
Но код можно сделать инвариантным от его местоположения. Т.е. переносишь функцию без изменений в другой модуль, или просто модуль переносишь в другую директорию - и возвращаемый результат отражает изменения.


 
McSimm   (2002-02-06 13:06) [8]

И все это без отладочной информации?

И exe будет также работать на любой машине?


 
Алексей Петров   (2002-02-06 13:11) [9]

Почему-же без отладочной? Что-то можно локально включить.

А вот где exe-шник будет запущен - не известно. Функция должна сказать, где она лежала в момент компиляции.


 
McSimm   (2002-02-06 13:28) [10]

Тогда признаю поражение.
Не вижу способа чтобы
- не используя .map;
- не имея доступа к dcu;
- инвариантно к месту расположения функции в теле программы
получить путь и имя pas файла
- даже если exe запущен на другой машине.

Все. Здаюсь.


 
Алексей Петров   (2002-02-06 14:51) [11]

Что, всем слабо?


 
VuDZ   (2002-02-06 15:03) [12]

вообще-то должен быть способ - когда у меня пару раз вылетал winCom (он написан на делфи, то писал строку, где произошла ошибка)
в С есть такой вариант:
#define chMSG(desc) message(__FILE__ "(" chSTR(__LINE__) "):" #desc)
так что должно быть что-то, связанно с препроцессором...


 
Алексей Петров   (2002-02-06 15:06) [13]

> VuDZ © (06.02.02 15:03)
В С эта задача тривиальна: там есть соответствующие предопределенные макросы.
char * getMyName()
{
return __FILE__;
}

А в ObjectPascal-е препроцессора нет.


 
VuDZ   (2002-02-06 15:26) [14]

2Алексей Петров
ну и я об этом же (о "С")

а для делфи должно быть нечто подобное, иначе, что это за языкъ...


 
Алексей Петров   (2002-02-06 15:32) [15]

Нормальный язык. А препроцессор - авторы считают, что не нужен. Правы или нет - не знаю? Но все, кто с ним работают - обходятся.


 
VuDZ   (2002-02-06 15:40) [16]

насколько я понял, суть проблемы такая: надо, что бы некая ф-ия знала, в котором модуле она находиться? так?

// типа, глобльная переменая для модуля
TString strMod = "my cool module.pas"

function .... (bla-bla-bla)
var
....
begin
....
OutputDebugString((TChar)"Proc called from ");
OutputDebugString((TChar)strMod);
....
end;

:D


 
McSimm   (2002-02-06 15:42) [17]

Вообще эта задачка в самый раз на призовую. Я про определение имени pas файла. (2All - ответ мне Алексей уже сказал).
В ней все для этого требования - и нестандартность мышления, и опыт/знания программирования на Делфи.

Вот только призы раздавать некому :)


 
Алексей Петров   (2002-02-06 15:43) [18]

> VuDZ © (06.02.02 15:40)
Чукча не читатель, чукча писатель :)

см. McSimm © (06.02.02 12:58) и Алексей Петров © (06.02.02 13:03)


 
VuDZ   (2002-02-06 16:12) [19]

2Алексей Петров
ya vol - мы мыслим глобально (или локально, смотря с какой стороны подходить)


 
vuk   (2002-02-06 19:07) [20]

Пойдеть? :o)

function GetUnitName : string;
var
s : string;
n, n2 : integer;
begin
Result := "";
{$C+}
try
Assert(false);
except
on e : exception do s := e.Message;
end;
{$C-}
n := Pos("(", s );
if n = 0 then exit;
n2 := Pos( ",", s );
if (n2 <= n ) then exit;
Result := copy( s, n+1, n2-n - 1);
end;


 
Shaman_Naydak   (2002-02-06 20:55) [21]

//1-я функция - та, о которой написал McSimm.
//Если передать ей HInstance, то она вернет имя модуля DLL/EXE.

function GetModuleFileName(Instance: LongWord) : string;
var
Buffer: array[0..261] of Char;
begin
SetString(Result, Buffer, Windows.GetModuleFileName(Instance, Buffer, SizeOf(Buffer)));
end;

// А вот эта ф-ция и ищет модуль класса, приколитесь
// проверить при компиляции с пакетом и без оного
function GetClassPackageFileName(aClass: TClass): string;
var Instance: LongWord;
begin
Result:="";
Instance:=FindClassHInstance(aClass);
if Instance <> 0 then
Result:=GetModuleFileName(Instance);
end;

>> Алексей Петров: Действительно, неплохая разминка для мозгов..
Может опубликуешь модуль с набором таких полезных ф-ций, а?


 
Алексей Петров   (2002-02-07 09:52) [22]

> vuk © (06.02.02 19:07)
Браво. Задача решена.
Но, позвольте одно мелкое замечие по коду: Вы {$C-} оставляете после себя, даже если до Вашей функции был {$C+}. Это не вполне корректно :)

ИМХО, для помещения фунции в прописи стоит заменить {$C+} и {$C-} на более сложные конструкции:

{$IFOPT C-}
{$C+}
{$DEFINE C_ACTIVATED}
{$ENDIF C-}

...

{$IFDEF C_ACTIVATED}
{$UNDEF C_ACTIVATED}
{$C-}
{$ENDIF}


Но это уже чисто техника, а задача решена отлично.


> Shaman_Naydak © (06.02.02 20:55)
В свете Вашего решения задача оказалась даже проще, чем я думал :) Мое решение было длиннее. Браво.
Дело в том, что я функцию FindClassHInstance нашел только вчера в свете обсуждения даннной задачи с MsSimm, а до того её всегда сам реализовывал. И вся её нетривиальность, на мой взгляд, заключалась именно в численном совпадении Hinstance с TMemInfo.AllocationBase, при использовании функции Win32 API VirtualQuery и именно это и используется в функции FindClassHInstance.

К стати GetModuleFileName именно так описана в SysUtils.pas.


 
Алексей Петров   (2002-02-07 10:09) [23]

Еще немного. Меня несколько удивило, что EAssertFailure не содержит отдельно имени pas файла и № строки, а только в виде сообщения.

Обратите внимание, что обработкой Assert можно управлять самим. Я лично использовал Assert совершенно нетривиальным образом: Мне нужно было организовать трасиировку нескольких потоков и я перекрыл AssertErrorHanler на код, пишуший в лог что поток прошел через указанную точку, а Exception не генерировал.
После этого повсеместно в коде потока были расставлены Assert(False). - может кому идея пригодится :)

А вот код, демонстрирующий подмену обработки:

unit Assertions;

interface
uses
SysUtils;

type
EAssertionWithDetail = class(EAssertionFailed)
protected
FUnitName: string;
FLineNumber: Integer;
public
constructor Create(const Message, Filename: AnsiString; LineNumber: Integer);
property UnitName: string read FUnitName;
property LineNumber: Integer read FLineNumber;
end;

implementation
uses
SysConst;

{ EAssertionWithDetail }
function CreateAssertException(const Message, Filename: string;
LineNumber: Integer): Exception;
var
S: string;
begin
if Message <> "" then S := Message else S := SAssertionFailed;
Result := EAssertionWithDetail.Create(S, Filename, LineNumber);
end;

procedure RaiseAssertException(const E: Exception; const ErrorAddr, ErrorStack: Pointer);
asm
MOV ESP,ECX
MOV [ESP],EDX
MOV EBP,[EBP]
JMP System.@RaiseExcept
end;

procedure AssertErrorHandler(const Message, Filename: string;
LineNumber: Integer; ErrorAddr: Pointer);
var
E: Exception;
begin
E := CreateAssertException(Message, Filename, LineNumber);
RaiseAssertException(E, ErrorAddr, PChar(@ErrorAddr)+4);
end;

constructor EAssertionWithDetail.Create(const Message,
Filename: AnsiString; LineNumber: Integer);
begin
inherited Create(Format(SAssertError,[Message, Filename, LineNumber]));
FUnitName := FileName;
FLineNumber := LineNumber;
end;

initialization
AssertErrorProc := @AssertErrorHandler;
finalization
AssertErrorProc := nil;
end.


 
Алексей Петров   (2002-02-07 10:20) [24]

Немного комментариев к unit Assertions - здесь большая часть просто скопированна из SysUtils.pas.
После подключения такого модуля к проекту можно из AssertionFailure вытаскивать имя модуля и № строки как свойства.

С таким модулем функция для решения задачи №1 выглядит так:

function GetUnitName : string;
begin
Result := "";
{$IFOPT C-}
{$C+}
{$DEFINE C_ACTIVATED}
{$ENDIF C-}
try
Assert(False);
except
on E: EAssertionWithDetail do
Result := E.UnitName
end;
{$IFDEF C_ACTIVATED}
{$UNDEF C_ACTIVATED}
{$C-}
{$ENDIF}
end;


 
vuk   (2002-02-07 14:53) [25]

to Алексей Петров:
С директивами компилятора - это все понятно, обычное решение с сохранением и восстановлением значения директивы. Просто лень было ковыряться - это же просто пример... ;o)



Страницы: 1 вся ветка

Форум: "Потрепаться";
Текущий архив: 2002.03.21;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.51 MB
Время: 0.006 c
1-66874
lipskiy
2002-03-03 21:56
2002.03.21
Компонент-расписание


1-66845
Mishka
2002-03-07 20:56
2002.03.21
Постоянно висящие Hintы


6-66940
Vampire
2001-11-03 18:54
2002.03.21
А с помощью NMStrm можно как покет отправить пусковой файл??? И чтобы у получателя он естественно тут же запутился


1-66841
Random
2002-03-07 19:09
2002.03.21
Вопрос по доступу к компонентам


3-66777
Лёша
2002-02-22 14:26
2002.03.21
Реализация post_event.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский