Как я могу возвратить PChar от функции DLL до приложения VB6, не рискуя катастрофическими отказами или утечками памяти?

Модульный тест должен протестировать единственный путь выполнения кода через отдельный метод. Когда осуществление метода передает за пределами того метода в другой объект, и назад снова, у Вас есть зависимость.

при тестировании того пути выполнения кода с фактической зависимостью Вы не поблочное тестирование; Вы - интеграционное тестирование. В то время как это хорошо и необходимо, это не поблочное тестирование.

, Если Ваша зависимость является багги, Ваш тест может быть затронут таким способом возвратить положительный false. Например, можно передать зависимость неожиданный пустой указатель, и зависимость не может бросить на пустой указатель, поскольку это документируется, чтобы сделать. Ваш тест не делает enounter исключение нулевого аргумента, как это должно иметь, и тестовые передачи.

кроме того, можно найти его твердое, если не невозможный, для надежного получения зависимого объекта возвратить точно, что Вы хотите во время теста. Это также включает ожидаемые исключения броска в тестах.

насмешка А заменяет ту зависимость. Вы устанавливаете ожидания по вызовам к зависимому объекту, установите точные возвращаемые значения, которые он должен дать Вам для выполнения теста, который Вы хотите, и/или какие исключения выдать так, чтобы можно было протестировать код обработки исключений. Таким образом можно протестировать рассматриваемую единицу легко.

TL; DR: Дразните каждую зависимость Ваши касания модульного теста.

6
задан Daniel Rikowski 9 November 2009 в 09:29
поделиться

7 ответов

Вместо этого вам нужно создать BSTR. Строки VB6 на самом деле являются BSTR. Вызовите SysAllocString () на стороне Delphi и верните BSTR на сторону VB6. Сторона VB6 должна будет вызвать SysFreeString () для освобождения строки - она ​​сделает это автоматически.

Если PChar соответствует строке ANSI (в вашем случае), вы должны вручную преобразовать ее в Unicode - используйте для этого MultiByteToWideChar () . См. этот ответ , чтобы узнать, как лучше использовать SysAllocStringLen () и MultiByteToWideChar () вместе.

6
ответ дан 8 December 2019 в 13:00
поделиться

Объединение ответа Sharptooth и Lars D; разве широкие строки уже не выделены через окна и BSTR?

2
ответ дан 8 December 2019 в 13:00
поделиться

Если вы не хотите рисковать сбоями или утечками памяти, создайте свой API, используя Windows API в качестве модели. Там функции API обычно не выделяют собственную память. Вместо этого вызывающий передает буфер и сообщает API, насколько велик буфер. API заполняет буфер до этого предела. См., Например, функцию GetWindowText . Функции не возвращают указатели , если только они не являются указателями на вещи, которые уже предоставил вызывающий. Вместо этого вызывающий предоставляет все сам, и функция просто использует то, что ей дано. Вы почти никогда не увидите параметр выходного буфера, который не сопровождается другим параметром, указывающим размер буфера.

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

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

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

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

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

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

5
ответ дан 8 December 2019 в 13:00
поделиться

I ' m не знаком с Dephi, но вот два основных варианта использования строк с не-COM DLL и VB6.

Вариант 1. Используйте строки "ANSI".

'DLL routine expecting to be passed pointers to ANSI strings '
'VB6 will allocate and deallocate the strings '
'Its vital that VB6 allocates sufficient space for the return string '
Declare Sub MyProc Lib "mylib.dll" (ByVal Param As String, _ 
  ByVal OutVal As String) 

Function DoMyProc(ByVal Param As String) As String
  Dim sResult As String
  sResult = Space$(255)  ' create 255 bytes of space for the return string '
  Call MyProc(Param, sResult) 
  DoMyProc = sResult
End Function

Вариант второй. Используйте BSTR.

'DLL routine expecting to be passed two BSTRs. It will modify the second one. '
'VB6 "owns" both BSTRs and will deallocate them when it has finished with them. '
Declare Sub MyProc(ByVal lpParam As Long, ByVal lpOutVal As Long)

Function DoMyProc(ByVal Param As String) As String
  Dim sResult As String
  Call MyProc(StrPtr(Param), StrPtr(sResult)) 
  DoMyProc = sResult
End Function

Я бы также посоветовал ознакомиться с советом Microsoft по написанию C DLL, которые будут вызываться из VB. Первоначально выпущен с VB5, но все еще актуален для VB6.

2
ответ дан 8 December 2019 в 13:00
поделиться

Используйте Windows API для выделения памяти, на которую указывает указатель PChar. Затем приложение VB может освободить память после использования, также используя Windows API.

1
ответ дан 8 December 2019 в 13:00
поделиться

Я бы сказал, что тот, кто выделяет память, должен также освободить ее в этом случае. Вы столкнетесь с проблемами в других сценариях. Таким образом, наиболее безопасный и чистый способ:

  1. DLL выделяет память (потому что знает, сколько) и возвращает PChar вызывающей стороне
  2. После того, как вызывающая сторона завершает работу с ней, она вызывает FreePointer обратно в DLL
  3. ] DLL освобождает память в экспортированной функции FreePointer

Настройка будет такой:

unit DLL;

interface

uses
  SysUtils;

function Execute(const Params: PChar): PChar; stdcall;
procedure FreePointer(const P: PChar); stdcall;

exports Execute;
exports FreePointer;

implementation

function Execute(const Params: PChar): PChar; stdcall;
var
  Size: Cardinal;
begin
  Size := Calculate the size;
  GetMem(Result, Size);

  ...do something to fill the buffer
end;

procedure FreePointer(const P: PChar); stdcall;
begin
  FreeMem(P);
end;

end.
1
ответ дан 8 December 2019 в 13:00
поделиться

Вы не можете вернуть PChar как результат функции, но можете передать дополнительный параметр PChar и скопировать строку, которую хотите вернуть, в этот PChar. Обратите внимание, что VB должен выделить эту строку до требуемого размера, прежде чем передавать ее в dll. Также в VB этот параметр должен быть объявлен как byval param как строка И он должен быть передан с byval:

  param = "aaaaaaaaaaaaaaaaaaaa" ' reserve 20 characters
  call myproc(byval param)

Дополнительный byval в вызове будет выполнять магию компилятора преобразования строки VB в PChar и обратно.

( Надеюсь, я правильно помню, прошло много времени с тех пор, как я был вынужден использовать VB.)

1
ответ дан 8 December 2019 в 13:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: