FreeBasic
Главная
Вход
Регистрация
Воскресенье, 25.01.2026, 22:39Приветствую Вас Гость | RSS
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 2
  • 1
  • 2
  • »
Корректен ли хедер?
DarkDemonДата: Понедельник, 19.01.2026, 19:05 | Сообщение # 1
Генерал-майор
Группа: Друзья
Сообщений: 285
Репутация: -1
Статус: Online
Хедер "win\vfw.bi".

Хотел портировать код, чтобы получать кадры с вебки, но хедер не заводится при подключении.
Обычно это означает что либо хедер просто порченный, либо что-то надо подключить дополнительно.

FBC 1.10.1 x64, винда.

А там как назло куча макросов, абстрагирование которых уходит корнями в бесконечность...


Сообщение отредактировал DarkDemon - Понедельник, 19.01.2026, 19:07
 
haavДата: Вторник, 20.01.2026, 06:07 | Сообщение # 2
Генералиссимус
Группа: Администраторы
Сообщений: 1448
Репутация: 50
Статус: Offline
Сложно судить без примера или ошибок компиляции. Я попробовал один из примеров с vfw.bi , запустился.

Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
DarkDemonДата: Вторник, 20.01.2026, 07:42 | Сообщение # 3
Генерал-майор
Группа: Друзья
Сообщений: 285
Репутация: -1
Статус: Online
Пример вот отсюда:
https://www.freebasic-portal.de/code-be....46.html

Код:

Код
' Grab_webcam.bas by Volta
' auf FB020 nur unter ME getestet!
#INCLUDE ONCE "win\vfw.bi" 'die vfw.bi includet die windows.bi

DECLARE SUB CamCap_init
DECLARE SUB CamCap_off (i AS INTEGER= 1)
DECLARE FUNCTION GRAB_FRAME2Image(BYVAL hWin AS INTEGER _
,            BYVAL lpHeader AS VIDEOHDR PTR) AS INTEGER

TYPE RGB32 FIELD = 1
  AS BYTE b,g,r,a
END TYPE

DIM SHARED AS INTEGER cam_breite, cam_hoehe, CamPosX, CamPosY
DIM SHARED AS INTEGER PTR cap_image
DIM SHARED AS HWND hCapture
DIM SHARED AS BITMAPINFOHEADER biheader

DIM ik AS STRING
SCREEN 18,32
CamPosX=0
CamPosY=19
CamCap_init
SCREENRES cam_breite,cam_hoehe+20,32
WIDTH cam_breite\8,(cam_hoehe+20)\16
cap_image = IMAGECREATE(cam_breite,cam_hoehe)
DO
  LOCATE 1,2 : ? TIME
  capGrabFrame(hCapture)
  SCREENLOCK
  PUT (CamPosX,CamPosY),cap_image,PSET
  SCREENUNLOCK
  SLEEP 1
  Ik = INKEY
LOOP UNTIL Ik = CHR(3) OR Ik = CHR(27) OR Ik = CHR(255,107)

CamCap_off 0
END

FUNCTION GRAB_FRAME2Image(BYVAL hWin AS INTEGER _
  ,  BYVAL lpHeader AS VIDEOHDR PTR) AS INTEGER
  DIM AS INTEGER picsize, zeile, x, y, j
  DIM AS RGB32 PTR lpScreen
  picsize = lpHeader->dwBytesUsed\3
  IF picsize = cam_breite * cam_hoehe THEN
    'Byte für Byte in das Image schaufeln
    zeile = cam_breite * (cam_hoehe-1)
    lpScreen = CPTR(RGB32 PTR,(cap_image))+8
    FOR y = 0 TO cam_hoehe-1
      FOR x = 0 TO cam_breite-1
        lpScreen[zeile+x].b = lpHeader->lpData
        [j]lpScreen[zeile+x].g = lpHeader->lpData[j+1]
        lpScreen[zeile+x].r = lpHeader->lpData[j+2]
        j+ = 3
      NEXT
      zeile -= cam_breite
    NEXT
  ELSE
    RETURN 0
  END IF
  RETURN 1
END FUNCTION

SUB CamCap_off (i AS INTEGER)
  capDriverDisconnect(hCapture)
  IF cap_image<>0 THEN IMAGEDESTROY cap_image
  IF i THEN SLEEP
  END
END SUB

SUB CamCap_init
  hCapture = capCreateCaptureWindow(@"Voltas Grab_Cam_Picture" _
  , &H40000000, 0, 0, 0, 0, FindWindow(0, 0), 0)
  IF hCapture = 0 THEN
    ? "error: can't create capture window !"
    CamCap_off 1
  END IF

  IF capDriverConnect(hCapture, 0) <> 1 THEN 'für die erste WebCam,
    '          sonst (hCapture, n) n =1,2,3 ...
    ? "error: can't connect the driver !"
    CamCap_off 1
  END IF

  capGetVideoFormat(hCapture, @biHeader, SIZEOF(BITMAPINFOHEADER))
  IF (biHeader.biCompression <> 0) THEN
    ?"error: sorry this example needs RGB format!"
    CamCap_off 1
  END IF

  cam_breite = biHeader.biWidth
  cam_hoehe = biHeader.biHeight
  capSetCallbackOnFrame(hCapture, @GRAB_FRAME2Image)
END SUB


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

Проблема в том, что просто подключение vfw.bi уже даёт ошибки, что странно в другом хедере в mmsystem.bi.
И фраза от компилятора "Too many errors, exiting" говорит о том, что это не 1 ошибка, а неперелопачиваемое кол-во.

При подключении перед ним "windows.bi" появляется 6 ошибок вида

Код
D:\Programs\FreeBasics\FreeBasic\FBC\inc\win\vfw.bi(1742) error 59: Illegal specification, at parameter 1 (lpofn) of GetOpenFileNamePreviewA() in 'declare function GetOpenFileNamePreviewA(byval lpofn as LPOPENFILENAMEA) as WINBOOL'


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

Код
#define AVICapSM(hwnd, m, w, l) iif(IsWindow(hwnd), SendMessage(hwnd, m, w, l), 0)

Для этого я нашёл код на делфе:

https://drkb.ru/multimedia/audio/extract_track/ed7dcb6994c641e4

Там функции capDriverConnect, capGetVideoFormat, capSetCallbackOnFrame выполнены понятным языком:

Код
'function    capDriverConnect(hwnd: HWND; i: INT): BOOL;
'begin
'    Result  := AVICapSM(hwnd, WM_CAP_DRIVER_CONNECT, i, 0) <> 0;
'end;

'function    capGetVideoFormat(hwnd: HWND; s: PVOID; wSize: WORD): DWORD;
'begin
'    Result  := AVICapSM(hwnd, WM_CAP_GET_VIDEOFORMAT, wSize, LPARAM(s));
'end;


Это по итогу превращается во что-то типа:

Код
 FUNCTION capDriverConnect(hwnd AS HWND, i AS INTEGER) AS BOOLEAN

    IF IsWindow(hwnd) <> 0 THEN
      SendMessage(hwnd, WM_CAP_DRIVER_CONNECT, i, 0)
    END IF

END FUNCTION


И если честно, я не знаю хватит ли мне терпения сделать даже это, т.к. на каждую, сука, переменную надо лезть в хедер,
смотреть тип, а там один тип ссылается на другой тип и другой на третий и всё в разных хедерах. Короче п.....ц...
Но я хочу убрать ужасающие портянки CAST-ов... те, что нагородили в хедере FB, это ужас просто...

И это ситуация "без прекрас", реально чем приходится заниматься человеку на FB... причём постоянно на это напарываюсь 99%
возьни именно с этим.


Сообщение отредактировал DarkDemon - Вторник, 20.01.2026, 07:47
 
haavДата: Вторник, 20.01.2026, 08:29 | Сообщение # 4
Генералиссимус
Группа: Администраторы
Сообщений: 1448
Репутация: 50
Статус: Offline
Цитата
Illegal specification, at parameter 1 (lpofn) of GetOpenFileNamePreviewA()


не хватает хедера: commdlg.bi

попробуй вначале записать эти хедеры:

Код
#INCLUDE ONCE "windows.bi"
#INCLUDE ONCE "win\commdlg.bi"
#INCLUDE ONCE "win\vfw.bi"


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
haavДата: Вторник, 20.01.2026, 09:00 | Сообщение # 5
Генералиссимус
Группа: Администраторы
Сообщений: 1448
Репутация: 50
Статус: Offline
Вот компилируется и запускается.
Изучать дальше лень. Так что , правильно или неправильно работает , не знаю.

Код
#include once "windows.bi"
#include once "win\commdlg.bi"
#INCLUDE ONCE "win\vfw.bi"

DECLARE SUB CamCap_init
DECLARE SUB CamCap_off (i AS INTEGER= 1)
DECLARE FUNCTION GRAB_FRAME2Image(BYVAL hWin AS INTEGER _
,            BYVAL lpHeader AS VIDEOHDR PTR) AS INTEGER

TYPE RGB32 FIELD = 1
  AS BYTE b,g,r,a
END TYPE

DIM SHARED AS INTEGER cam_breite, cam_hoehe, CamPosX, CamPosY
DIM SHARED AS INTEGER PTR cap_image
DIM SHARED AS HWND hCapture
DIM SHARED AS BITMAPINFOHEADER biheader

DIM ik AS STRING
SCREEN 18,32
CamPosX=0
CamPosY=19
CamCap_init
SCREENRES cam_breite,cam_hoehe+20,32
WIDTH cam_breite\8,(cam_hoehe+20)\16
cap_image = IMAGECREATE(cam_breite,cam_hoehe)
DO
  LOCATE 1,2 : ? TIME
  dim as WinBOOL wRes = capGrabFrame(hCapture)
  SCREENLOCK
  PUT (CamPosX,CamPosY),cap_image,PSET
  SCREENUNLOCK
  SLEEP 1
  Ik = INKEY
LOOP UNTIL Ik = CHR(3) OR Ik = CHR(27) OR Ik = CHR(255,107)

CamCap_off 0
END

FUNCTION GRAB_FRAME2Image(BYVAL hWin AS INTEGER _
  ,  BYVAL lpHeader AS VIDEOHDR PTR) AS INTEGER
  DIM AS INTEGER picsize, zeile, x, y, j
  DIM AS RGB32 PTR lpScreen
  picsize = lpHeader->dwBytesUsed\3
  IF picsize = cam_breite * cam_hoehe THEN
    
    zeile = cam_breite * (cam_hoehe-1)
    lpScreen = CPTR(RGB32 PTR,(cap_image))+8
    FOR y = 0 TO cam_hoehe-1
      FOR x = 0 TO cam_breite-1
        lpScreen[zeile+x].b = lpHeader->lpData[j]
        lpScreen[zeile+x].g = lpHeader->lpData[j+1]
        lpScreen[zeile+x].r = lpHeader->lpData[j+2]
        j+ = 3
      NEXT
      zeile -= cam_breite
    NEXT
  ELSE
    RETURN 0
  END IF
  RETURN 1
END FUNCTION

SUB CamCap_off (i AS INTEGER)
  dim as WinBOOL wRes = capDriverDisconnect(hCapture)
  IF cap_image<>0 THEN IMAGEDESTROY cap_image
  IF i THEN SLEEP
  END
END SUB

SUB CamCap_init
  hCapture = capCreateCaptureWindow(@"Voltas Grab_Cam_Picture" _
  , &H40000000, 0, 0, 0, 0, FindWindow(0, 0), 0)
  IF hCapture = 0 THEN
    ? "error: can't create capture window !"
    CamCap_off 1
  END IF

  IF capDriverConnect(hCapture, 0) <> 1 THEN
    
    ? "error: can't connect the driver !"
    CamCap_off 1
  END IF

  dim as WinBOOL wRes = capGetVideoFormat(hCapture, @biHeader, SIZEOF(BITMAPINFOHEADER))
  IF (biHeader.biCompression <> 0) THEN
    ?"error: sorry this example needs RGB format!"
    CamCap_off 1
  END IF

  cam_breite = biHeader.biWidth
  cam_hoehe = biHeader.biHeight
  wRes = capSetCallbackOnFrame(hCapture, @GRAB_FRAME2Image)
END SUB


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
DarkDemonДата: Вторник, 20.01.2026, 09:43 | Сообщение # 6
Генерал-майор
Группа: Друзья
Сообщений: 285
Репутация: -1
Статус: Online
Код
попробуй вначале записать эти хедеры:

А где можно подсмотреть зависимости всех хедеров? Это спрашиваю чтобы не создавать в будущем подобных тем.
Или это где-то есть в windows.bi?

Добавлено (20.01.2026, 09:48)
---------------------------------------------

Код
Так что , правильно или неправильно работает , не знаю.

По идее реботает, просто моя вебка не поддерживает необходимый формат и прога пишет "sorry this example needs RGB format!"
 
haavДата: Вторник, 20.01.2026, 10:16 | Сообщение # 7
Генералиссимус
Группа: Администраторы
Сообщений: 1448
Репутация: 50
Статус: Offline
Так увидел функцию или константу , которую не может распознать компилятор , сразу ищи ее в хедере. Как найдешь , подключай нужный хедер , или вытаскивай ее определение оттуда. Если нет такой функции , то искать в MSDN и декларировать вручную.

Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
DarkDemonДата: Вторник, 20.01.2026, 11:32 | Сообщение # 8
Генерал-майор
Группа: Друзья
Сообщений: 285
Репутация: -1
Статус: Online
Понятно, спасибо!
 
zamabuvaraeuДата: Среда, 21.01.2026, 07:04 | Сообщение # 9
Полковник
Группа: Друзья
Сообщений: 186
Репутация: 5
Статус: Offline
Виндовые заголовочники требуют подключить "windows.bi". Если кто‐то говорит что это не так — не верьте. Всегда на первое место ставьте "windows.bi". Перед всякими "win\что‐то там" необходимо указывать "windows.bi".
 
DarkDemonДата: Среда, 21.01.2026, 09:42 | Сообщение # 10
Генерал-майор
Группа: Друзья
Сообщений: 285
Репутация: -1
Статус: Online
Цитата zamabuvaraeu ()
Виндовые заголовочники требуют подключить "windows.bi". Если кто‐то говорит что это не так — не верьте. Всегда на первое место ставьте "windows.bi". Перед всякими "win\что‐то там" необходимо указывать "windows.bi".

Да Windows.bi то понятно зачем, когда про него говорил это была цель консолидации с другими
программами, которые его явно требуют(большинство), нечасто пытаюсь уйти от его использования.
Так то вижу функции в коде, которые вызываются.

Вебку кстати завёл, но работает всё это дело как говно. У моей вебки есть своя менюшка настроек,
т.е. она даже с дефолтным драйвером винды есть. Вот такая:



И что забавно, когда использую OBS - всё нормально, эти настройки сохраняются в системе, НО
после запуска моей проги, эти настройки сбрасываются. Наверное чего-то не знаю, буду колупать
дальше. Коллбеки работают крайне странно и скорее не работают, поэтому пример с немецкого
сайта после тестов могу смело назвать нерабочим на моей вебке, т.к. коллбек там попросту не
будет вызываться(ему нужны какие-то доп команды и настройки вне коллбека, ещё пишут что надо
внутри коллбека обрабатывать сообщения через PeekMessage\TranslateMessage\DispatchMessage что
надо сказать - очень странно), а я хотел использовать FBGfx у которого свой обработчик, который сам
начинает это всё делать(из-за того что ему приходится создавать окно и он полагает, что оно основное,
т.е. даёт на него фокус) и ну вы понимаете.
Нормальных советов и исходников нигде нет, переколупал десятки ресурсов. Короче полный каламбур
и веселуха.
Люди пишут что надо делать через DirectShow, а я туда точно не полезу, думал простыми средствами
получится. Хотя все другие исходники которые видел - в них используются все те же функции.

Ну и бонусом, ради веселья тестирую новую идеологию поэтапной инициализации, SELECT CASE внутри DO,
выходит интересно, т.е. вместо портянок IF-ELSE или самопальных функций контроля ошибки имеем
чёткую цепь действий.

Добавлено (21.01.2026, 10:12)
---------------------------------------------
Если что, советов пока не прошу, сейчас есть азарт расколупать это дело самостоятельно по манам, тестам и документации.
Это так, скорее побурчать, создать движуху.
К сожалению, вебка у меня всего одна и довольно голимая, что, разумеется, не даёт никакой полной картины тест кейзов.

Прикрепления: 7802515.png (21.0 Kb)
 
zamabuvaraeuДата: Среда, 21.01.2026, 18:42 | Сообщение # 11
Полковник
Группа: Друзья
Сообщений: 186
Репутация: 5
Статус: Offline

Цитата
Ну и бонусом, ради веселья тестирую новую идеологию поэтапной инициализации, SELECT CASE внутри DO,
выходит интересно, т.е. вместо портянок IF-ELSE или самопальных функций контроля ошибки имеем
чёткую цепь действий.
А вот это подробнее, пожалуйста
 
DarkDemonДата: Четверг, 22.01.2026, 11:54 | Сообщение # 12
Генерал-майор
Группа: Друзья
Сообщений: 285
Репутация: -1
Статус: Online
Цитата zamabuvaraeu ()
А вот это подробнее, пожалуйста

Вкратце:

Код
InitStage = 1
LastStage = 3

  DO
   '  Шаги инициализации
   SELECT CASE  InitStage
     '  Деинициализация устройства\модуля при неудаче
     '  И рестарт инициализации
     CASE 0
        Try = Try + 1                    '  Кол-во попыток
        IF Try = MaxTry THEN EXIT DO     '  Выход если все попытки сделали
        InitStage = 1

     '  Шаги инициализации
     CASE 1
     CASE 2
     CASE 3
   END SELECT
   '  Следующий шаг
   IF InitStage > 0 THEN InitStage += 1

  LOOP UNTIL InitStage > LastStage

Где-то видел что люди заводят процедуру, внутри неё проверка на ошибку и END. Ставят её после каждого
шага, это подход грубый, чаще всего завершать прогу нельзя, надо чтобы она работала "сквозь" любые ошибки.
Поэтому неудачный инит должен быть сопровождён деинициализацией и уничтожением заведённых ресурсов.
Другие используют GOTO чтобы отпрыгивать в конец для деиниц ресурсов. Тоже его использовал до поры до
времени, но портянки проверок IF, отступами двигающиеся вправо и выходящие за экран - задирают.
А тут пришла идея организовать всё в CASE-ы, структурно. В любой момент можно выпрыгнуть из инита через
EXIT DO и с шага инита через EXIT SELECT, кол-во попыток контролируется сразу после деиниц в одном из первых
CASE-ов. Логику после CASE-a можно усложнить, если шагов деинициализации больше одного(нет смысла этим
заниматься в коде сразу после неудачного шага инициализации).

В общем это небольшой апгрейд своего стиля кодирования. Не знаю полезен ли он кому-то. Т.к. пишу сугубо на 3GL
то мне это принесёт небольшой профит. Кода станет немного меньше(из-за компактности организации данной логики),
и всё будет +/- структурно, возможно возрастёт читаемость при вбивании себе в голову этого шаблона.


Сообщение отредактировал DarkDemon - Четверг, 22.01.2026, 11:58
 
sashasoldДата: Пятница, 23.01.2026, 16:53 | Сообщение # 13
Лейтенант
Группа: Пользователи
Сообщений: 50
Репутация: 0
Статус: Offline
насколько я помню, для того чтобы правильно завершалась программа, из любого места, есть Sub Destructor. Который выполняется перед закрытием программы.
Я не сталкивался, но часто мелькает про утечку памяти и ресурсов. Вот вписываем туда закрытие файлов, сохранение чего надо, и освобождение ресурсов.
Тогда должно срабатывать и от End в любом месте.

Добавлено (23.01.2026, 16:54)
---------------------------------------------
А по поводу программы для Вебки, я искал в инете, потом уже думал код найти, ни то не другое не помогло.
самая простая функция а как оказалось фиг свищи, моя камера не работала как надо от сторонних утилиток, с родной logitec проблемы были какие. Даже забросил затею с вебкой.
Итог со временем увидел возможность в OBS, мощная штука все работает.

А хотел просто записывать видео с камеры на ПК. Требуется сохранение в h.264, а лучше h.265 (возможно с некоторыми настройками качества сжатия).
Если сможешь доделать до этого состояния буду рад.

 
DarkDemonДата: Пятница, 23.01.2026, 18:13 | Сообщение # 14
Генерал-майор
Группа: Друзья
Сообщений: 285
Репутация: -1
Статус: Online
Код
Sub Destructor.

Не использую ООП принципиально. Предпочитаю всё контролить руками.

Цитата sashasold ()
Требуется сохранение в h.264, а лучше h.265

Давным давно Стас бросал код, где через OpenGL рендерился треугольник, который потом захватывался и сохранялся
в любой формат(там выплывал стандартный диалог кодеков винды). Так вот отдельно я видел как минимум XVid кодеки,
но по сути можно найти любые и использовать тот код, в т.ч. h264\h265. Код был исключительно сложный, колупать долго,
но при сильном желании расколупать можно.

Вебку расколупал. Но повторюсь, работает как говно. А про нюансы расскажу:

Во-первых, окно создающееся через capCreateCaptureWindow. Требует обработчик очереди сообщений, иначе нихрена
ничего не работает.

Во-вторых, последовательность для превью:
capCreateCaptureWindow
capDriverConnect
capPreviewRate
capPreview

дальше цикл.

В-трьетих, блочит к хренам всё(осн. цикл), поэтому строго вешать на отдельный поток. Однако хорошие новости - ЦП при этом
не жрёт, т.е. взаимодействие с шиной корректное, поэтому отдельный поток - нормальное решение.

В-четвёртых: грабить кадр можно через capGrabFrame, потом capEditCopy (в буфер обмена), а оттуда уже получаем через
GetClipboardData(CF_DIB). В интернете это всё ищется.

В-пятых: есть чек того, какие системные меню настроек оно поддерживает и тут есть дерьмо. То меню что я выше показывал
из OBS - является системным, при вызове capDlgVideoSource появляется что-то схожее, немного отличающееся, но нихрена
не оказывающее влияние на работу вебки. Тут я пока не расколупал. Сколько не гуглил, инфы по этой функции - ноль.
Моя вебка через OBS работает нормально, до 30 к/с, самопальной прогой - кадров 5-6. Дерьмовое дело!
Говорят надо DirectShow - но там сущий геморрой, какие-то графы эффектов и прочая дрисня, к тому же это е**чий COM,
поэтому лезть туда - исключительно себе дороже. С COM мне хватает колупания с дизасмом на x64, там очень весело, особенно
со стеком...

Для записи и стримов OBS является идеальным вариантом. Встаёт вопрос зачем оно мне.
Так вот прошерщивая интернет я нифига не нашёл нормального аналога Net Speakerphone. Сам спикер мне не совсем нравится,
и если бы у меня было всё необходимое, то попробовал бы написать нормальный аналог, прям максимально простой без идиотии.
В свете последних событий - довольно актуально. Скоро такой варик связи со своей семьёй в другом городе может остаться
чуть ли не единственным. Но рвать жопу разумеется не буду, всё делается тихо спокойно да и вообще если прогресс с девайсами
пойдёт.
 
zamabuvaraeuДата: Суббота, Вчера, 10:36 | Сообщение # 15
Полковник
Группа: Друзья
Сообщений: 186
Репутация: 5
Статус: Offline
Тогда проще через For всё делать:


Код
Function Initialize() As Boolean

   Dim CurrentStep As Integer
   
   For i As Integer = 0 To InitStepsMaximum
      Select Case i
         Case 0
            ' создать память
            p = Allocate(...)
            
            If p = 0 Then
               ' ошибка
               CurrentStep = i
               Exit For
            End If
         Case 1
            ' Создать Handle
            h = CreateEvent(NULL, TRUE, FALSE, NULL)
            
            If h = NULL Then
               ' ошибка
               CurrentStep = i
               Exit For
            End If
         Case 2
            ' создать окно
            w = CreateWindowEx(...)
            
            If w = NULL Then
               ' ошибка
               CurrentStep = i
               Exit For
            End If
         Case 3
            ' создать файл
            f = CreateFile(...)
            
            If f = INVALID_HANDLE_VALUE Then
               ' ошибка
               CurrentStep = i
               Exit For
            End If
         Case Else
            ' Инициализация пройдена
            ' возвращаем успех
            Return True
      End Select
   Next

   ' Очистка в обратном порядке:
   For i As Integer = CurrentStep - 1 To 0 Step -1
      Select Case i
         Case 2
            ' удалить окно
            DestroyWindow(w)
         Case 1
            ' Удалить HANDLE
            CloseHandle(h)
         Case 0
            ' Уничтожить память
            Deallocate(p)
      End Select
   Next

   ' Ошибка
   Return False

End Function


Пример можно доработать для возвращения не только True|False, но и определённого кода ошибки через GetLastError().
Вместо единичек, двоек и троек лучше бы ввести именованные константы INITSTAGE_MEMORY, INITSTAGE_WINDOW или INITSTAGE_FILE, чтобы понятно было из текста какой сейчас шаг инициализации (а не циферки запоминать).


Сообщение отредактировал zamabuvaraeu - Суббота, 24.01.2026, 10:42
 
  • Страница 1 из 2
  • 1
  • 2
  • »
Поиск: