Привет - Моя первая программа

Всё, что касается программирования на старых языках или для старых систем

Re: Привет - Моя первая программа

Сообщение uav » 28 май 2026, 12:05

clihlt писал(а):
uav писал(а):Вообще, по-хорошему, за такое на Ростелеком надо в РКН жаловаться...
Что останавливает?

Меня останавливает то, что у меня не Ростелеком и этой проблемы нет. :-)
По идее, должен же жаловаться тот, у кого она есть - пользователь Ростелекома.
Нужно же указывать какую-то информацию - где, как, что именно не работает, личные данные и т.п.
Не от третьего же лица писать - "Я вот слышал, что там что-то не работает"...

luzga, а эта Ваша программа, как я понял, для использования с Dynamic DNS применяется?
Или checkip.dyndns.org там просто для примера?
Последний раз редактировалось uav 28 май 2026, 12:23, всего редактировалось 3 раз(а).
Аватара пользователя
uav
Мастер Даунгрейда
 
Сообщения: 3050
Зарегистрирован: 22 дек 2008, 14:21

Re: Привет - Моя первая программа

Сообщение clihlt » 28 май 2026, 12:46

luzga писал(а):Не советую.
Так и запишем: "Мастер и Маргарита" не читали.;)
С уважением,
Владислав Васильев (aka clihlt).
Аватара пользователя
clihlt
Мастер Даунгрейда
 
Сообщения: 508
Зарегистрирован: 20 мар 2023, 21:17
Откуда: Брянск, СССР

Re: Привет - Моя первая программа

Сообщение luzga » 28 май 2026, 13:51

uav писал(а): а эта Ваша программа, как я понял, для использования с Dynamic DNS применяется?
Или checkip.dyndns.org там просто для примера?

Программа моя. Адрес, по которому загружается страница у меня появился много лет назад. Тогда, когда ещё всё в основном на http и работало.
Эта программа приложена в пакете. Изначально она написана на C++.
Я изменил её, чтобы прикрепить в качестве развлечения пользователям.
И ещё, код в программе, в основном используется с глобальными переменными, хотя, все их можно объявить локальными.
И ещё. Здесь нет прогресса индикатора. Просто. Как самый первый GetIP.
Для сборки программы понадобится Borland C++ 5.0 или выше версия, или
компилятор от Microsoft - это Visual Studio, версии, начиная с 6.0 (1998 года выпуска).
У меня установлен и Borland C++ - (выберите на странице, файл для скачивания 229.5 Мб 1997 5.02). Устанавливать нужно не всё, только Borland.
и Microsoft Visual C++ 6.0 - (выберите на странице Visual CPP ISO 380.4 Мб 1998 6.00.8168.0). Для Visual C++ 6.0, также можно установить сервис пак (SP5). Он там же, на странице. Хотя, не критично и можно без него.
 Развернуть: WinMain.cpp
Код: Выделить всё
// WinMain.cpp

#include <windows.h>
#include "resource.h"
BOOL CopyToClipboard(char* str);
void mb(char* str);
typedef HRESULT (WINAPI* _URLDownloadToFileA)(LPUNKNOWN pCaller, LPCSTR szURL, LPCSTR szFileName, DWORD dwReserved, void* lpfnCB);
_URLDownloadToFileA pURLDownloadToFile;

#define BUFFSIZE 2048
char szBuff[BUFFSIZE];
char szResult[BUFFSIZE];

char* szAppname = "GetIP";
char* szUrl = "http://checkip.dyndns.org/Current IP Check.htm";
char* szErr01 = "Не удалось загрузить функцию URLDownloadToFile";
char* szErr02 = "Нет связи.";
char* szErr03 = "Не удалось создать временный файл для записи.";
char* szErr04 = "Не удалось. Блокирует Ростелеком!";
char* szMatch = "Current IP Address:";
char* szDebugFileName = "ip_dbg.txt";
HANDLE hFile;
char szTempFileName[MAX_PATH];
char* szToken;
DWORD n, dwBytesRead;

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
   pURLDownloadToFile = (_URLDownloadToFileA)
      GetProcAddress(LoadLibraryA("urlmon"),
      "URLDownloadToFileA");
   if (!pURLDownloadToFile)
      mb(szErr01);

   GetTempPath(MAX_PATH,szTempFileName);
   lstrcat(szTempFileName,"ip.txt");
   if (pURLDownloadToFile(0,szUrl,szTempFileName,0,0))
      mb(szErr02);

#ifndef DEBUG
   hFile = CreateFile(szDebugFileName,
      GENERIC_READ,0,0,OPEN_EXISTING,0,0);
#else
   hFile = CreateFile(szTempFileName,
      GENERIC_READ,0,0,OPEN_EXISTING,0,0);   
#endif
   if (INVALID_HANDLE_VALUE==hFile)
      mb(szErr03);

   ReadFile(hFile,szResult,BUFFSIZE,&dwBytesRead,NULL);
   CloseHandle(hFile);
   if (!strstr(szResult,szMatch))
      mb(szErr04);

   szToken = strrchr(szResult, ':');
   szToken = strtok(szToken, "<");
   lstrcpyn(szResult, szToken+2, sizeof(szResult));

   // Скопировать IP-адрес в буфер обмена.
   n = lstrlen(szResult);
   if (n)
      n = CopyToClipboard(szResult);
   if (!n)
      wsprintf(szBuff,"IP Address: %s",szResult);
   else {
      wsprintf(szBuff,
      "IP Address: %s\n\n"
      "Адрес скопирован в Буфер Обмена\n"
      "для вставки в документ нажмите клавишу \"Ctrl+V\".",
      szResult);
   }
   mb(szBuff);
   return 0;
}

BOOL CopyToClipboard(char* str) {
   BOOL bRet=FALSE;
   CloseClipboard();
   if (OpenClipboard(GetActiveWindow())) {
      EmptyClipboard();
      HGLOBAL GlobalMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE,lstrlen(str)+1);
      if (GlobalMem) {
         char* Data=(char*)GlobalLock(GlobalMem);
         lstrcpy(Data,str);
         GlobalUnlock(GlobalMem);
         if (SetClipboardData(CF_TEXT,GlobalMem))
            bRet=1;
      }
      CloseClipboard();
   }
   return bRet;
}

void mb(char* str) {
   UINT uType=MB_OK | MB_ICONINFORMATION |
   MB_SETFOREGROUND | MB_SYSTEMMODAL;
   n=0;
   if (strstr(str,"Нет ") || strstr(str,"Не удалось"))
      ++n;
   if (n) {
      uType &=~MB_ICONINFORMATION;
      uType |=MB_ICONWARNING;
   } MessageBox(GetActiveWindow(),str,szAppname,uType);
   if (n) ExitProcess(n);
}
Вложения
GetIP_Cpp.zip
(16.54 Кб) Скачиваний: 47
Последний раз редактировалось luzga 28 май 2026, 14:06, всего редактировалось 3 раз(а).
Аватара пользователя
luzga
Мастер Даунгрейда
 
Сообщения: 320
Зарегистрирован: 04 сен 2025, 19:35

GetIP - CPP - Progress

Сообщение luzga » 28 май 2026, 17:01

Я сделал, как и в ассемблерной программе. Трюк с прогрессом.
 Развернуть: GetIP.cpp
Код: Выделить всё
// GetIP.cpp

#ifdef _MSC_VER
#pragma comment(lib,"comctl32.lib")
#endif
#include <windows.h>
#include <commctrl.h>
#include "resource.h"
BOOL CopyToClipboard(char* str);
void mb(char* str);
int DoExit();
#ifndef PBS_SMOOTH
#define PBS_SMOOTH 01
#endif
#ifndef PBS_VERTICAL
#define PBS_VERTICAL 04
#endif
#ifndef PBM_SETBARCOLOR
#define PBM_SETBARCOLOR (WM_USER+9)
#endif

typedef HRESULT (WINAPI* _URLDownloadToFileA)(LPUNKNOWN pCaller, LPCSTR szURL, LPCSTR szFileName, DWORD dwReserved, void* lpfnCB);
_URLDownloadToFileA pURLDownloadToFile;

char* szAppname = "GetIP";
char* szMsg = "\nПодключение к серверу checkip.dyndns.org\n"
"Пожалуйста, ждите...";
char* szUrl = "http://checkip.dyndns.org/Current IP Check.htm";
char* szName = "ip.txt";
char* szMatch = "Current IP Address:";
char* szDebugFileName = "ip_dbg.txt";
char* szFormat = "IP Address: %s";
char* szFormat2 = "IP Address: %s\n"
"Адрес скопирован в Буфер Обмена\n"
"для вставки в документ нажмите клавишу \"Ctrl+V\".";
char* szErr01 = "Не удалось создать прогресс.";
char* szErr02 = "Не удалось загрузить функцию URLDownloadToFile";
char* szErr03 = "Нет связи.";
char* szErr04 = "Не удалось создать временный файл для записи.";
char* szErr05 = "Не удалось. Блокирует Ростелеком!";

HINSTANCE g_hInstance;
BOOL g_bRunning;
DWORD dwColor = RGB(255, 0, 0); // Red
//DWORD dwColor = RGB(0, 0, 255); // Blue
//DWORD dwColor = RGB(0, 128, 0); // Green
#define BUFFSIZE 2048
char szBuff[BUFFSIZE];

static DWORD WINAPI WorkThread(LPVOID)
{
   pURLDownloadToFile = (_URLDownloadToFileA)
      GetProcAddress(LoadLibraryA("urlmon"),
      "URLDownloadToFileA");
   if (!pURLDownloadToFile)
   {
      lstrcpy(szBuff,szErr02);
      return DoExit();
   }

   char szTempFileName[MAX_PATH];
   GetTempPath(MAX_PATH,szTempFileName);
   lstrcat(szTempFileName,szName);
   if (pURLDownloadToFile(0,szUrl,szTempFileName,0,0))
   {
      lstrcpy(szBuff,szErr03);
      return DoExit();
   }

   HANDLE hFile;
#ifdef _DEBUG
   hFile = CreateFile(szDebugFileName,
      GENERIC_READ,0,0,OPEN_EXISTING,0,0);
#else
   hFile = CreateFile(szTempFileName,
      GENERIC_READ,0,0,OPEN_EXISTING,0,0);   
#endif

   if (INVALID_HANDLE_VALUE==hFile)
   {
      lstrcpy(szBuff,szErr04);
      return DoExit();
   }

   DWORD n, dwBytesRead;
   char szResult[BUFFSIZE];
   ReadFile(hFile,szResult,BUFFSIZE,&dwBytesRead,NULL);
   CloseHandle(hFile);
   if (!strstr(szResult,szMatch))
   {
      lstrcpy(szBuff,szErr05);
      return DoExit();
   }

   char* szToken = strrchr(szResult, ':');
   szToken = strtok(szToken, "<");
   lstrcpyn(szResult, szToken+2, sizeof(szResult));

   n = lstrlen(szResult);
   if (n)   // Скопировать IP-адрес в буфер обмена.
      n = CopyToClipboard(szResult);
   if (!n)
      wsprintf(szBuff,szFormat,szResult);
   else
      wsprintf(szBuff,szFormat2,szResult);

   g_bRunning = 0; // Работа завершена!
   return 0;
}

static DWORD WINAPI ProgressThread(LPVOID)
{
   HWND hwndProgress, hWnd = 0;

   // Найти главное окно программы,
   // в данном случае системный MessageBox.
   while (!hWnd)
   {
      Sleep(50); // Таймаут (небольшой перерыв).
      hWnd = FindWindow(NULL,szAppname);
   }

   // Обеспечивает загрузку библиотеки Comctl32.dll.
   InitCommonControls();

   // Скрыть кнопку OK у MessageBox.
   ShowWindow(GetTopWindow(hWnd),SW_HIDE);

// Вычислить координаты главного окна (т.е. родительского),
// в данном случае, родительское окно, системный MessageBox.
   RECT rect;
   GetClientRect(hWnd,&rect);
   int x = 1;
   int y = rect.bottom - 20;
   int nWidth = rect.right - 2;
   int nHeight = 20;

// Создать прогресс индикатор (Progress Bar).
   hwndProgress = CreateWindow("msctls_progress32",
      "Progress",
      WS_VISIBLE | WS_CHILD | PBS_SMOOTH,
      x, y, nWidth, nHeight,
      hWnd,(HMENU)IDC_PROGRESS1,
      g_hInstance,NULL);
   
   if (!hwndProgress)
   {
      lstrcpy(szBuff,szErr01);
      return DoExit();
   }

   // Создать рабочий поток.
   DWORD tid;
   CreateThread(NULL,0,WorkThread,0,0,&tid);

   // Цвет прогресс индикатора.
   SendMessage(hwndProgress,
      PBM_SETBARCOLOR,0,(LPARAM)dwColor);

   int nMaxRange = 100;
   int nNewPos = 0;

   // Показать прогресс индикатор.
   ShowWindow(hwndProgress,SW_SHOW);

   // Вычислить диапазон прогресс индикатора (0-100).
   SendMessage(hwndProgress,
      PBM_SETRANGE,
      0,(LPARAM)MAKELONG(0,nMaxRange));

   // Установить диапазон прогресс индикатора.
   SendMessage(hwndProgress,
      PBM_SETSTEP,(WPARAM)1,0);

   // Пока пользователь не закрыл окно или
   // переменная bRunning не пуста - выполнять цикл.
   while (IsWindowVisible(hWnd) && g_bRunning)
   {
      ++nNewPos; // Прибавить шкалу индикатора прогресса.
      if (nMaxRange == nNewPos)
         nNewPos = 0;

      // Движение прогресс индикатора.
      SendMessage(hwndProgress,PBM_SETPOS,nNewPos,0);
      Sleep(20); // Таймаут. Небольшой переыв.
   }

   // Закрыть прогресс бар.
   DestroyWindow(hwndProgress);

   // Закрыть диалоговое окно (MessageBox) нажав кнопку OK.
   //ShowWindow(GetTopWindow(hWnd),SW_SHOW);
   SendMessage(GetTopWindow(hWnd),BM_CLICK,0,0);

   return 0;
}

int DoExit()
{
   HWND hWnd = FindWindow(NULL,szAppname);
   if (hWnd) // Если окно найдено, закрыть его.
   {
      // Закрыть диалоговое окно (MessageBox) нажав кнопку OK.
      //ShowWindow(GetTopWindow(hWnd),SW_SHOW);
      SendMessage(GetTopWindow(hWnd),BM_CLICK,0,0);
   }
   if (szBuff[0]) // Если буфер не пуст, показать сообщение.
   {
      mb(szBuff);
      szBuff[0] = 0;
      g_bRunning = 0;
   }
   return 0;
}

/*
* Начало программы (Entry point).
*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
   g_hInstance = hInstance;
   g_bRunning = 1;
   DWORD tid;
   CreateThread(NULL,0,ProgressThread,0,0,&tid);
   mb(szMsg);
   while (g_bRunning)
      Sleep(20);
   return DoExit();
}

BOOL CopyToClipboard(char* str) {
   BOOL bRet=FALSE;
   CloseClipboard();
   if (OpenClipboard(GetActiveWindow())) {
      EmptyClipboard();
      HGLOBAL GlobalMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE,lstrlen(str)+1);
      if (GlobalMem) {
         char* Data=(char*)GlobalLock(GlobalMem);
         lstrcpy(Data,str);
         GlobalUnlock(GlobalMem);
         if (SetClipboardData(CF_TEXT,GlobalMem))
            bRet=1;
      }
      CloseClipboard();
   }
   return bRet;
}

void mb(char* str) {
   UINT uType=MB_OK | MB_ICONINFORMATION |
   MB_SETFOREGROUND | MB_SYSTEMMODAL;
   int n=0;
   if (strstr(str,"Нет ") || strstr(str,"Не удалось"))
      ++n;
   if (n) {
      uType &=~MB_ICONINFORMATION;
      uType |=MB_ICONWARNING;
   } MessageBox(GetActiveWindow(),str,szAppname,uType);
   if (n) ExitProcess(n);
}

Есть один ньюанс, при поиске дескриптора окна (hWnd, хэндла).
Это здесь :
char* szAppname = "GetIP"; // Это заголовок.
// Найти главное окно программы,
// в данном случае системный MessageBox.
while (!hWnd)
{
Sleep(50); // Таймаут (небольшой перерыв).

// Функции FindWindow нужно два параметра
// один из которых заголовок окна.
hWnd = FindWindow(NULL,szAppname);
}
Если этот заголовок будет совпадать с именем папки, то программа
поведёт себя непредсказуемо. Для этого, лучше всего, добавить ещё
какую-нибудь строку или символ. Сделайте так, как в ассемблерной версии программы
(здесь я забыл). Вообще, у меня ОС настроена показывать полный путь
в строке заголовка и из-за этого, у меня проблем нет. Вы же, не забудьте
исправить. Я так и не сказал, как программа может повести себя, если
примет Хэндл (hWnd), идентификатор папки, а не окна. Скорее всего,
просто быстро закроется или может создать прогресс на окне папки.
Итого. Вам нужно изменить заголовок окна на это:
char* szAppname = "GetIP - Узнать IP-адреса";

Также, есть дополнительный параметр поиска hWnd идентификатора,
это имя класса, но из-за трюка с поиском не собственного окна - это
является не проблемой, а плохим тоном или как говорят костылём.
В общем, у системного MessageBox класс называется #32770.
Для просмотра свойств окно, есть несколько утилит, одна
в инструментах Borland и Microsoft, имя её Spyxx. Есть независимая
утилита WinSpy
 Развернуть: Имя оконного класса MessageBox
Изображение
Вложения
GetIP_CPP_Progress.zip
(18.69 Кб) Скачиваний: 44
Последний раз редактировалось luzga 28 май 2026, 19:57, всего редактировалось 5 раз(а).
Аватара пользователя
luzga
Мастер Даунгрейда
 
Сообщения: 320
Зарегистрирован: 04 сен 2025, 19:35

Итого

Сообщение luzga » 29 май 2026, 08:41

В конечном итоге у нас вышло две версии программы. Я их обозначил только по имени папок. Это GetIP_Asm и GetIP_Cpp_Progress.
Я довёл, до более совершенной версии, программы. Убрал лишние ходы. Я не шахматист, слабо двигаю, но не беда. По мере накопления опыта, станешь видеть поле деятельности лучше и сразу отсекаешь ненужные шаги.
В общем, можете разбираться. Я как всегда прикрепляю и вид модулей, кому-то ведь необязательно скачивать, а интересно просто глянуть.
 Развернуть: GetIP.asm
Код: Выделить всё
%TITLE "GetIP.asm"
;-------------------------------------------------------
; Программа подключается к сайту checkip.dyndns.org
; по-протоколу HTTP. Скачивает страницу "Current IP Check.htm".
; Сохраняет скаченное во-временной директории ОС Windows,
; с именем ip.txt. Копирует адрес в Буфер Обмена
; выводит информацию и завершается.
; Программа работает в ОС Windows.
;-------------------------------------------------------
   IDEAL   ; Переводит Turbo Assembler в режим Ideal.
   P386   ; Разрешение всех инструкций процессора 80386.
   MODEL   flat, STDCALL ; Модель памяти.

include   "Win32.inc" ; Содержит структуры, определение переменных.
include   "GetIP.ri" ; Вставка идентификаторов ресурсов.

COLOR_RED equ 0FFh ; Цвет прогресс бара RGB(255, 0, 0) красный.
COLOR_BLUE equ 0FF0000h ; Цвет прогресс бара RGB(0, 0, 255) синий.

nMaxRange equ 100
DEBUG_APP equ 0 ; Для отладки, нужно установить не нуль т.е. единицу.

   DATASEG ; Сегмент данных.
;-------------------------------------------------------
szAppname db 'GetIP - Узнать IP-адреса', 0 ; Имя (заголовок) программы
szMsg db 13,10,'Подключение к серверу checkip.dyndns.org ',13,10
db 'Пожалуйста, ждите...',0

szProgressWnd db 'msctls_progress32',0
szProgressApp db 'Progress',0

; urlmon.dll модуль библиотеки ОС
szLibFileName db 'urlmon',0
; Имя функции
szProcName db 'URLDownloadToFileA',0

; Страница, которую программа, попробует загрузить.
szUrl db 'http://checkip.dyndns.org/Current IP Check.htm',0
; Имя файла в котором будет сохранена страница.
szName db 'ip.txt',0

; Информационные сообщения.
szFormat db 'IP-адрес компьютера: %s',0
szFormat2 db 'IP-адрес компьютера: %s',13,10
db 'Адрес скопирован в Буфер Обмена',13,10
db 'для вставки в документ нажмите клавишу "Ctrl+V".',0
szSkobka db '<',0
szMatch db 'Current IP Address:',0 ; Найти совпадение

; Сообщения о неудачах.
szErr01 db 'Не удалось создать progress bar',0
szErr02 db 'Не удалось загрузить функцию URLDownloadToFile',0
szErr03 db 'Нет связи.',0
szErr04 db 'Не удалось создать временный файл для записи.',0
szErr05 db 'Не удалось. Блокирует Ростелеком!',0
szErrTemp db 'Нет ', 0
szErrTemp2 db 'Не удалось', 0
szDebugFileName db 'ip_dbg.txt',0 ; Для отладки.

   UDATASEG ; Сегмент неинициализированных переменных.
;-------------------------------------------------------
szTempFileName   db 104h dup(?) ; MAX_PATH = 260
szBuff      db 2*400h dup(?) ; 2048
szResult      db 2*400h dup(?) ; 2048
szToken      dd ?
tid      dd ?
hInstance      dd ?
bRunning      dd ?

   CODESEG ; Тело программы (сегмент кода).
;-------------------------------------------------------
; Список процедур экспортируемых из ОС.
include "AProc.inc" ; Отдельный файл, для удобства.
;-------------------------------------------------------

proc   WorkThread
   LOCAL @@pURLDownloadToFile:dword, @@nLen:dword
   LOCAL @@dwBytesRead:dword

   ; Загрузка функции URLDownloadToFile
   ; из библиотечного модуля urlmon.dll
   push offset szProcName
   push offset szLibFileName
   call LoadLibraryA
   ; Получить адрес функции
   push eax ; hModule дескриптор.
   call GetProcAddress
   ; Сохранить адрес функции в переменной
   mov [@@pURLDownloadToFile], eax
   ; Адрес функции получен, если регистр EAX не нуль
   ; продолжить программу или сообщить о ошибке
   ; и выйти из программы.
   cmp eax, 0
   jne short @@10
   push offset szErr02 ; Сообщение о ошибке.
   jmp @@98
@@10:
   ; Сооружение имени файла в который будет записан
   ; ответ удаленного сервера.
   ; Сначала узнать, где расположен временный каталог системы.
   push offset szTempFileName
   push 104h
   call GetTempPathA

   ; Конкатенация (объединение) двух строк:
   ; имя временн. каталога ОС (у меня C:\Temp) с именем файла
   ; C:\Temp и Ip.txt
   push offset szName
   push offset szTempFileName
   call lstrcatA

   ; Вызов функции ОС URLDownloadToFile
   ; скачивает файл из интернет (URL) и сохраняет
   ; его на локальный диск. В нашем случае во временный
   ; каталог ОС с именем Ip.txt (у меня C:\Temp\Ip.txt).
   push 0
   push 0
   push offset szTempFileName
   push offset szUrl
   push 0
   call [@@pURLDownloadToFile]
   cmp eax, 0
   je short @@20
   push offset szErr03 ; Сообщение о ошибке.
   jmp @@98
@@20:
; Открыть записанный файл из временного каталога
   push 0   ; hTemplateFile Дескриптор файла шаблона
   push 0   ; dwFlagsAndAttributes Атрибуты файла
   push 3   ; dwCreationDisposition Действие (создать/открыть)
   push 0   ; lpSecurityAttributes Атрибуты безопасности
   push 0   ; dwShareMode Режим совместного доступа
   push 80000000h   ; dwDesiredAccess Режим доступа (чтение/запись)

if DEBUG_APP
   push offset szDebugFileName ; Для отладки
else
   push offset szTempFileName ; Имя файла/устройства
endif ; end DEBUG_APP

   call CreateFileA
   mov ebx, eax ; Дескриптор файла
   cmp eax, 0FFFFFFFFh ; -1
   jne short @@30
   push offset szErr04 ; Сообщение о ошибке.
   jmp @@98
@@30:
; Получить данные из файла в буфер.
   push 0   ; lpOverlapped Для асинхронного чтения
   lea eax, [@@dwBytesRead]  ; lpNumberOfBytesRead Указатель на переменную с числом считанных байт
   push eax
   push 400h ; nNumberOfBytesToRead Сколько байт прочитать 1024 (400h)
   push offset szResult ; Буфер для данных.
   push ebx   ; Дескриптор файла.
   call ReadFile
   push ebx
   call CloseHandle

; Проверить, есть совпадение на строку в полученном тексте?
   push offset szMatch
   push offset szResult
   call strstr   ; Если, текст szResult содержит текст szMatch
   add esp, 8 ; то переход на метку @@35 или сообщение и выход
   cmp eax, 0
   jne short @@35
   push offset szErr05 ; Ссообщение о ошибке.
   jmp @@98
@@35:
; Разбор данных.
   push 3Ah ; Отсечь строку по двоеточие :
   push offset szResult
   call strrchr
   add esp, 8
   mov [szToken], eax

   push offset szSkobka
   push [szToken]
   call strtok
   add esp, 8
   mov [szToken], eax

   push 400h
   mov eax, [szToken]
   add eax, 2
   push eax ; String
   push offset szResult
   call lstrcpynA

   push offset szResult
   call lstrlenA
   mov [@@nLen], eax
   cmp [@@nLen], 0
   je short @@40

; Скопировать IP-адрес в Буфер Обмена.
   push offset szResult
   call CopyToClipboard
   mov [@@nLen], eax
@@40:
   cmp [@@nLen], 0
   jne short @@50
   push offset szResult
   push offset szFormat
   jmp short @@60
@@50:
   push offset szResult
   push offset szFormat2
@@60:
   push offset szBuff
   call _wsprintfA
   add esp, 0Ch ; 12 (вытолкнуть три аргумента из стека)
   jmp short @@99
@@98:
   call DoExit
@@99:
   mov [bRunning], 0
   ret
endp   WorkThread

proc   ProgressThread
   LOCAL @@hwnd:dword, @@hwndProgress:dword
   LOCAL @@rect:RECT, @@newPos:dword
   LOCAL @@x:dword, @@y:dword, @@width:dword, @@height:dword

; Найти главное окно программы, в данном случае системный MessageBox.
@@10:
   push 50 ; Таймаут (небольшой перерыв).
   call Sleep ; Используется для приостановки выполнения текущего потока программы на заданный промежуток времени.

; Найти диалоговое окно (системный MessageBox).
   push offset szAppname ; Заголовок окна.
   push 0
   call FindWindowA ; Используется для получения дескриптора (HWND) окна верхнего уровня по его заголовку или имени класса.
   mov [@@hwnd], eax ; Продолжать поиск, пока не найден дескриптор
   cmp eax, 0 ; т.е. регистр eax не нуль.
   je short @@10

; Обеспечивает загрузку библиотеки Comctl32.dll.
   call InitCommonControls

; Скрыть кнопку OK у MessageBox.
   push SW_HIDE
   push [@@hwnd]
   call GetTopWindow
   mov ebx, eax
   push eax
   call ShowWindow

; Вычислить координаты главного окна (т.е. родительского),
; в данном случае, родительское окно, системный MessageBox.
   lea eax, [@@rect]
   push eax
   push [@@hwnd]
   call GetClientRect ; Используется для получения размеров клиентской (рабочей) области окна.
   mov [@@x], 1
   mov edx, [@@rect.bottom]
   add edx, 0FFFFFFECh
   mov [@@y], edx
   mov ecx, [@@rect.right]
   add ecx, 0FFFFFFFEh
   mov [@@width], ecx
   mov [@@height], 20

; Создать прогресс индикатор (Progress Bar).
   push 0      ; lpParam
   push [hInstance]
   push IDC_PROGRESS ; Объявлен в файле GetIP.ri
   push [@@hwnd]   ; hWndParent дескриптор род. окна.
   push [@@height]
   push [@@width]
   push [@@y]
   push [@@x]
   push 50000001h   ; dwStyle
   push offset szProgressApp ; Заголовок окна
   push offset szProgressWnd ; Имя оконного класса msctls_progress32
   push 0      ; dwExStyle
   call CreateWindowExA
   mov [@@hwndProgress], eax
   cmp eax, 0
   jne short @@30
   ; Не удалось создать прогесс бар
   push offset szErr01 ; Сообщение о ошибке.
   jmp @@98
@@30:
; Создать рабочий поток.
   push offset tid      ; lpThreadId
   push 0         ; dwCreationFlags
   push 0         ; lpParameter
   push offset WorkThread   ; lpStartAddress
   push 0         ; dwStackSize
   push 0         ; lpThreadAttributes
   ; Cоздания нового потока исполнения внутри
   ; виртуального адресного пространства текущего процесса.
   call CreateThread

; Цвет прогресс индикатора.
   push COLOR_RED      ; lParam
   push 0         ; wParam
   push PBM_SETBARCOLOR   ; Msg
   push [@@hwndProgress]
   call SendMessageA

; Показать прогресс индикатор.
   push SW_SHOW
   push [@@hwndProgress]
   call ShowWindow

; Вычислить диапазон прогресс индикатора (0-100).
   mov eax, nMaxRange
   shl eax, 10h
   or eax, 0

; Установить диапазон прогресс индикатора.
   push eax         ; lParam   
   push 0         ; wParam
   push PBM_SETRANGE   ; Msg
   push [@@hwndProgress]
   call SendMessageA
   mov [@@newPos], 0

@@40:
   inc [@@newPos] ; Увеличить индикатор на единицу.
   cmp [@@newPos], nMaxRange ; Если индикатор меньше или равно 100
   jle short @@50 ; не переходить, а
   mov [@@newPos], 0 ; обнулить.

@@50:
; Движение прогресс индикатора.
   push 0         ; lParam
   push [@@newPos]      ; wParam
   push PBM_SETPOS      ; Msg
   push [@@hwndProgress]
   call SendMessageA

   push 20 ; Таймаут. Небольшой переыв.
   call Sleep
   
; Окно видимо, пользователь не закрыл?
   push [@@hwnd]   
   call IsWindowVisible
   cmp eax, 0 ; Сравнить, регистр EAX равен нулю? Если да, выход:
   je short @@90 ; - переход на метку @@90

   cmp [bRunning], 0   ; Если переменная пуста, значит операция
   jne short @@40 ; завершена, выход: - не переходить на метку @@40
@@90:
   push [@@hwndProgress]   ; Закрыть прогресс
   call DestroyWindow

; Закрыть диалоговое окно (MessageBox) нажав кнопку OK.
   push 0         ; lParam
   push 0         ; wParam
   push BM_CLICK      ; Msg
   push ebx
   call SendMessageA      ; Нажать на кнопку OK

; Если буфер не пуст, переход на метку @@99
   cmp [byte szBuff], 0
   jne short @@99
   mov [bRunning], 0 ; иначе, обнулить переменную.
   jmp short @@99
@@98:
   call DoExit
@@99:
   ret
endp   ProgressThread

proc DoExit
   USES ebx, ecx
   ARG @@str:dword   
; Найти и закрыть окно с прогресс баром.
   push offset szAppname ; Заголовок окна.
   push 0
   call FindWindowA
   cmp eax, 0
   je short @@10
   push eax
   call GetTopWindow
   push 0      ; lParam
   push 0      ; wParam
   push BM_CLICK   ; Msg
   push eax
   call SendMessageA   ; Нажать на кнопку OK
@@10:
   mov ebx, [@@str]
   push ebx
   call lstrlenA
   cmp eax, 0
   je short @@99
   push ebx
   push offset szBuff
   call lstrcpyA
   push offset szBuff
   call mb
   pop ecx
   mov eax, 0
   mov [byte szBuff], 0
   mov [bRunning], 0
@@99:
   ret
endp   DoExit

;
; Начало программы.
;
Start:
   push 0
   call GetModuleHandleA ; Извлекает дескриптор указанного модуля.
   mov [hInstance], eax

; Создать прогресс индикатор (поток).
   push offset tid
   push 0         ; dwCreationFlags
   push 0         ; lpParameter
   push offset ProgressThread   ; lpStartAddress
   push 0         ; dwStackSize
   push 0         ; lpThreadAttributes
   ; Cоздания нового потока исполнения внутри
   ; виртуального адресного пространства текущего процесса.
   call CreateThread

   mov [bRunning], 1 ; Работа началась, установить флаг.
   push offset szMsg ; Вместо диалогового окна, вызовем системный
   call mb ; MessageBox. В созданном ранее, потоке ProgressThread
   pop ecx ; получим дескриптор и станем работать как с собственным.
   ; Способ таит подводные камни, нужно пользоваться осторожно.

; Обработка сообщений: у нас не собственное окно, станем ждать завершения
; процесса, контролируя переменную. Когда bRunning обнулится,
; значит работа окончена. Следует переход на метку Exit, что завершит программу.
@@LOOP:
   push 20
   call Sleep
   cmp [bRunning], 1
   je short @@LOOP
   push offset szBuff
   call DoExit

; Завершение программы.
   push 0 ; Код выхода.
   call ExitProcess ; Заканчивает работу процесса и всех его потоков.

;-------------------------------------------------------
; Подпрограммы помощники
;-------------------------------------------------------

proc CopyToClipboard
   ; Копирует текст в Буфер обмена.
   USES ebx, edx, edi, esi
   ARG @@str:dword
   call CloseClipboard
   call GetActiveWindow
   push eax
   call OpenClipboard
   cmp eax, 0
   je short @@99
   mov edx, 0
   call EmptyClipboard
   mov ebx, [@@str]
   push ebx
   call lstrlenA
   inc eax
   push eax   ; Bytes
   push 2002h ; Flags
   call GlobalAlloc
   mov esi, eax
   cmp eax, 0
   je short @@10
   push esi   ; Mem
   call GlobalLock
   mov ebx, [@@str]
   push ebx
   push eax   ; String
   call lstrcpyA
   push esi   ; Mem
   call GlobalUnlock
   push esi   ; Mem
   push 1   ; uFormat
   call SetClipboardData
   cmp eax, 0
   je short @@10
   mov edx, 1
@@10:
   call CloseClipboard
   mov eax, edx
@@99:
   ret
endp CopyToClipboard

proc    mb
   ; Функция выведет сообщение.
   ; Если строка содержит текст, который определён в двух переменных
   ; szErrTemp и szErrTemp2 - это "Нет" и "Не удалось", то функция, после
   ; сообщения, завершает программу.
   USES ebx, edi, esi ; Используются регистры
   ARG @@str:dword ; Строка сообщения
; uType MessageBox (IconInformation)
   mov esi, MB_OK or MB_ICONINFORMATION or MB_SETFOREGROUND or MB_SYSTEMMODAL
   mov ebx, 0
   push offset szErrTemp ; Строка содержит слово "Нет" ?
   mov edi, [@@str]
   push edi
   call strstr ; Используется для поиска первого вхождения
      ; подстроки в другую строку (главную).
   add esp, 8
   cmp eax, 0
   jne short @@10
   push offset szErrTemp2 ; Строка содержит слово "Не удалось" ?
   push edi
   call strstr
   add esp, 8
   cmp eax, 0
   je short @@20
@@10:
   inc ebx
@@20:
   cmp ebx, 0
   je short @@30
; Изменить стиль MessageBox (IconWarning)
   and esi, 0FFFFFFBFh ; MB_OK or MB_ICONWARNING or MB_SETFOREGROUND or MB_SYSTEMMODAL
   or esi, 30h
@@30:
   push esi ; uType MessageBox
   push offset szAppname ; Заголовок окна
   push edi ; Текст сообщения
   call GetActiveWindow ; Извлекает дескриптор (HWND) активного
         ; окна, которое принадлежит очереди
         ; сообщений вызывающего потока.
   push eax ; hWnd, дескриптор родительского окна (может быть нуль)
   call MessageBoxA
   cmp ebx, 0
   je short @@99
   push ebx ; Код выхода для всех потоков.
   call ExitProcess ; Заканчивает работу процесса и всех его потоков.
@@99:
   ret
endp    mb

   END   Start   ; Конец программы/точка входа.

 Развернуть: GetIP.cpp
Код: Выделить всё
// GetIP.cpp

#ifdef _MSC_VER
#pragma comment(lib,"comctl32.lib")
#endif
#include <windows.h>
#include <commctrl.h>
#include "resource.h"
BOOL CopyToClipboard(char* str);
void mb(char* str);
int DoExit(char* str=NULL);// По умолчанию, строковый параметр пуст. Это значит, можно вызывать функцию не указывая параметр.
#ifndef PBS_SMOOTH // Это определение, если в заголовочных файлах, старых средств разработки, значение отсутствует.
#define PBS_SMOOTH 01 // Это значение влияет на вид прогресс бара.
#endif
#ifndef PBM_SETBARCOLOR
#define PBM_SETBARCOLOR (WM_USER+9)
#endif

typedef HRESULT (WINAPI* _URLDownloadToFileA)(LPUNKNOWN pCaller, LPCSTR szURL, LPCSTR szFileName, DWORD dwReserved, void* lpfnCB);
_URLDownloadToFileA pURLDownloadToFile;

char* szAppname = "GetIP - Узнать IP-адреса";
char* szMsg = "\nПодключение к серверу checkip.dyndns.org\n"
"Пожалуйста, ждите...";
char* szUrl = "http://checkip.dyndns.org/Current IP Check.htm";
char* szName = "ip.txt";
char* szMatch = "Current IP Address:";
char* szDebugFileName = "ip_dbg.txt";
char* szFormat = "IP Address: %s";
char* szFormat2 = "IP Address: %s\n"
"Адрес скопирован в Буфер Обмена\n"
"для вставки в документ нажмите клавишу \"Ctrl+V\".";
char* szErr01 = "Не удалось создать прогресс.";
char* szErr02 = "Не удалось загрузить функцию URLDownloadToFile";
char* szErr03 = "Нет связи.";
char* szErr04 = "Не удалось создать временный файл для записи.";
char* szErr05 = "Не удалось. Блокирует Ростелеком!";

HINSTANCE g_hInstance;
BOOL g_bRunning;
DWORD dwColor = RGB(255, 0, 0); // Red
//DWORD dwColor = RGB(0, 0, 255); // Blue
//DWORD dwColor = RGB(0, 128, 0); // Green
#define BUFFSIZE 2048
char szBuff[BUFFSIZE];

static DWORD WINAPI WorkThread(LPVOID)
{
   pURLDownloadToFile = (_URLDownloadToFileA)
      GetProcAddress(LoadLibraryA("urlmon"),
      "URLDownloadToFileA");
   if (!pURLDownloadToFile)
   {
      return DoExit(szErr02);
   }

   char szTempFileName[MAX_PATH];
   GetTempPath(MAX_PATH,szTempFileName);
   lstrcat(szTempFileName,szName);
   if (pURLDownloadToFile(0,szUrl,szTempFileName,0,0))
   {
      return DoExit(szErr03);
   }

   HANDLE hFile;
#ifdef _DEBUG
   hFile = CreateFile(szDebugFileName,
      GENERIC_READ,0,0,OPEN_EXISTING,0,0);
#else
   hFile = CreateFile(szTempFileName,
      GENERIC_READ,0,0,OPEN_EXISTING,0,0);   
#endif

   if (INVALID_HANDLE_VALUE==hFile)
   {
      return DoExit(szErr04);
   }

   DWORD n, dwBytesRead;
   char szResult[BUFFSIZE];
   ReadFile(hFile,szResult,BUFFSIZE,&dwBytesRead,NULL);
   CloseHandle(hFile);
   if (!strstr(szResult,szMatch))
   {
      return DoExit(szErr05);
   }

   char* szToken = strrchr(szResult, ':');
   szToken = strtok(szToken, "<");
   lstrcpyn(szResult, szToken+2, sizeof(szResult));

   n = lstrlen(szResult);
   if (n)   // Скопировать IP-адрес в буфер обмена.
      n = CopyToClipboard(szResult);
   if (!n)
      wsprintf(szBuff,szFormat,szResult);
   else
      wsprintf(szBuff,szFormat2,szResult);

   g_bRunning = 0; // Работа завершена!
   return 0;
}

static DWORD WINAPI ProgressThread(LPVOID)
{
   HWND hwndProgress, hWnd = 0;

   // Найти главное окно программы,
   // в данном случае системный MessageBox.
   while (!hWnd)
   {
      Sleep(50); // Таймаут (небольшой перерыв).
      hWnd = FindWindow(NULL,szAppname);
   }

   // Обеспечивает загрузку библиотеки Comctl32.dll.
   InitCommonControls();

   // Скрыть кнопку OK у MessageBox.
   ShowWindow(GetTopWindow(hWnd),SW_HIDE);

// Вычислить координаты главного окна (т.е. родительского),
// в данном случае, родительское окно, системный MessageBox.
   RECT rect;
   GetClientRect(hWnd,&rect);
   int x = 1;
   int y = rect.bottom - 20;
   int nWidth = rect.right - 2;
   int nHeight = 20;

// Создать прогресс индикатор (Progress Bar).
   hwndProgress = CreateWindow("msctls_progress32",
      "Progress",

// Влияет на вид прогресс бара : PBS_SMOOTH (сплошной).
      WS_VISIBLE | WS_CHILD | PBS_SMOOTH,
// По умолчанию, обычный (см. картинку View Progress Bar Default
//      WS_VISIBLE | WS_CHILD,
      x, y, nWidth, nHeight,
      hWnd,(HMENU)IDC_PROGRESS1,
      g_hInstance,NULL);
   
   if (!hwndProgress)
   {
      return DoExit(szErr01);
   }

   // Создать рабочий поток.
   DWORD tid;
   CreateThread(NULL,0,WorkThread,0,0,&tid);

   // Цвет прогресс индикатора.
   SendMessage(hwndProgress,
      PBM_SETBARCOLOR,0,(LPARAM)dwColor);

   int nMaxRange = 100;
   int nNewPos = 0;

   // Показать прогресс индикатор.
   ShowWindow(hwndProgress,SW_SHOW);

   // Установить диапазон прогресс индикатора.
   SendMessage(hwndProgress,
      PBM_SETRANGE,
      0,(LPARAM)MAKELONG(0,nMaxRange));

   // Пока пользователь не закрыл окно или
   // переменная bRunning не пуста - выполнять цикл.
   while (IsWindowVisible(hWnd) && g_bRunning)
   {
      ++nNewPos; // Прибавить шкалу индикатора прогресса.
      if (nMaxRange == nNewPos)
         nNewPos = 0;

      // Движение прогресс индикатора.
      SendMessage(hwndProgress,PBM_SETPOS,nNewPos,0);
      Sleep(20); // Таймаут. Небольшой переыв.
   }

   // Закрыть прогресс бар.
   DestroyWindow(hwndProgress);

   // Закрыть диалоговое окно (MessageBox) нажав кнопку OK.
   //ShowWindow(GetTopWindow(hWnd),SW_SHOW);
   SendMessage(GetTopWindow(hWnd),BM_CLICK,0,0);

   // Если буфер не содержит текст, обнулить переменную
   // тем самым установив флаг завершить цикл, который
   // идёт в функции WinMain.
   if (!szBuff[0])
      g_bRunning = 0;

   return 0;
}

int DoExit(char* str)
{
   HWND hWnd = FindWindow(NULL,szAppname);
   if (hWnd) // Если окно найдено, закрыть его.
   {
      // Закрыть диалоговое окно (MessageBox) нажав кнопку OK.
      //ShowWindow(GetTopWindow(hWnd),SW_SHOW);
      SendMessage(GetTopWindow(hWnd),BM_CLICK,0,0);
   }

   if (lstrlen(str)) // Если буфер не пуст, показать сообщение.
   {
      lstrcpy(szBuff,str);
      mb(szBuff);
      szBuff[0] = 0;
      g_bRunning = 0;
   }
   return 0;
}

/*
* Начало программы (Entry point).
*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
   g_hInstance = hInstance;
   g_bRunning = 1; // Флаг начала работы.

   DWORD tid; // Создание первого потока.
   CreateThread(NULL,0,ProgressThread,0,0,&tid);
   mb(szMsg); // Вывести сообщение.
   while (g_bRunning) // Пока g_bRunning не нуль, цикл
      Sleep(20); // с небольшой задержкой.
   return DoExit(szBuff);
}

BOOL CopyToClipboard(char* str) {
   // Функция копирует текст в Буфер Обмена.
   BOOL bRet=FALSE;
   CloseClipboard();
   if (OpenClipboard(GetActiveWindow())) {
      EmptyClipboard();
      HGLOBAL GlobalMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE,lstrlen(str)+1);
      if (GlobalMem) {
         char* Data=(char*)GlobalLock(GlobalMem);
         lstrcpy(Data,str);
         GlobalUnlock(GlobalMem);
         if (SetClipboardData(CF_TEXT,GlobalMem))
            bRet=1;
      }
      CloseClipboard();
   }
   return bRet;
}

void mb(char* str) {
   UINT uType=MB_OK | MB_ICONINFORMATION |
   MB_SETFOREGROUND | MB_SYSTEMMODAL;
   int n=0;
   if (strstr(str,"Нет ") || strstr(str,"Не удалось"))
      ++n;
   if (n) {
      uType &=~MB_ICONINFORMATION;
      uType |=MB_ICONWARNING;
   } MessageBox(GetActiveWindow(),str,szAppname,uType);
   if (n) ExitProcess(n);
}
Вложения
GetIP_Asm.zip
(16.03 Кб) Скачиваний: 45
GetIP_Cpp_Progress.zip
(24.68 Кб) Скачиваний: 44
Последний раз редактировалось luzga 29 май 2026, 08:42, всего редактировалось 1 раз.
Аватара пользователя
luzga
Мастер Даунгрейда
 
Сообщения: 320
Зарегистрирован: 04 сен 2025, 19:35

Копирование файлов

Сообщение luzga » 01 июн 2026, 11:09

Я часто копирую. Таким образом сохраняюсь. Написание скриптов на BAT-файлах, такое же программирование, но с меньшими возможностьями.
 Развернуть: Cp.BAT
Код: Выделить всё
@Echo off

REM Копирует все файлы папки с одного места на другое!
REM Как пользоваться ?
REM Расположить этот файл где-то в папке, у меня Bin
REM Сам Bin определён в окружении переменных системы
REM т.е. можно выполнять просто вызвав пункт меню выполнить
REM Win + R ввести команду cp c: h: и нажать Ввод (Enter)
REM Другой способ.
REM Положить этот файл на диск, папку например С:
REM Открыть консоль (черное окошко) из меню Пуск
REM Дать команду C: нажать Ввод (Enter), для перехода на диск
REM С и вводим команду выше

REM svArg1 - откуда копировать
REM svArg2 - куда копировать
set svArg1=%1
set svArg2=%2

REM Проверка, если это Windows 9x - не работать!
REM В версиях Windows 9x XCopy имеет другие параметры.
REM Можете провести исследование и сделать, для другой версии, сами!
if exist "%USERPROFILE%" goto @@10
@echo. Sorry. Need other OS!
goto ERROR

:@@10
if "%svArg1%" == "" (
@echo. Need input drive letter!
goto ERROR
) else (
@echo. Input drive letter %svArg1%
)

if "%svArg2%" == "" (
@echo. Need otput drive letter!
goto ERROR
) else (
@echo. Output drive letter %svArg2%
)
cls
if exist %svArg1% goto @@20
@echo.
@echo.   ---[ MISSING ]---
@echo.
@echo.   %svArg1%
@echo.
pause
goto EXIT

:@@20
if exist %svArg2% goto @@30
@echo.
@echo.   ---[ MISSING ]---
@echo.
@echo.   %svArg2%
@echo.
pause
goto EXIT

:@@30
@echo.
@echo.
@echo.   Copy %svArg1% to %svArg2%
@echo.   Continue ?
@echo.
@echo.   Canceled CTRL+C or Close Window
@echo.
pause

cls
XCopy %svArg1%\*.* %svArg2%\ /Y /C /I /E /R /G /H /K

@echo.
@echo.      -= Done =-
@echo.
pause
goto EXIT

:ERROR
@echo.   ---[ ERROR ]---
@echo.
pause

:EXIT

 Развернуть: Мультик
Изображение
Аватара пользователя
luzga
Мастер Даунгрейда
 
Сообщения: 320
Зарегистрирован: 04 сен 2025, 19:35

Вычислить объём данных из количества процентов

Сообщение luzga » Вчера, 18:54

Вычисляет число из количества процентов.
Например, из винчестера объёмом 80 GB (80 000), узнать сколько будет четыре процента.
Изображение
 Развернуть: CalcPercent.cpp
Код: Выделить всё
// CalcPercent.cpp
//
// Вычисляет число из количества процентов.
// Например, из винчестера объёмом 80 GB (80 000), узнать
// сколько будет четыре процента.

#include <windows.h> // Включить заголовочный файл Windows.
#include <stdio.h> // Включить стандартный заголовочный файл.
void CalcPercent(void); // Функция вычисления процента из числа.
void printfEx(char* svStr); // Функция конвертирует текст (вывод в консоль).
float TBytes = 1099511627776.0; // Макисмальное число ввода.

void main(void) // Основная функция.
{
   char selection;

   do {
      fflush(stdin);

      printfEx("1.  Ввести данные \n");
      printfEx("Q.  Выйти из программы \n");
      printfEx("Enter [Ввод] Выбрать меню: ");

      selection = (char)getchar(); // Захватывает символ для выбора меню, который является '1' или 'q'.
      switch (selection)
      {
         case '1' : // Если пользователь ввел '1', перейте к функции CalcPercent.
            CalcPercent(); // Запускает вычисление.
            break; // Выйти из блока.
         case 'q' : // Если пользователь ввёл 'q', выйти.
            break;
      } // Конец блока 'switch'.

   } while (selection != 'q');
}

void CalcPercent(void)
{
   float total, count, result;
   total = count = result = 0;
   
   while (!result)
   {
      if (!total)
      {
         printfEx("Укажите объём данных (например 80000) : ");
         scanf("%f", &total);
         if (total > TBytes || total < -TBytes)
         {
            printfEx("Некорректное значение.\n");
            total = 0;
         }
      }
      else if (!count)
      {
         printfEx("Укажите количество процентов (например 4) : ");
         scanf("%f", &count);
         if (count > TBytes || count < -TBytes)
         {
            printfEx("Некорректное значение.\n");
            count = 0;
         }
      }
      else if (total && count)
      {
         printfEx("Результат равен ");

         result = (count/100)*total;
         printf("%4.f\n\n", result);
      }
   }
}

void printfEx(char* svStr)
{
   char svBuff[1024];
   size_t size = wsprintf(svBuff, "%s", svStr);
   CharToOemBuffA((const char*)svBuff, svBuff, size);
   printf("%s", svBuff);
}
Вложения
CalcPercent.zip
(24.49 Кб) Скачиваний: 5
Последний раз редактировалось luzga 09 июн 2026, 19:15, всего редактировалось 1 раз.
Аватара пользователя
luzga
Мастер Даунгрейда
 
Сообщения: 320
Зарегистрирован: 04 сен 2025, 19:35

Пред.

Вернуться в Программирование

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

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