Delphi #IF эквивалентная (ОТЛАДКА)?

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

одно возможное решение передает дескриптор события в запрос ввода / вывода, и если мы получили ERROR_IO_PENDING - вызовите RegisterWaitForSingleObject для этого события. если этот вызов будет успешным - будет вызвана наша функция обратного вызова WaitOrTimerCallback - или потому что ввод / вывод будет завершен (с любым окончательным статусом) и в этот момент событие (которое мы передаем как I / Запрос O и RegisterWaitForSingleObject ) будут установлены или потому что истекло время ожидания ( dwMilliseconds ) - в этом случае нам нужно вызвать функцию CancelIoEx .

, так скажем, у нас есть class IO_IRP : public OVERLAPPED, у которого есть подсчет ссылок (нам нужно сохранить указатель на OVERLAPPED, используемый в запросе ввода-вывода для передачи его в CancelIoEx . уверен, что этот OVERLAPPED все еще не используется в другом новом вводе / выводе - поэтому еще не свободен). в этом случае возможна реализация:

class WaitTimeout
{
    IO_IRP* _Irp;
    HANDLE _hEvent, _WaitHandle, _hObject;

    static VOID CALLBACK WaitOrTimerCallback(
        __in  WaitTimeout* lpParameter,
        __in  BOOLEAN TimerOrWaitFired
        )
    {
        UnregisterWaitEx(lpParameter->_WaitHandle, NULL);

        if (TimerOrWaitFired)
        {
            // the lpOverlapped unique here (because we hold reference on it) - not used in any another I/O
            CancelIoEx(lpParameter->_hObject, lpParameter->_Irp);
        }

        delete lpParameter;
    }

    ~WaitTimeout()
    {
        if (_hEvent) CloseHandle(_hEvent);
        _Irp->Release();
    }

    WaitTimeout(IO_IRP* Irp, HANDLE hObject) : _hEvent(0), _Irp(Irp), _hObject(hObject)
    {
        Irp->AddRef();
    }

    BOOL Create(PHANDLE phEvent)
    {
        if (HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL))
        {
            *phEvent = hEvent;
            _hEvent = hEvent;

            return TRUE;
        }

        return FALSE;
    }
public:

    static WaitTimeout* Create(PHANDLE phEvent, IO_IRP* Irp, HANDLE hObject)
    {
        if (WaitTimeout* p = new WaitTimeout(Irp, hObject))
        {
            if (p->Create(phEvent))
            {
                return p;
            }

            delete p;
        }

        return NULL;
    }

    void Destroy()
    {
        delete this;
    }

    // can not access object after this call
    void SetTimeout(ULONG dwMilliseconds)
    {
        if (RegisterWaitForSingleObject(&_WaitHandle, _hEvent, 
            (WAITORTIMERCALLBACK)WaitOrTimerCallback, this, 
            dwMilliseconds, WT_EXECUTEONLYONCE|WT_EXECUTEINWAITTHREAD))
        {
            // WaitOrTimerCallback will be called
            // delete self here
            return ;
        }

        // fail register wait
        // just cancel i/o and delete self
        CancelIoEx(_hObject, _Irp);
        delete this;
    }
};

и использовать что-то вроде

if (IO_IRP* Irp = new IO_IRP(...))
{
    WaitTimeout* p = 0;

    if (dwMilliseconds)
    {
        if (!(p = WaitTimeout::Create(&Irp->hEvent, Irp, (HANDLE)socket)))
        {
            err = ERROR_NO_SYSTEM_RESOURCES;
        }
    }

    if (err == NOERROR)
    {
        DWORD dwBytes;

        err = ConnectEx(socket, RemoteAddress, RemoteAddressLength, 
            lpSendBuffer, dwSendDataLength, &dwBytes, Irp)) ?
                NOERROR : WSAGetLastError();
    }

    if (p)
    {
        if (err == ERROR_IO_PENDING)
        {
            p->SetTimeout(dwMilliseconds);
        }
        else
        {
            p->Destroy();
        }
    }

    Irp->CheckErrorCode(err);
}

другое возможное решение установить таймер через CreateTimerQueueTimer , а если таймер истек - позвоните [ 1112] или закройте ручку ввода-вывода отсюда. разница с решением события - если ввод / вывод будет завершен до истечения таймера - функция обратного вызова WaitOrTimerCallback не будет вызываться автоматически. в случае события - устанавливается событие подсистемы ввода / вывода, когда завершается ввод / вывод (после первоначального состояния ожидания) и благодаря этому (событие в состоянии сигнала) будет вызываться обратный вызов. но в случае таймера - ни в коем случае не передавать его в запрос io как параметр (I / O принимает только дескриптор события). В результате нам нужно сохранить указатель на объект таймера самостоятельно и вручную освободить его, когда завершится ввод-вывод. так что здесь будет 2 указателя на объект таймера - один из пула (сохраненный CreateTimerQueueTimer ) и один из нашего класса объекта (сокета) (он нам нужен для объекта разыменования после завершения ввода / вывода). это требует подсчета ссылок на объект, который тоже инкапсулирует таймер. с другой стороны, мы можем использовать таймер не для одной операции ввода-вывода, а для нескольких операций ввода-вывода (поскольку это не прямое связывание с некоторыми операциями ввода-вывода)

17
задан Boris Callens 29 September 2008 в 06:34
поделиться

4 ответа

Используйте это:

{$IFDEF DEBUG}
...
{$ENDIF}
28
ответ дан 30 November 2019 в 11:04
поделиться

Кроме того, какой сказанный lassevk, можно также использовать несколько других методов оценки компилятора (так как Delphi 6, я верю):

{$IF NOT DECLARED(SOME_SYMBOL)} 
  // Mind you : The NOT above is optional
{$ELSE}
{$IFEND}

, Чтобы проверить, имеет ли компилятор эту функцию, используйте:

 {$IFDEF CONDITIONALEXPRESSIONS}

существует несколько использования для этого.

, Например, Вы могли проверить версию RTL; От справки Delphi:

можно использовать RTLVersion в выражениях $IF для тестирования уровня версии библиотеки времени выполнения независимо от уровня версии компилятора.
Пример: {$IF RTLVersion> = 16.2}... {$IFEND}

кроме того, сама версия компилятора может быть проверена, снова из кода:

CompilerVersion присваивает значение компилятор, когда системная единица компилируется. Это указывает на уровень пересмотра функций компилятора / синтаксис языка, который может совершенствоваться независимо от RTLVersion. CompilerVersion может быть протестирован в выражениях $IF и должен использоваться вместо того, чтобы тестировать на условное выражение VERxxx, определяют. Всегда тестируйте на больший, чем или меньше, чем известный уровень пересмотра. Это - плохая идея протестировать на определенный уровень пересмотра.

Другая вещь, которую я регулярно делаю, определяют символ, когда она еще не определяется (хороший для вперед-compatiblity), как это:

 {$IF NOT DECLARED(UTF8String)}
 type
   UTF8String = type AnsiString;
 {$IFEND} 

Hope это помогает!

8
ответ дан 30 November 2019 в 11:04
поделиться

Эти директивы управления доступны:

{$IFDEF}
{$ELSE}
{$ENDIF}
{$IFNDEF} //if *not* defined

и они могут использоваться как показано здесь:

procedure TfrmMain.Button1Click(Sender: TObject);
begin
  {$IFDEF MY_CONDITIONAL}
  ShowMessage('my conditional IS defined!');
  {$ELSE}
  ShowMessage('my conditional is NOT defined!');
  {$ENDIF}

  {$IFNDEF MY_CONDITIONAL}
  ShowMessage('My conditional is explicitly NOT defined');
  {$ENDIF}
end;
3
ответ дан 30 November 2019 в 11:04
поделиться

DebugHook устанавливается, если приложение работает под отладчиком IDE. Не то же самое, что директива компилятора, но все же довольно полезная. Например:

ReportMemoryLeaksOnShutdown := DebugHook <> 0; // show memory leaks when debugging
6
ответ дан 30 November 2019 в 11:04
поделиться
Другие вопросы по тегам:

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