ошибка при написании wdx плагина
Select messages from
# through # FAQ
[/[Print]\]
Goto page 1, 2  Next  :| |:
Total Commander -> Написание плагинов для Total Commander

#1: ошибка при написании wdx плагина Author: tonyy PostPosted: Mon May 13, 2013 14:16
    —
Уважаемые участники форума!
нужна помощь. не могу найти ошибку, из-за которой не работает плагин.
вот код:
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.

надеюсь на конструктивную помощь. это мой первый плагин. буду благодарен любой помощи.

#2:  Author: CaptainFlintLocation: Москва PostPosted: Mon May 13, 2013 16:57
    —
Для начала хорошо бы описать, как именно проявляется "неработа" плагина. Что значит "не работает"? Не устанавливается? Устанавливается, но не выводится в списке WDX-плагинов? Выводится, но не показывает список полей? Показывает, но неправильно?..

#3:  Author: tonyy PostPosted: Mon May 13, 2013 21:52
    —
он устанавливается. выводится в списке wdx плагинов появляются название поле, а вот сами значения не появляются

#4:  Author: MVVLocation: Ростов-Дон PostPosted: Mon May 13, 2013 22:10
    —
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.

#5:  Author: CaptainFlintLocation: Москва PostPosted: Tue May 14, 2013 00:46
    —
Вопрос на засыпку: а зачем имена полей плагина завершаются пробелами? Я сразу и не заметил… Я вовсе не уверен, что Тотал вообще умеет такое нормально кушать. Так что первым делом нужно эти пробелы убить, а тестовые колонки в Тотале пересоздать. И если по-прежнему содержимое будет пустым, то надо либо пошаговой отладкой проходить, как предложил MVV, либо комментировать всё содержимое функции ContentGetValueW, заменять её простейшей реализацией (например, безусловным заполнением константной строкой, без всяких segdread и отложенных выполнений), ну и последовательно приводить к желаемому виду, постоянно проверяя, работает ли код после очередного шага.

#6:  Author: tonyy PostPosted: Tue May 14, 2013 17:47
    —
пробелы убрал. проблему это не решило, к сожалению.
как провести пошаговую отладку подключаясь к тоталу?

#7:  Author: ProgMan13 PostPosted: Tue May 14, 2013 19:21
    —
Отступы действительно дикие, тотал спокойно обрабатывает поля с такими пробелами, вызова функции отложенного выполнения в приведённом примере нет, код рабочий.
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';

#8:  Author: MVVLocation: Ростов-Дон PostPosted: Tue May 14, 2013 19:38
    —
tonyy,
Укажи в качестве отлаживаемого в среде разработки процесса тотал, запускаемый с конфигом, который грузит дебаг-версию плагина, по идее можно будет отлаживать. В Visual Studio так прекрасно работает.

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

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

#9:  Author: ProgMan13 PostPosted: Tue May 14, 2013 20:04
    —
MVV wrote:
Это еще зачем? По-моему, те строчки выполняют вполне определенную задачу - сообщают тоталу на первом (основном) проходе, что обработка затянется, и что нужно вызвать функцию во втором (фоновом) проходе.

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

#10:  Author: MVVLocation: Ростов-Дон PostPosted: Tue May 14, 2013 20:32
    —
Критическая секция нужна только при необходимости обращения к общим глобальным ресурсам, которых тут не наблюдается.
В основном потоке функция работает со своими параметрами и завершается.
В фоновом выполняет какие-то операции, это один поток, никто не будет вызывать её одновременно больше 1 раза, поэтому проблем не будет, даже если segdread использует глобальные объекты.

#11:  Author: ProgMan13 PostPosted: Tue May 14, 2013 20:45
    —
MVV wrote:
В фоновом выполняет какие-то операции, это один поток, никто не будет вызывать её одновременно больше 1 раза, поэтому проблем не будет, даже если segdread использует глобальные объекты.
Ладно, стоит думать, что Кристиан всё сделал как надо. Но если на другой панели эта функция будет вызвана для другого файла или файла с пустым расширением?

#12:  Author: MVVLocation: Ростов-Дон PostPosted: Tue May 14, 2013 23:41
    —
На другой панели это будет либо основной поток, либо тот же фоновый (у тотала только один фоновый поток для загрузки контентных полей).

В любом случае, критическая секция должна быть настолько мала, насколько это возможно. Поэтому если ей где-то и место, то в недрах функции segdread (и то только в моменты обращения к глобальным объектам, и то не факт, что нужна), но уж точно не на всю ContentGetValueW.

#13:  Author: tonyy PostPosted: Wed May 15, 2013 14:19
    —
спасибо большое за помощь. вот что у меня получилось и что более менее работает. хочется узнать, если здесь возможность для улучшения. нет ли тут некорректностей?
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?

#14:  Author: CaptainFlintLocation: Москва PostPosted: Wed May 15, 2013 15:27
    —
tonyy wrote:
вот что у меня получилось и что более менее работает.

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

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

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

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

Отличие очевидно: в поддержке юникодных имён. Если попадётся SEGD-файл с юникодным именем, то Тотал не сможет его обработать через плагин, если не будет функции ContentGetValueW.
Если для функции segdread есть аналог, умеющий работать с такими файлами, то лучше сделать ContentGetValueW; если нет, то проще оставить ContentGetValue, чтобы не тратить ресурсы на перекодировку.

#15:  Author: MVVLocation: Ростов-Дон PostPosted: Wed May 15, 2013 15:27
    —
ContentGetValueW - юникодная. Соответственно, плюс в том, что понимает файлы с путями, содержащими всякие там иероглифы и просто символы разных кодовых страниц.

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



Total Commander -> Написание плагинов для Total Commander


output generated using printer-friendly topic mod. All times are GMT + 4 Hours

Goto page 1, 2  Next  :| |:
Page 1 of 2

Powered by phpBB © 2001, 2005 phpBB Group