Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Статическое подключение dll


Автор: Norfonzor 23.12.2009, 20:18
New -> other -> DllWizard
код длл:
Код

library mydll;

uses
  SysUtils,
  Classes;
const n=100;
{$R *.res}

function Prostoe4islo(n: integer):boolean; stdcall;
var
ok:boolean;

i,j:integer;

begin
ok:=true;
if (n<=0)or(n=2) then ok:=false;


if n>=3 then
for i:=2 to (n-1) do
begin
if round(n/i)-(n/i)=0 then ok:=false;
end;

if ok=false then result:=false else result:=true;
end;

{Директива exports указывает, какие функции будут экспортированы этой DLL}
exports Prostoe4islo;

begin
end.


нажимаю F9
вылазит:user posted image
Dll создается

далее close

new aplication
код:
Код

program MainWindow;

uses
  Windows,
  Messages,
  SysUtils;

const
  id_Button = 1;
  id_Edit = 2;




function prostoe4islo(n:integer):boolean; stdcall; external 'MYDLL.DLL';


function PlainWinProc (hWnd: THandle; nMsg: UINT;
  wParam, lParam: Cardinal): Cardinal; export; stdcall;
var
  Rect: TRect;
  s1, s2, s_c: array [0..127] of Char;
  n1, n2:integer;


begin

  Result := 0;
  case nMsg of
    wm_Create:
      begin

      GetClientRect (hWnd, Rect);

      CreateWindowEx (0,
                      'button',
                      '&OK',
                       ws_Child or ws_Visible or ws_Border or bs_PushButton,
                       Rect.Left + 120, Rect.Top + 10,
                       100, 20,
                       hwnd,
                       id_Button,
                       hInstance,
                       nil);

       CreateWindowEx (0,
                      'Edit',
                       '',
                       ws_Child or ws_Visible or ws_Border or es_Number,
                       Rect.Left + 10, Rect.Top + 10,
                       100, 20,
                       hwnd,
                       id_Edit,
                       hInstance,
                       nil);
       SetWindowText(GetDlgItem (hWnd, id_Edit),'0');
       end;
   wm_Command:
   begin
      if LoWord (wParam) = id_Button then
        if HiWord (wParam) = bn_Clicked then
          begin
            GetWindowText(GetDlgItem (hWnd, id_Edit), s1, GetWindowTextLength(GetDlgItem (hWnd, id_Edit))+1);
            //MessageBox (hWnd, '', 'Ðåçóëüòàò', MB_OK)

            if Prostoe4islo(strtoint(s1))then MessageBox (hWnd, 'Простое!', 'Результат', MB_OK);
           end;
   end;
    wm_Destroy:
      PostQuitMessage (0);
    else
      Result := DefWindowProc (hWnd, nMsg, wParam, lParam);
  end;
end;

procedure WinMain;
var
  hWnd: THandle;
  Msg: TMsg;
  WndClassEx: TWndClassEx;
begin

  WndClassEx.cbSize := sizeOf (TWndClassEx);
  WndClassEx.lpszClassName := 'PlainWindow';
  WndClassEx.style := cs_VRedraw or cs_HRedraw;
  WndClassEx.hInstance := HInstance;
  WndClassEx.lpfnWndProc := @PlainWinProc;
  WndClassEx.cbClsExtra := 0;
  WndClassEx.cbWndExtra := 0;
  WndClassEx.hIcon := LoadIcon (hInstance,
    MakeIntResource ('MAINICON'));
  WndClassEx.hIconSm  := LoadIcon (hInstance,
    MakeIntResource ('MAINICON'));
  WndClassEx.hCursor := LoadCursor (0, idc_Arrow);;
  WndClassEx.hbrBackground := GetStockObject (white_Brush);
  WndClassEx.lpszMenuName := nil;

  if RegisterClassEx (WndClassEx) = 0 then
    MessageBox (0, 'Invalid class registration',
      'Plain API', MB_OK)
  else
  begin
    hWnd := CreateWindowEx (
      WS_SIZEBOX,
      WndClassEx.lpszClassName,
      'Ïóñòîå îêíî',
      ws_OverlappedWindow,
      cw_UseDefault, cw_UseDefault,
      240, 300,
      0,
      0,
      HInstance,
      nil);
    if hWnd = 0 then
      MessageBox (0, 'Window not created',
        'Plain API', MB_OK)
    else
    begin
      ShowWindow (hWnd, sw_ShowNormal);
      while GetMessage (Msg, 0, 0, 0) do
      begin
        TranslateMessage (Msg);
        DispatchMessage (Msg);
      end;
    end;
  end;
end;

begin
  WinMain;
end.



подключаю длл статически через:

Код

function prostoe4islo(n:integer):boolean; stdcall; external 'MYDLL.DLL';


и вызываю ф-ию через: 
Код

 if Prostoe4islo(strtoint(s1))then MessageBox (hWnd, 'Простое!', 'Результат', MB_OK);


вылазит:
user posted image

Сломал голову, в чем ошибка?
Да еще если стереть строчку 
Код

if Prostoe4islo(strtoint(s1))then MessageBox (hWnd, 'Простое!', 'Результат', MB_OK);
 то прога комплитица

Сейчас попробую еще подключить динамически. 

Динамически:
Код длл такойже

Мэйн:
Код

program MainWindowsDin;

uses
  Windows,
  Messages,
  SysUtils;

const
  id_Button = 1;
  id_Edit = 2;



function PlainWinProc (hWnd: THandle; nMsg: UINT;
  wParam, lParam: Cardinal): Cardinal; export; stdcall;
var
  Rect: TRect;
  s1, s2, s_c: array [0..127] of Char;
  n1, n2:integer;
  prostoe4islo: function(n:integer):boolean;
  LibHandle: THandle;

begin

  Result := 0;
  case nMsg of
    wm_Create:
      begin

      GetClientRect (hWnd, Rect);

      CreateWindowEx (0,
                      'button',
                      '&OK',
                       ws_Child or ws_Visible or ws_Border or bs_PushButton,
                       Rect.Left + 120, Rect.Top + 10,
                       100, 20,
                       hwnd,
                       id_Button,
                       hInstance,
                       nil);

       CreateWindowEx (0,
                      'Edit',
                       '',
                       ws_Child or ws_Visible or ws_Border or es_Number,
                       Rect.Left + 10, Rect.Top + 10,
                       100, 20,
                       hwnd,
                       id_Edit,
                       hInstance,
                       nil);
       SetWindowText(GetDlgItem (hWnd, id_Edit),'0');
       end;
   wm_Command:
   begin
      if LoWord (wParam) = id_Button then
        if HiWord (wParam) = bn_Clicked then
          begin
            GetWindowText(GetDlgItem (hWnd, id_Edit), s1, GetWindowTextLength(GetDlgItem (hWnd, id_Edit))+1);


            //MessageBox (hWnd, '', 'Результат', MB_OK)

            @Prostoe4islo := nil;
            LibHandle := LoadLibrary('MYDLL.DLL');
            {Если все OK}
            if LibHandle <= 32 then MessageBox (hWnd, 'Ошибка 1', 'ошибка', MB_OK);

            @Prostoe4islo := GetProcAddress(LibHandle,'Prostoe4islo');
            {Если и здесь все OK}
            if @Prostoe4islo <> nil then
            begin
            {...то вызываем эту функцию и показываем результат}

            if Prostoe4islo(strtoint(s1)) then MessageBox (hWnd, 'Число простое!', 'Результат', MB_OK) else
            MessageBox (hWnd, 'Число НЕ простое!', 'Результат', MB_OK);
            end else MessageBox (hWnd, 'Ошибка 2', 'ошибка', MB_OK);

            FreeLibrary(LibHandle);

           end;
   end;
    wm_Destroy:
      PostQuitMessage (0);
    else
      Result := DefWindowProc (hWnd, nMsg, wParam, lParam);
  end;
end;

procedure WinMain;
var
  hWnd: THandle;
  Msg: TMsg;
  WndClassEx: TWndClassEx;
begin

  WndClassEx.cbSize := sizeOf (TWndClassEx);
  WndClassEx.lpszClassName := 'PlainWindow';
  WndClassEx.style := cs_VRedraw or cs_HRedraw;
  WndClassEx.hInstance := HInstance;
  WndClassEx.lpfnWndProc := @PlainWinProc;
  WndClassEx.cbClsExtra := 0;
  WndClassEx.cbWndExtra := 0;
  WndClassEx.hIcon := LoadIcon (hInstance,
    MakeIntResource ('MAINICON'));
  WndClassEx.hIconSm  := LoadIcon (hInstance,
    MakeIntResource ('MAINICON'));
  WndClassEx.hCursor := LoadCursor (0, idc_Arrow);;
  WndClassEx.hbrBackground := GetStockObject (white_Brush);
  WndClassEx.lpszMenuName := nil;

  if RegisterClassEx (WndClassEx) = 0 then
    MessageBox (0, 'Invalid class registration',
      'Plain API', MB_OK)
  else
  begin
    hWnd := CreateWindowEx (
      WS_SIZEBOX,
      WndClassEx.lpszClassName,
      'Пустое окно',
      ws_OverlappedWindow,
      cw_UseDefault, cw_UseDefault,
      240, 300,
      0,
      0,
      HInstance,
      nil);
    if hWnd = 0 then
      MessageBox (0, 'Window not created',
        'Plain API', MB_OK)
    else
    begin
      ShowWindow (hWnd, sw_ShowNormal);
      while GetMessage (Msg, 0, 0, 0) do
      begin
        TranslateMessage (Msg);
        DispatchMessage (Msg);
      end;
    end;
  end;
end;

begin
  WinMain;
end.



  объявляю длл и ф-ию:
Код

  prostoe4islo: function(n:integer):boolean;
  LibHandle: THandle;


подключаю длл через:
Код

           @Prostoe4islo := nil;
            LibHandle := LoadLibrary('MYDLL.DLL');
            if LibHandle <= 32 then MessageBox (hWnd, 'Ошибка 1', 'ошибка', MB_OK);
            @Prostoe4islo := GetProcAddress(LibHandle,'Prostoe4islo');
            if @Prostoe4islo <> nil then


обращаюсь к ф-ии
Код

          begin
            if Prostoe4islo(strtoint(s1)) then MessageBox (hWnd, 'Число простое!', 'Результат', MB_OK) else
            MessageBox (hWnd, 'Число НЕ простое!', 'Результат', MB_OK);
          end 
          else MessageBox (hWnd, 'Ошибка 2', 'ошибка', MB_OK);


отключаю длл
Код

FreeLibrary(LibHandle);


ошибок никаких не выдает, но ккаое бы число я не вписал то всегда ответ одинаковый:
'Число НЕ простое!'
код проверки числа на простоту проверял создав обычный проект, числа распознает.

в чем здесь косяк??

Автор: Alexeis 23.12.2009, 21:04
Можно попробовать так.
Код

function prostoe4islo(n:integer):boolean; stdcall; external 'MYDLL.DLL' name 'prostoe4islo';


Я бы для порядка посмотрел секцию экспорта у Dll и проверил есть ли там такая функция.

Автор: Norfonzor 23.12.2009, 21:21
Alexeis, 
изменил в MainWindow
Код

function prostoe4islo(n:integer):boolean; stdcall; external 'MYDLL.DLL';

на
Код

function prostoe4islo(n:integer):boolean; stdcall; external 'MYDLL.DLL' name 'prostoe4islo';


ошибка остается

а про проверить ф-ии в exports строчка 
Код

exports Prostoe4islo;

в Mydll присутствует. да еще при открытии длл через open project
вылазит ошибка: 
user posted image
но проект открывается, при закрытии спрашивает сохранить ли проект, спрашивает даже если код я не правил.

вот ссылка на проект мб станет понятно в чем проблема 
http://depositfiles.com/files/mq2c6gqn8

Автор: Alexeis 23.12.2009, 21:51
Norfonzor, лучше приатачьте саму dll, я гляну ее экспорт.

Автор: bems 23.12.2009, 21:56
Регистр не совпадает.
Ты экспортируешь с большой буквы, оно и ищется с большой.
Языку дельфи пофиг на регистр, но к системным функциям ищущим экспортируемый символ в длл в длл это не относится.
А ошибка про res-файл не имеет отношения, это другое.

Автор: Alexeis 23.12.2009, 21:59
Цитата(bems @  23.12.2009,  20:56 Найти цитируемый пост)
Регистр не совпадает.

Угу ток что проверил справку по GetProcAddress
Цитата

The spelling and case of a function name pointed to by lpProcName must be identical to that in the EXPORTS statement of the source DLL's module-definition (.def) file

Т.е. регистр имеет значение. Причем важен регистр именно тут
> name 'prostoe4islo';

Автор: Демо 23.12.2009, 22:07
Скопируй имя функции из её определения везде и снова попробуй.


Код

library mydll;

uses
  SysUtils,
  Classes;
const n=100;

function Prostoe4islo(n: integer):boolean; stdcall;
var
  i: Integer;
begin
  Result := (n<=0) or (n=2);

  if n>=3 then
  begin
    for i:=2 to (n-1) do
    begin
      if round(n/i)-(n/i)=0 then
      begin
        Result := False;
        Exit;
      end;
    end;
  end;
end;
exports Prostoe4islo;
begin
end.

Кстати у тебя лишние вычисления. Проверять деление нужно до (n div 2), и даже до квадратного корня из n.

Автор: bems 23.12.2009, 22:08
Цитата(Alexeis @  23.12.2009,  21:59 Найти цитируемый пост)
Т.е. регистр имеет значение. Причем важен регистр именно тут
> name 'prostoe4islo'; 

да, но если исправить раньше, то name 'prostoe4islo' можно и выкинуть

Автор: Alexeis 23.12.2009, 22:17
Цитата(bems @  23.12.2009,  21:08 Найти цитируемый пост)
да, но если исправить раньше, то name 'prostoe4islo' можно и выкинуть

  Но ИМХО лучше когда имя указано явно. Чисто для порядка. 

Автор: Norfonzor 24.12.2009, 21:33
Спасибо, большое, статическое подключение работает и ответ выдает правильный, а вот динамическое не хочет, всегда выдает что число не простое, даже вбивал на прямую в ф-ию простые числа, ф-ия возращает false всегда. здесь ошибка уже ведь не в длл. Имя ф-ии везде изменил с маленькой буквы.

Автор: bems 24.12.2009, 21:39
Цитата(Norfonzor @  23.12.2009,  20:18 Найти цитируемый пост)
if LibHandle <= 32 then MessageBox (hWnd, 'Ошибка 1', 'ошибка', MB_OK);
Проверяй на равенство нулю. Если не 0, то всегда будет значительно больше тридцати двух. 

А про неверный результат:
Цитата(Norfonzor @  23.12.2009,  20:18 Найти цитируемый пост)
prostoe4islo: function(n:integer):boolean;

Цитата(Norfonzor @  23.12.2009,  20:18 Найти цитируемый пост)
function Prostoe4islo(n: integer):boolean; stdcall;
Найди одно отличие

Автор: Alexeis 24.12.2009, 22:51
  На всякий случай поясню stdcall определяет метод передачи параметров и возвращения результата, именно поэтому функция возвращала неверный результат.

Автор: Norfonzor 25.12.2009, 08:32
 smile  Работает! bems и Alexeis, спасибо огромное! мог бы поставить плюсы, поставил!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)