Lazarus и DDEML

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Lazarus и DDEML

Сообщение delete » 07.09.2011 10:28:54

Подскажите, где я накосячил с памятью?

Портировал почти дефолтный пример по работе с DDEML из Visual C++ на Lazarus, с оглядкой на Delphi и вот, что в итоге получилось:

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

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,
  SysUtils,
  Windows;

{$R *.res}

const
  DMLERR_NO_ERROR = 0;
  APPCMD_CLIENTONLY = 10;

var
  idInst: DWORD;

function DdeConnect(_para1:DWORD; _para2:HSZ; _para3:HSZ;_para4:PCONVCONTEXT ):HCONV; external 'user32' name 'DdeConnect';

function DdeCallback(CallType, Fmt: UINT; Conv: HConv; hsz1, hsz2: HSZ;
    Data: HDDEData; Data1, Data2: DWORD): HDDEData stdcall;
begin
  Result := 0
end;

function GetUrlBrowser(NameBrowser: String): String stdcall;
var
iReturn: DWORD;
hszApp, hszTopic, hszItem: HSZ;
hCnv: DWORD;
hData: HDDEDATA;
Buf: String[255];
begin
  Result := '';
  idInst := 0;
  iReturn := DdeInitialize(@idInst, @DdeCallback, APPCMD_CLIENTONLY, 0);
  if iReturn = DMLERR_NO_ERROR then
  begin
    //DDE Connect to Server using given AppName and topic.
    hszTopic := 0;
    hszApp := 0;
    hCnv := 0;
    hszApp := DdeCreateStringHandle(idInst, 'FIREFOX', CP_WINANSI);
    hszTopic := DdeCreateStringHandle(idInst, 'WWW_GetWindowInfo', CP_WINANSI);
    hCnv := DdeConnect(idInst, hszApp, hszTopic, nil);
    DdeFreeStringHandle(idInst, hszApp);
    DdeFreeStringHandle(idInst, hszTopic);
    if hCnv <> 0 then
    begin
      hszItem := DdeCreateStringHandle(idInst, 'surl', CP_WINANSI);
      hData := DdeClientTransaction(nil, 0, hCnv, hszItem, CF_TEXT, XTYP_REQUEST, 5000, nil);
      if hData <> 0 then
      begin
        DdeGetData(hData, @Buf, 255, 0);
        //strcopy(Result, PChar(Buf));
        Result := Buf;
      end;
      //DDE Disconnect and Uninitialize.
      DdeDisconnect(hCnv);
    end;
    DdeUninitialize(idInst);
  end;
end;

var
  slChromeUrl: String;
  Process: String;

begin
    Process := 'firefox';
    slChromeUrl := GetUrlBrowser(Process);
    MessageBox(0, PChar(slChromeUrl), 'Caption', 0);
end.


Это должно работать, но программа валится с ошибкой SIGSEGV при возврате из функции GetUrlBrowser, причем если закомментировать строку hCnv := DdeConnect(idInst, hszApp, hszTopic, nil), то программа завершается нормально, но результат ее работы нулевой, естественно.

Правильно WideString использовать, поэтому с нее начинал, а потом уже стал с String мучаться, но эффект тот же самый. Может там с юникодом как-то надо работать? Я уже вообще не знаю, куда рыть. Уже все объявления функций из WinAPI перепроверил. Все правильно. Еще одна деталь: DdeConnect возвращает 0, но DDEGetLastError выдает DMLERR_NO_ERROR (скорее всего вообще ничего не выдает, а код остается после предыдущей функции).
delete
незнакомец
 
Сообщения: 5
Зарегистрирован: 07.09.2011 09:55:09

Re: Lazarus и DDEML

Сообщение Sergei I. Gorelkin » 07.09.2011 10:55:14

Функция DDEConnect должна иметь тип вызова stdcall.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1407
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Lazarus и DDEML

Сообщение delete » 07.09.2011 11:42:03

Хм. Спасибо за наводку. Прямо сейчас проверить не могу, потому что пробую пересобрать Lazarus с fpc 2.7.1 (хотя сильно сомневаюсь, что он взлетит при таком то количестве ошибок компиляции).

Посмотрел еще раз файл sourcertlwinwinincfunc.inc
Действительно, у некоторых функций имеется метка stdcall, а у других нет. Чем это определяется, какой функции нужна эта метка, а какой нет? Я довольно смутно помню, что связано это со стеком при вызове функций, но подробностей не могу вспомнить, хоть убейте.

Добавлено спустя 4 минуты 52 секунды:
Sergei I. Gorelkin писал(а):Функция DDEConnect должна иметь тип вызова stdcall.



Черт, вы гений! Спасибо огромное! Я же с утра сегодня мучаюсь с этой проблемой! А теперь все, как по маслу работает!
delete
незнакомец
 
Сообщения: 5
Зарегистрирован: 07.09.2011 09:55:09

Re: Lazarus и DDEML

Сообщение Vadim » 07.09.2011 12:45:21

delete писал(а):Чем это определяется, какой функции нужна эта метка, а какой нет?

stdcall определяет, в каком порядке в стеке расположены параметры вызываемой функции. А потом, после выполнения, кто чистит загаженный стек. stdcall должна быть у всех функций WinAPI без исключения. Иначе будет Содом и Гоморра. :)
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Lazarus и DDEML

Сообщение Sergei I. Gorelkin » 07.09.2011 13:59:27

Некоторые функции winapi имеют тип cdecl, например wsprintf, wvsprintf. Но таких всего несколько штук.

В исходниках модуля windows в начале есть директива {$calling stdcall}, задающая тип вызова по умолчанию. Поэтому повторение "stdcall" после каждой ф-ции там не нужно.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1407
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Lazarus и DDEML

Сообщение delete » 07.09.2011 16:10:47

Еще раз, спасибо. Очень познавательно!
delete
незнакомец
 
Сообщения: 5
Зарегистрирован: 07.09.2011 09:55:09

Re: Lazarus и DDEML

Сообщение Vadim » 08.09.2011 08:36:09

Sergei I. Gorelkin писал(а):В исходниках модуля windows в начале есть директива {$calling stdcall}, задающая тип вызова по умолчанию. Поэтому повторение "stdcall" после каждой ф-ции там не нужно.

У неё действие модулем Windows, похоже, и заканчивается, потому что товарищ объявил функцию DdeConnect в своём модуле и к нему сия директива не применилась. Вот как раз для этих случаев и надо к каждой функции WinAPI присоединять stdcall.
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Lazarus и DDEML

Сообщение delete » 08.09.2011 08:44:13

Vadim писал(а):Вот как раз для этих случаев и надо к каждой функции WinAPI присоединять stdcall.

Мне бы вообще в голову не пришло что-то переопределять, если бы в исходниках fpc эта функция была изначально правильно определена.
delete
незнакомец
 
Сообщения: 5
Зарегистрирован: 07.09.2011 09:55:09

Re: Lazarus и DDEML

Сообщение Vadim » 08.09.2011 09:01:01

delete писал(а):если бы в исходниках fpc эта функция была изначально правильно определена

Ну, всё, сейчас Павел расстроится. Это он её, лично, определял в исходниках. :)
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Lazarus и DDEML

Сообщение delete » 08.09.2011 21:27:23

Да, собственно, в svn уже все исправлено. Так что прогресс на лицо :) Да и не так уж сложно было зайти на msdn.com и посмотреть правильное определение. Вот только с stdcall я прокололся. Тут только моя вина.
delete
незнакомец
 
Сообщения: 5
Зарегистрирован: 07.09.2011 09:55:09


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 231

Рейтинг@Mail.ru