Страница 1 из 2

ошибка при написании wdx плагина

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

Код: Выделить всё

{$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.
надеюсь на конструктивную помощь. это мой первый плагин. буду благодарен любой помощи.

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

Добавлено: Пн май 13, 2013 21:52
tonyy
он устанавливается. выводится в списке wdx плагинов появляются название поле, а вот сами значения не появляются

Добавлено: Пн май 13, 2013 22:15
MVV

Код: Выделить всё

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

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

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

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

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

Непонятно, кстати, зачем вызывать segdread для пустого расширения. Ведь эта пара строк завершает функцию только при первом проходе И непустом расширении. При первом проходе и пустом расширении функция продолжит работу.

Код: Выделить всё

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

Кстати, если s - ансишная строка, необязательно её в юникод конвертить перед возвратом тоталу, он прекрасно поймет, если вернуть ему ансишную с результатом FT_STRING.

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

Добавлено: Вт май 14, 2013 17:47
tonyy
пробелы убрал. проблему это не решило, к сожалению.
как провести пошаговую отладку подключаясь к тоталу?

Добавлено: Вт май 14, 2013 19:21
ProgMan13
Отступы действительно дикие, тотал спокойно обрабатывает поля с такими пробелами, вызова функции отложенного выполнения в приведённом примере нет, код рабочий.

Код: Выделить всё

  if (Flags and CONTENT_DELAYIFSLOW)>0 then
    if (ext<>'') then begin Result:= FT_DELAYED; Exit end;
Перед Exit должен быть вызов типа MyThreadedFunction, а её нет. Эти две строчки - фэйк - их закомментировать.

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

Добавлено: Вт май 14, 2013 19:38
MVV
tonyy,
Укажи в качестве отлаживаемого в среде разработки процесса тотал, запускаемый с конфигом, который грузит дебаг-версию плагина, по идее можно будет отлаживать. В Visual Studio так прекрасно работает.
ProgMan13 писал(а):Перед Exit должен быть вызов типа MyThreadedFunction, а её нет. Эти две строчки - фэйк - их закомментировать.
Это еще зачем? По-моему, те строчки выполняют вполне определенную задачу - сообщают тоталу на первом (основном) проходе, что обработка затянется, и что нужно вызвать функцию во втором (фоновом) проходе.

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

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

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

Добавлено: Вт май 14, 2013 23:41
MVV
На другой панели это будет либо основной поток, либо тот же фоновый (у тотала только один фоновый поток для загрузки контентных полей).

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

Добавлено: Ср май 15, 2013 14:19
tonyy
спасибо большое за помощь. вот что у меня получилось и что более менее работает. хочется узнать, если здесь возможность для улучшения. нет ли тут некорректностей?

Код: Выделить всё

{$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?

Добавлено: Ср май 15, 2013 15:27
CaptainFlint
tonyy писал(а):вот что у меня получилось и что более менее работает.
То есть выходит, что вся проблема была лишь в том, что segdread требует имя файла в ANSI?..
tonyy писал(а):еще у меня есть вопросы по поводу функции ContentGetDetectString зачем она нужна и на сколько критично, если ее убрать?
Зачем она нужна, описано в документации по написанию плагинов. Если кратко, позволяет отфильтровать файлы, заведомо плагином неподдерживаемые.
tonyy писал(а):а также по поводу функции ContentGetValueW - в чем ее отличие от ContentGetValue. есть ли смысл делать все таки через ContentGetValueW?
Отличие очевидно: в поддержке юникодных имён. Если попадётся SEGD-файл с юникодным именем, то Тотал не сможет его обработать через плагин, если не будет функции ContentGetValueW.
Если для функции segdread есть аналог, умеющий работать с такими файлами, то лучше сделать ContentGetValueW; если нет, то проще оставить ContentGetValue, чтобы не тратить ресурсы на перекодировку.

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

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