Total Commander Forum Index Total Commander
Форум поддержки пользователей Total Commander
Сайты: Все о Total Commander | Totalcmd.net | Ghisler.com | RU.TCKB
 
 RulesRules   SearchSearch   FAQFAQ   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

ошибка при написании wdx плагина
Goto page 1, 2  Next
 
Post new topic   Reply to topic    Total Commander Forum Index -> Написание плагинов для Total Commander printer-friendly view
View previous topic :: View next topic  
Author Message
tonyy



Joined: 13 May 2013
Posts: 5

Post (Separately) Posted: Mon May 13, 2013 14:16    Post subject: ошибка при написании wdx плагина Reply with quote

Уважаемые участники форума!
нужна помощь. не могу найти ошибку, из-за которой не работает плагин.
вот код:
Code:

{$E wdx}
library Segd1Inf1;

uses
  Windows,
  SysUtils,

  ContPlug,
  Usegdread,

  Classes;

  const
  _DetectString: PAnsiChar = 'EXT="segd"';

  _FieldsNum = 3;
  _Fields: array[0.._FieldsNum-1] of PAnsiChar = (
    'prof ',
    'piket ',
    'data ');

procedure ContentGetDetectString(DetectString: PAnsiChar; maxlen: integer); stdcall;
begin
  lstrcpynA(DetectString, _DetectString,maxlen);
end;

function ContentGetSupportedField(FieldIndex: integer; FieldName: PAnsiChar;
  Units: PAnsiChar; maxlen: integer): integer; stdcall;
begin
  if FieldIndex in [0..High(_Fields)] then
  begin
    lstrcpynA(FieldName,_Fields[FieldIndex],maxlen);
    strcopy(Units,'');

    Result := FT_STRING;
  end else Result := ft_NoMoreFields;
end;                                                                               

function ContentGetValueW(fn: PWideChar; FieldIndex, UnitIndex: integer;
  FieldValue: PWideChar; MaxLen, Flags: integer): integer; stdcall;
var

  s: AnsiString;
  ext: string;
 
begin

  if (FieldIndex<0) or (FieldIndex >= _FieldsNum) then
    begin Result:= FT_NOSUCHFIELD; Exit end;

  ext:= LowerCase(ExtractFileExt(fn));

  if (Flags and CONTENT_DELAYIFSLOW)>0 then
    if (ext<>'') then begin Result:= FT_DELAYED; Exit end;

        s:= segdread(fn, FieldIndex);

        if s=''
          then
            Result:= FT_FIELDEMPTY
          else
          begin
             lstrcpynW(FieldValue, PWideChar(Widestring(s)), MaxLen);
             Result:= FT_STRINGW;
          end;

end;


function ContentGetValue(fn: PAnsiChar; FieldIndex, UnitIndex: integer;                                   
  FieldValue: PWideChar; MaxLen, Flags: integer): integer; stdcall;

begin
  //Result := ContentGetValueW(PWideChar(WideString(fn)), FieldIndex, UnitIndex, FieldValue, MaxLen, Flags);
   Result:=ft_fieldempty;


end;                                                                                                     

exports
  ContentGetDetectString,
  ContentGetSupportedField,
  ContentGetValueW,
  ContentGetValue;
                                                                                                         
end.

{$R *.res}

begin
end.

надеюсь на конструктивную помощь. это мой первый плагин. буду благодарен любой помощи.
Back to top
View user's profile Send private message
CaptainFlint



Joined: 14 Dec 2004
Posts: 6151
Location: Москва

Post (Separately) Posted: Mon May 13, 2013 16:57    Post subject: Reply with quote

Для начала хорошо бы описать, как именно проявляется "неработа" плагина. Что значит "не работает"? Не устанавливается? Устанавливается, но не выводится в списке WDX-плагинов? Выводится, но не показывает список полей? Показывает, но неправильно?..
_________________
Почему же, ё-моё, ты нигде не пишешь "ё"?
Back to top
View user's profile Send private message
tonyy



Joined: 13 May 2013
Posts: 5

Post (Separately) Posted: Mon May 13, 2013 21:52    Post subject: Reply with quote

он устанавливается. выводится в списке wdx плагинов появляются название поле, а вот сами значения не появляются
Back to top
View user's profile Send private message
MVV



Joined: 15 Oct 2009
Posts: 4811
Location: Ростов-Дон

Post (Separately) Posted: Mon May 13, 2013 22:10    Post subject: Reply with quote

Code:
Result:=ft_fieldempty;

Типа, дядя Коммандир, всё ок, поле пустое... Для теста уже возвращай строчку текстовую какую-нибудь, или число. Впрочем, если есть юникодовская версия функции, тотал (современный) не будет вызывать ансишную.

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

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

Добавлено спустя 6 минут:

А, это некорректные отступы сбивают с толку...

Непонятно, кстати, зачем вызывать segdread для пустого расширения. Ведь эта пара строк завершает функцию только при первом проходе И непустом расширении. При первом проходе и пустом расширении функция продолжит работу.
Code:
   if (Flags and CONTENT_DELAYIFSLOW)>0 then
      if (ext<>'') then begin Result:= FT_DELAYED; Exit end;


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

Кстати, если s - ансишная строка, необязательно её в юникод конвертить перед возвратом тоталу, он прекрасно поймет, если вернуть ему ансишную с результатом FT_STRING.
_________________
TCFS2 + TCFS2Tools: Полноэкранный режим и многое другое (обсуждение)
WINCMD.RU: AskParam, CopyTree, NTLinks, Sudo, VirtualPanel…
Back to top
View user's profile Send private message
CaptainFlint



Joined: 14 Dec 2004
Posts: 6151
Location: Москва

Post (Separately) Posted: Tue May 14, 2013 00:46    Post subject: Reply with quote

Вопрос на засыпку: а зачем имена полей плагина завершаются пробелами? Я сразу и не заметил… Я вовсе не уверен, что Тотал вообще умеет такое нормально кушать. Так что первым делом нужно эти пробелы убить, а тестовые колонки в Тотале пересоздать. И если по-прежнему содержимое будет пустым, то надо либо пошаговой отладкой проходить, как предложил MVV, либо комментировать всё содержимое функции ContentGetValueW, заменять её простейшей реализацией (например, безусловным заполнением константной строкой, без всяких segdread и отложенных выполнений), ну и последовательно приводить к желаемому виду, постоянно проверяя, работает ли код после очередного шага.
_________________
Почему же, ё-моё, ты нигде не пишешь "ё"?
Back to top
View user's profile Send private message
tonyy



Joined: 13 May 2013
Posts: 5

Post (Separately) Posted: Tue May 14, 2013 17:47    Post subject: Reply with quote

пробелы убрал. проблему это не решило, к сожалению.
как провести пошаговую отладку подключаясь к тоталу?
Back to top
View user's profile Send private message
ProgMan13



Joined: 19 Aug 2009
Posts: 334

Post (Separately) Posted: Tue May 14, 2013 19:21    Post subject: Reply with quote

Отступы действительно дикие, тотал спокойно обрабатывает поля с такими пробелами, вызова функции отложенного выполнения в приведённом примере нет, код рабочий.
Code:
  if (Flags and CONTENT_DELAYIFSLOW)>0 then
    if (ext<>'') then begin Result:= FT_DELAYED; Exit end;

Перед Exit должен быть вызов типа MyThreadedFunction, а её нет. Эти две строчки - фэйк - их закомментировать.

Несколько лет назад на форуме поднималась тема про расширения файлов в DetectString. Расширение должно быть написано прописными буквами Smile Так что надо поменять
_DetectString: PAnsiChar = 'EXT="segd"';
на
_DetectString: PAnsiChar = 'EXT="SEGD"';
Перекомпилировать и переустановить(!) плагин.
Я не знаю, правильно ли работает функция segdread, но чтобы проверить работу плагина просто заменить
s:= segdread(fn, FieldIndex);
на
s:= 'TEST';
Back to top
View user's profile Send private message
MVV



Joined: 15 Oct 2009
Posts: 4811
Location: Ростов-Дон

Post (Separately) Posted: Tue May 14, 2013 19:38    Post subject: Reply with quote

tonyy,
Укажи в качестве отлаживаемого в среде разработки процесса тотал, запускаемый с конфигом, который грузит дебаг-версию плагина, по идее можно будет отлаживать. В Visual Studio так прекрасно работает.

ProgMan13 wrote:
Перед Exit должен быть вызов типа MyThreadedFunction, а её нет. Эти две строчки - фэйк - их закомментировать.

Это еще зачем? По-моему, те строчки выполняют вполне определенную задачу - сообщают тоталу на первом (основном) проходе, что обработка затянется, и что нужно вызвать функцию во втором (фоновом) проходе.
_________________
TCFS2 + TCFS2Tools: Полноэкранный режим и многое другое (обсуждение)
WINCMD.RU: AskParam, CopyTree, NTLinks, Sudo, VirtualPanel…
Back to top
View user's profile Send private message
ProgMan13



Joined: 19 Aug 2009
Posts: 334

Post (Separately) Posted: Tue May 14, 2013 20:04    Post subject: Reply with quote

MVV wrote:
Это еще зачем? По-моему, те строчки выполняют вполне определенную задачу - сообщают тоталу на первом (основном) проходе, что обработка затянется, и что нужно вызвать функцию во втором (фоновом) проходе.

Хм, да это моё видение. Функция не возвращает никаких данных быстро, слишком специализированная (файлы "segd"). Вызов этой функции в фоне не должен залочить TC, как я понимаю, - тогда согласен.
Тогда добавить Enter/LeaveCriticalSection?
Back to top
View user's profile Send private message
MVV



Joined: 15 Oct 2009
Posts: 4811
Location: Ростов-Дон

Post (Separately) Posted: Tue May 14, 2013 20:32    Post subject: Reply with quote

Критическая секция нужна только при необходимости обращения к общим глобальным ресурсам, которых тут не наблюдается.
В основном потоке функция работает со своими параметрами и завершается.
В фоновом выполняет какие-то операции, это один поток, никто не будет вызывать её одновременно больше 1 раза, поэтому проблем не будет, даже если segdread использует глобальные объекты.
_________________
TCFS2 + TCFS2Tools: Полноэкранный режим и многое другое (обсуждение)
WINCMD.RU: AskParam, CopyTree, NTLinks, Sudo, VirtualPanel…
Back to top
View user's profile Send private message
ProgMan13



Joined: 19 Aug 2009
Posts: 334

Post (Separately) Posted: Tue May 14, 2013 20:45    Post subject: Reply with quote

MVV wrote:
В фоновом выполняет какие-то операции, это один поток, никто не будет вызывать её одновременно больше 1 раза, поэтому проблем не будет, даже если segdread использует глобальные объекты.
Ладно, стоит думать, что Кристиан всё сделал как надо. Но если на другой панели эта функция будет вызвана для другого файла или файла с пустым расширением?
Back to top
View user's profile Send private message
MVV



Joined: 15 Oct 2009
Posts: 4811
Location: Ростов-Дон

Post (Separately) Posted: Tue May 14, 2013 23:41    Post subject: Reply with quote

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

В любом случае, критическая секция должна быть настолько мала, насколько это возможно. Поэтому если ей где-то и место, то в недрах функции segdread (и то только в моменты обращения к глобальным объектам, и то не факт, что нужна), но уж точно не на всю ContentGetValueW.
_________________
TCFS2 + TCFS2Tools: Полноэкранный режим и многое другое (обсуждение)
WINCMD.RU: AskParam, CopyTree, NTLinks, Sudo, VirtualPanel…
Back to top
View user's profile Send private message
tonyy



Joined: 13 May 2013
Posts: 5

Post (Separately) Posted: Wed May 15, 2013 14:19    Post subject: Reply with quote

спасибо большое за помощь. вот что у меня получилось и что более менее работает. хочется узнать, если здесь возможность для улучшения. нет ли тут некорректностей?
Code:

{$E wdx}
library Segd1Inf1;

uses
  Windows,
  SysUtils,

  ContPlug,
  Usegdread,

  Classes;

  const
  _DetectString: PAnsiChar = 'EXT="SEGD"';

  _FieldsNum = 3;
  _Fields: array[0.._FieldsNum-1] of PAnsiChar = (
    'prof',
    'piket',
    'data');

procedure ContentGetDetectString(DetectString: PAnsiChar; maxlen: integer); stdcall;
begin
  lstrcpynA(DetectString, _DetectString,maxlen);
end;

function ContentGetSupportedField(FieldIndex: integer; FieldName: PAnsiChar;
  Units: PAnsiChar; maxlen: integer): integer; stdcall;
begin
  if FieldIndex in [0..High(_Fields)] then
  begin
    lstrcpynA(FieldName,_Fields[FieldIndex],maxlen);
    strcopy(Units,'');

    Result := FT_STRING;
  end else Result := ft_NoMoreFields;
end;                                                                               

function ContentGetValue(fn: pchar; FieldIndex, UnitIndex: integer;
  FieldValue: PByte; MaxLen, Flags: integer): integer; stdcall;
 var
    s:AnsiString;
begin
     s:= segdread(fn, FieldIndex);
     Strlcopy (PAnsiChar (Fieldvalue),PAnsiChar(s),maxlen-1);
     result:=ft_string;
end;

exports
  ContentGetDetectString,
  ContentGetSupportedField,
  ContentGetValue;
                                                                                                         
end.


проверку на расширение 'segd' я сделал в модуле segdread.
еще у меня есть вопросы по поводу функции ContentGetDetectString зачем она нужна и на сколько критично, если ее убрать?
а также по поводу функции ContentGetValueW - в чем ее отличие от ContentGetValue. есть ли смысл делать все таки через ContentGetValueW?
Back to top
View user's profile Send private message
CaptainFlint



Joined: 14 Dec 2004
Posts: 6151
Location: Москва

Post (Separately) Posted: Wed May 15, 2013 15:27    Post subject: Reply with quote

tonyy wrote:
вот что у меня получилось и что более менее работает.

То есть выходит, что вся проблема была лишь в том, что segdread требует имя файла в ANSI?..

tonyy wrote:
еще у меня есть вопросы по поводу функции ContentGetDetectString зачем она нужна и на сколько критично, если ее убрать?

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

tonyy wrote:
а также по поводу функции ContentGetValueW - в чем ее отличие от ContentGetValue. есть ли смысл делать все таки через ContentGetValueW?

Отличие очевидно: в поддержке юникодных имён. Если попадётся SEGD-файл с юникодным именем, то Тотал не сможет его обработать через плагин, если не будет функции ContentGetValueW.
Если для функции segdread есть аналог, умеющий работать с такими файлами, то лучше сделать ContentGetValueW; если нет, то проще оставить ContentGetValue, чтобы не тратить ресурсы на перекодировку.
_________________
Почему же, ё-моё, ты нигде не пишешь "ё"?
Back to top
View user's profile Send private message
MVV



Joined: 15 Oct 2009
Posts: 4811
Location: Ростов-Дон

Post (Separately) Posted: Wed May 15, 2013 15:27    Post subject: Reply with quote

ContentGetValueW - юникодная. Соответственно, плюс в том, что понимает файлы с путями, содержащими всякие там иероглифы и просто символы разных кодовых страниц.

ContentGetDetectString нужна, чтобы тотал автоматом определял строку детектирования. Если функции не будет, строку придется прописывать вручную. Если строки не будет, плагин будет работать для всех файлов, а не только определенных.
_________________
TCFS2 + TCFS2Tools: Полноэкранный режим и многое другое (обсуждение)
WINCMD.RU: AskParam, CopyTree, NTLinks, Sudo, VirtualPanel…
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Total Commander Forum Index -> Написание плагинов для Total Commander All times are GMT + 4 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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 vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group