Копирование физического файла с диска в буфер обмена

Clarion, Clarion 7

Модератор: Дед Пахом

Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
NewUser
Старожил
Сообщения: 238
Зарегистрирован: 10 Ноябрь 2005, 23:07
Откуда: Краснодар
Благодарил (а): 6 раз

Копирование физического файла с диска в буфер обмена

Сообщение NewUser »

Привет всем!
Понадобилось помещать физический файл на диске в буфер обмена.
На форуме не нашел как это сделать.
Задал вопрос ИИ DeepSeek'у.
Получил его фантазии по этому поводу:

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

 PROGRAM

  MAP
    INCLUDE('CWINDOWS.INC')   ! Windows API константы и типы
    INCLUDE('CSHELL.INC')     ! Для Shell API (CF_HDROP)
  END

CopyFileToClipboard PROCEDURE(STRING filePath), BOOL
IsFileExists       PROCEDURE(STRING filePath), BOOL
  ! Объявление внешних Windows API функций
KERNEL32 API(GlobalAlloc), ULONG, DLL, NAME('GlobalAlloc'), RAW
           ULONG(uFlags), ULONG(dwBytes)
KERNEL32 API(GlobalLock), PTR, DLL, NAME('GlobalLock'), RAW
           ULONG(hMem)
KERNEL32 API(GlobalUnlock), BOOL, DLL, NAME('GlobalUnlock'), RAW
           ULONG(hMem)
KERNEL32 API(GlobalFree), ULONG, DLL, NAME('GlobalFree'), RAW
           ULONG(hMem)
USER32   API(OpenClipboard), BOOL, DLL, NAME('OpenClipboard'), RAW
           ULONG(hWndNewOwner)
USER32   API(EmptyClipboard), BOOL, DLL, NAME('EmptyClipboard'), RAW
USER32   API(SetClipboardData), PTR, DLL, NAME('SetClipboardData'), RAW
           ULONG(uFormat), ULONG(hMem)
USER32   API(CloseClipboard), BOOL, DLL, NAME('CloseClipboard'), RAW

  CODE
  ! Пример использования:
  filePath CSTRING(260) ! Максимальная длина пути в Windows
  filePath = 'C:\test\file.txt' ! Путь к файлу (можно ввести динамически)
  
  IF SELF.CopyFileToClipboard(filePath)
    MESSAGE('Файл скопирован в буфер обмена!')
  ELSE
    MESSAGE('Ошибка копирования файла в буфер обмена!')
  END

! Проверка существования файла
IsFileExists PROCEDURE(STRING filePath)
  CODE
  RETURN (GetFileAttributesA(filePath) <> 0FFFFFFFFh) ! INVALID_FILE_ATTRIBUTES

! Основная функция копирования файла в буфер обмена (ANSI-версия)
CopyFileToClipboard PROCEDURE(STRING filePath)
hMem        ULONG
pDropFiles  &DROPFILES
pFilePath   &CSTRING
filePathLen ULONG
dropFilesSize ULONG
success     BOOL(FALSE)
  CODE
  IF ~SELF.IsFileExists(filePath) THEN RETURN FALSE.

  ! Открываем буфер обмена
  IF ~API(OpenClipboard, 0) THEN RETURN FALSE.
  API(EmptyClipboard)

  ! Вычисляем размер данных (ANSI)
  filePathLen = LEN(CLIP(filePath)) + 1   ! +1 для нуль-терминатора
  dropFilesSize = SIZE(DROPFILES) + (filePathLen + 1)  ! +1 для двойного нуль-терминатора

  ! Выделяем память
  hMem = API(GlobalAlloc, GHND | GMEM_SHARE, dropFilesSize)
  IF hMem = 0 THEN 
    API(CloseClipboard)
    RETURN FALSE.
  END

  ! Блокируем память
  pDropFiles = API(GlobalLock, hMem)
  IF pDropFiles = 0 THEN
    API(GlobalFree, hMem)
    API(CloseClipboard)
    RETURN FALSE.
  END

  ! Заполняем структуру DROPFILES (ANSI)
  pDropFiles.pFiles = SIZE(DROPFILES)  ! Смещение к списку файлов
  pDropFiles.pt.x = 0
  pDropFiles.pt.y = 0
  pDropFiles.fNC = FALSE
  pDropFiles.fWide = FALSE             ! ANSI (не Unicode)

  ! Копируем путь к файлу (ANSI)
  pFilePath = pDropFiles + SIZE(DROPFILES)
  pFilePath = filePath

  ! Добавляем второй нуль-терминатор (для списка файлов)
  pFilePath[filePathLen] = 0

  ! Разблокируем память
  API(GlobalUnlock, hMem)

  ! Помещаем данные в буфер обмена
  IF API(SetClipboardData, CF_HDROP, hMem) THEN 
    success = TRUE
  ELSE
    API(GlobalFree, hMem)
  END

  ! Закрываем буфер обмена
  API(CloseClipboard)

  RETURN success
Вопрос: стоит ли двигаться в этом направлении, и вычищать ошибки, или есть (у кого) уже готовое решение?
Аватара пользователя
Губин Игорь
Шубуршун
Сообщения: 2584
Зарегистрирован: 16 Сентябрь 2005, 16:35
Откуда: Москва
Благодарил (а): 3 раза
Поблагодарили: 26 раз

Копирование физического файла с диска в буфер обмена

Сообщение Губин Игорь »

NewUser писал(а): 19 Июнь 2025, 17:03 помещать физический файл на диске в буфер обмена
Что значит "помещать физический файл на диске в буфер обмена"?
Ссылку на файл, его содержимое?
Это я только кажусь дураком! На самом деле я полный идиот!
NewUser
Старожил
Сообщения: 238
Зарегистрирован: 10 Ноябрь 2005, 23:07
Откуда: Краснодар
Благодарил (а): 6 раз

Копирование физического файла с диска в буфер обмена

Сообщение NewUser »

По всей видимости - ссылку на файл, для прикрепления его, например, в сообщение чата.
Да, ещё: C6.3
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3289
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 15 раз
Поблагодарили: 49 раз
Контактная информация:

Копирование физического файла с диска в буфер обмена

Сообщение Дед Пахом »

Если не придираться к синтаксису, то принципиально всё верно. Классы TGlobalMemory и TClipboard есть в моём winapi.inc, примерно так:

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

IF gmem.GlobalAlloc(GMEM_SHARE, nStrLen + 1)
    szCopyTo &= gmem.GlobalLock()
    winapi::lstrcpy(ADDRESS(szCopyTo), ADDRESS(szData))
    gmem.GlobalUnlock()
    
    cbd.OpenClipboard()
    cbd.EmptyClipboard()
    cbd.SetClipboardData(CF_TEXT, gmem.GetHandle())
    cbd.CloseClipboard()
  ELSE
    printd('GlobalAlloc(%i) failed, error %i', nStrLen + 1, winapi::GetLastError())
  END
С уважением, ДП
NewUser
Старожил
Сообщения: 238
Зарегистрирован: 10 Ноябрь 2005, 23:07
Откуда: Краснодар
Благодарил (а): 6 раз

Копирование физического файла с диска в буфер обмена

Сообщение NewUser »

Формат CF_HDROP — это стандартный Windows-механизм для передачи списка файлов через буфер обмена.
Когда вы вставляете данные из буфера обмена в чат или почту, система понимает, что это файл(ы), а не текст или изображение.
Приложение (например, Telegram) получает путь к файлу и предлагает его прикрепить или загрузить.
NewUser
Старожил
Сообщения: 238
Зарегистрирован: 10 Ноябрь 2005, 23:07
Откуда: Краснодар
Благодарил (а): 6 раз

Копирование физического файла с диска в буфер обмена

Сообщение NewUser »

Дед Пахом писал(а): 19 Июнь 2025, 17:13 Классы TGlobalMemory и TClipboard есть в моём winapi.inc
Как это использовать практически и по-шажно?
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3289
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 15 раз
Поблагодарили: 49 раз
Контактная информация:

Копирование физического файла с диска в буфер обмена

Сообщение Дед Пахом »

Шаг первый:

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

INCLUDE('winapi.inc'), ONCE
С уважением, ДП
Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 5236
Зарегистрирован: 06 Ноябрь 2014, 12:48
Благодарил (а): 12 раз
Поблагодарили: 65 раз

Копирование физического файла с диска в буфер обмена

Сообщение finsoftrz »

Лень код писать, особенно после ИИ. :shock:

В целом, для чтения файла используются функции win api. С такими прототипами.

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

     MODULE('WINAPI')
       CreateFile_ta(*CSTRING,ULONG,ULONG,LONG,ULONG,ULONG,UNSIGNED=0),UNSIGNED,RAW,PASCAL,NAME('CreateFileA')
       GetFileSize_ta(UNSIGNED,*ULONG),ULONG,PASCAL,NAME('GetFileSize')
       ReadFile_ta(UNSIGNED,LONG,ULONG,*ULONG,LONG),BOOL,PASCAL,RAW,NAME('ReadFile')
       WriteFile_ta(UNSIGNED,<*?>,ULONG,*ULONG,<*?>),BOOL,PASCAL,RAW,PROC,NAME('WriteFile')
       CloseHandle_ta(UNSIGNED),BOOL,PASCAL,PROC,NAME('CloseHandle')
       ShellExecute_ta(UNSIGNED,*CSTRING,*CSTRING,LONG=0,LONG=0,SIGNED=1),UNSIGNED,PASCAL,RAW,NAME('ShellExecuteA')
     END


Функция чтения файла в строку выглядит так. А строку в setclipboard потом засунуть.

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

!===================================================================================
! Загрузить файл в строку
!
FsTrueApi.LoadStringFromFile FUNCTION (STRING pFileName, Byte pReg)

loc:szFile          CSTRING(FILE:MaxFileName)
loc:hFile           LONG
loc:dwSize          UNSIGNED
loc:lpFileSizeHigh  ULONG
loc:dwBytesRead     ULONG
loc:bRead           BOOL

loc:ok              byte
loc:StrBuf          &CString
loc:s               Cstr

   CODE

      if pFileName=''
         SELF.ErrorMessageSet('Не задано имя файла для загрузки!')
         return(0)
      .
   
      if ~exists(pFileName)
         SELF.ErrorMessageSet('Не найден файл для загрузки - ' & clip(pFileName))
         return(0)
      . 
   
      if ~(SELF.BufIn &= NULL)
         SELF.BufIn = ''
         dispose(SELF.BufIn)
      .      

      loc:ok=0
      loc:szFile=pFileName
      loc:hFile = CreateFile_ta(loc:szFile,GENERIC_READ,0,0,OPEN_EXISTING,0,0)  !чтение шаблона из файла
      if loc:hFile <> INVALID_HANDLE_VALUE
         loc:dwSize = GetFileSize_ta(loc:hFile,loc:lpFileSizeHigh)
         if loc:dwSize > 0
            loc:StrBuf &= new(CSTRING(loc:dwSize))    !создаем буфер
            loc:bRead = ReadFile_ta(loc:hFile,ADDRESS(loc:StrBuf),SIZE(loc:StrBuf),loc:dwBytesRead,0)
            loc:ok=1
         end
         CloseHandle_ta(loc:hFile)
      end

      if loc:ok=0
         SELF.ErrorMessageSet('Ошибка чтения файла - ' & clip(pFileName))
         return(0)
      .

      if pReg=0
         SELF.BufIn &= new(String(loc:dwSize))
         SELF.BufIn = loc:StrBuf
      else   !с перекодировкой из utf-8
         loc:s.Set(loc:StrBuf)  
         loc:s.ToASCII()
         SELF.BufIn &= new(String(len(clip(loc:s.Str()))))
         SELF.BufIn = loc:s.Str()         
      .   

      clear(loc:StrBuf)
      dispose(loc:StrBuf)

      return(1)
C6/C12, ШВС, tps/btrieve.
NewUser
Старожил
Сообщения: 238
Зарегистрирован: 10 Ноябрь 2005, 23:07
Откуда: Краснодар
Благодарил (а): 6 раз

Копирование физического файла с диска в буфер обмена

Сообщение NewUser »

Благодарю!
Все вроде бы понятно.
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3289
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 15 раз
Поблагодарили: 49 раз
Контактная информация:

Копирование физического файла с диска в буфер обмена

Сообщение Дед Пахом »

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

df                          TDiskFile
sContent                    &STRING, AUTO
  CODE
  sContent &= df.LoadFile(pFileName)
  IF NOT sContent &= NULL
    !- и т.д.
С уважением, ДП
Аватара пользователя
Губин Игорь
Шубуршун
Сообщения: 2584
Зарегистрирован: 16 Сентябрь 2005, 16:35
Откуда: Москва
Благодарил (а): 3 раза
Поблагодарили: 26 раз

Копирование физического файла с диска в буфер обмена

Сообщение Губин Игорь »

finsoftrz писал(а): 19 Июнь 2025, 18:12 В целом, для чтения файла используются функции win api. С такими прототипами.
Если уж совсем минимизировать, то проще использовать systemstringclass

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

include('systemstring.inc'),once
AFile SystemStringClass
AFile.FromFile('файл')
SetClipBoard(AFile.ToString())
Если же фай юникодный или бинарный, то да, надо читать вручную и работать через Windows API SetClipboardData
Это я только кажусь дураком! На самом деле я полный идиот!
kreator
✯ Ветеран ✯
Сообщения: 5159
Зарегистрирован: 28 Май 2009, 15:54
Откуда: Москва
Благодарил (а): 11 раз
Поблагодарили: 26 раз

Копирование физического файла с диска в буфер обмена

Сообщение kreator »

NewUser писал(а): 19 Июнь 2025, 17:12 По всей видимости - ссылку на файл, для прикрепления его, например, в сообщение чата.
Да, ещё: C6.3
Вы бы посмотрели стандартные функции Клариона (setclipboard, clipboard). Чего-то я сомневаюсь, что "копирование" файла в проводнике есть чтение и копирование всего файла в память. Возможно достаточно скопировать только путь.
We are hard at work… for you. :)
Аватара пользователя
Губин Игорь
Шубуршун
Сообщения: 2584
Зарегистрирован: 16 Сентябрь 2005, 16:35
Откуда: Москва
Благодарил (а): 3 раза
Поблагодарили: 26 раз

Копирование физического файла с диска в буфер обмена

Сообщение Губин Игорь »

kreator писал(а): 19 Июнь 2025, 22:28 Возможно достаточно скопировать только путь.
Об этом уже сказали в самом начале. Дальше идут развлекалочки...
Это я только кажусь дураком! На самом деле я полный идиот!
NewUser
Старожил
Сообщения: 238
Зарегистрирован: 10 Ноябрь 2005, 23:07
Откуда: Краснодар
Благодарил (а): 6 раз

Копирование физического файла с диска в буфер обмена

Сообщение NewUser »

kreator писал(а): 19 Июнь 2025, 22:28 Возможно достаточно скопировать только путь.
Цитата из переписки с Дипсиком, которая подтвердила эмпирический опыт:
Упрощённый Clarion-код (только ссылка на файл)
Если вам не нужна сложная логика с DROPFILES, можно просто скопировать текстовый путь к файлу в буфер обмена (но тогда некоторые приложения не распознают его как файл для вставки).

Способ 1 (простой текст — не всегда работает)
далее идет предложенный ИИ код реализации упрощенной версии (могу, если кому интересно, опубликовать, он не большой, но с синтаксическими, как и положено для Дипсика, ошибками :wink: Но, структурно - всё правильно.)
Недостаток:
Некоторые мессенджеры (например, Telegram) не распознают такой текст как файл для прикрепления.
Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 5236
Зарегистрирован: 06 Ноябрь 2014, 12:48
Благодарил (а): 12 раз
Поблагодарили: 65 раз

Копирование физического файла с диска в буфер обмена

Сообщение finsoftrz »

Я бы не очень обращал внимание на то, что пишет Дипсик. В моим экспериментах, полную ахинею гнал. Надо много времени, чтобы обучить его более менее корректно выдавать код. Намного проще и быстрее написать шаблон. :D
ИИ имеет смысл сейчас для начинающих программистов на самых распространенных языках, типа html, css, частично javascript.
C6/C12, ШВС, tps/btrieve.
Ответить