Ответы пользователя по тегу C++
  • Как удалить линии вокруг кнопок и прочих элементов в WinAPI?

    SerJook
    @SerJook
    кодер
    Попробуйте так:

    SendMessage(hWndButton, WM_CHANGEUISTATE, MAKEWPARAM(UIS_SET, UISF_HIDEFOCUS), 0);


    Можете отослать это сообщение родительскому окну, и тогда прямоугольник фокуса должен пропасть со всех дочерних контролов.
    Ответ написан
    1 комментарий
  • Как сделать окно игнорирующее нажатия мыши если не зажата клавиша шифт?

    SerJook
    @SerJook
    кодер
    Если говорить про Windows, то:

    Создаете окно с расширенными стилями WS_EX_LAYERED | WS_EX_TRANSPARENT|WS_EX_TOPMOST
    Устанавливаете окну степень прозрачности:
    SetLayeredWindowAttributes(hWnd, 0, 100, LWA_ALPHA);

    Устанавливаете хук на клавиатуру:
    hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardEvent, hInstance, NULL);

    Функция обработки событий клавиатуры (примерный вид):

    код
    LRESULT CALLBACK KeyboardEvent(int nCode, WPARAM wParam, LPARAM lParam)
    {
        if ((nCode == HC_ACTION))
        {
            KBDLLHOOKSTRUCT* hooked_key = (KBDLLHOOKSTRUCT*)lParam; 
            if (hooked_key->vkCode == VK_LSHIFT || hooked_key->vkCode == VK_RSHIFT) {
                bool shiftPressed = (wParam == WM_KEYDOWN);
                LONG oldStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
                if (shiftPressed) {
                    SetWindowLong(hWnd, GWL_EXSTYLE, oldStyle & (~WS_EX_TRANSPARENT));
                }
                else {
                    SetWindowLong(hWnd, GWL_EXSTYLE, oldStyle | WS_EX_TRANSPARENT);
                }
            }
        }
        return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
    }

    В ней динамически устанавливается и снимается расширенный стиль WS_EX_TRANSPARENT.

    При выходе убираете хук:
    UnhookWindowsHookEx(hKeyboardHook);
    Не знаю, как обойтись без хука, ведь неактивному окну не приходят события клавиатуры.
    Ответ написан
    Комментировать
  • Как правильно нарисовать линию в WINAPI?

    SerJook
    @SerJook
    кодер
    Несколько комментариев по вашему коду:

    Переменные Pen, ptPrevious, fDraw не сохраняются между вызовами функции, сделайте их статическими или глобальными. В текущем варианте ваш код создает ОГРОМНОЕ количество GDI-объектов.

    static HPEN Pen =  CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
    static BOOL fDraw = FALSE;
    static POINT ptPrevious = { 0, 0 };


    При обработке WM_PAINT нельзя использовать GetDC(). Если вы не заметили, это нагружает процессор.
    Правильно будет использовать BeginPaint() и EndPaint();

    case WM_PAINT: {
            PAINTSTRUCT ps;
            hdc = BeginPaint(hWnd, &ps);
            // TODO: рисовать здесь
            EndPaint(hWnd, &ps);
            break;
        }


    Чтобы нарисованное не стиралось при обновлении окна, вам надо рисовать в Back Buffer (не знаю, как это по-русски). Для этого вам надо создать BITMAP c помощью CreateCompatibleBitmap, HDC с помощью CreateCompatibleDC, загрузить в созданный HDC BITMAP с помощью SelectObject, и рисовать на HDC. Потом вызывать BitBlt и копировать бэкбуфер в реальный HDC окна (внутри обработчика WM_PAINT).
    Другой вариант (без back buffer): сохраняйте координаты ваших линий в некий массив, и выводите их все в обработчике WM_PAINT.

    Если же вам не нужно, чтоб нарисованное не стиралось, просто уберите обработчик WM_PAINT.

    Еще небольшая придирка: вместо LOWORD(lParam) при получении координат надо использовать GET_X_LPARAM и GET_Y_LPARAM.

    ptPrevious.x = GET_X_LPARAM(lParam);
    ptPrevious.y = GET_Y_LPARAM(lParam);
    Ответ написан
    1 комментарий
  • Как к четырем элементам массива добавить ещё два?

    SerJook
    @SerJook
    кодер
    Используйте std::vector.

    #include <iostream>
    #include <conio.h>
    #include <vector>
    using namespace std;
    
    int main()
    {
        int rez;
        int arr_src[] = {1,8,3,2};
        std::vector<int> arr(arr_src, arr_src + sizeof(arr_src)/sizeof(arr_src[0]));
    
        arr.push_back(7);
        arr.push_back(8);
    
        rez = arr.size();          //кол-во элементов в массиве
        cout << rez << endl;
    
        for (int i = 0; i < rez; i++)
            cout << arr[i] << ' ';
    
        getch();
        return 0;
    }


    Еще у вас ошибка в условии выхода из цикла.
    Ответ написан
    Комментировать
  • Почему нельзя перегрузить оператор?

    SerJook
    @SerJook
    кодер
    В целях оптимизации памяти стандарт языка C++ называет vector<bool> специальным стандартным контейнером, в котором каждый элемент bool использует только один бит памяти вместо того, чтобы занимать 1 байт, как занимает обычный bool. Ценой этой оптимизации является то, что этот контейнер не предоставляет всех возможностей и интерфейс, как это делает нормальный стандартный контейнер.

    Т.к. мы не можем получить адрес отдельного бита в байте, такие вещи, как operator[] не могут вернуть bool&, а вместо этого возвращают прокси-объект, который позволяет манипулировать отдельным битом. Этот прокси не является типом bool&, вы не можете присвоить его адрес указателю с типом bool*, как вы могли бы сделать с "нормальным" контейнером. Это означает что bool &pb =v[0] не является валидным кодом.
    Ответ написан
    Комментировать
  • Как в c++ совместить свойства и лямба функции?

    SerJook
    @SerJook
    кодер
    Не получится это сделать.
    Согласно синтаксису свойства (property) после слова get должно идти имя функции и ни что иное.
    __declspec( property( get=get_func_name, put=put_func_name ) ) declarator

    Когда компилятор видит обращение к этому полю, он заменяет его на обращение к функциям get или put.
    Ответ написан
  • Можно ли вывести список enum?

    SerJook
    @SerJook
    кодер
    На чистых плюсах решения получаются трудно поддерживаемыми, можно воспользоваться библиотекой better-enums.

    #include "enum.h"
    
    BETTER_ENUM(etype, int, laborer, secretary, manager, accountant, executive, researcher);
    
    //...
    struct employee {
        int number;
        float pension;
        etype post = etype::laborer;
        date start;
    };
    
    int main()
    {
        //... пропущено
        for (etype i : etype::_values())
        {
            std::cout << i << " ";
        }
        std::cout << std::endl;
        std::string etypeStr;
        std::cin >> etypeStr;
        first.post = etype::_from_string(etypeStr.c_str());   
    }
    Ответ написан
    Комментировать
  • [C++] Как получить размер и длительность аудиофайла по URL?

    SerJook
    @SerJook
    кодер
    Можно воспользоваться библиотекой ffmpeg. Для этого эта библиотека должна быть собрана с поддержкой сети. Для соединений https нужно собрать с поддержкой openssl.

    Вот приблизительный код, который получает длительность и размер файла:

    extern "C"
    {
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    }
       
    ... 
    const char    *url = "http://localhost/test.mp3";
    AVFormatContext *pFormatCtx = NULL;
    int ret = avformat_open_input(&pFormatCtx, url, NULL, NULL);
    if (ret >= 0) {
            avformat_find_stream_info(pFormatCtx, NULL);
            int seconds = (pFormatCtx->duration / AV_TIME_BASE);
            int64_t size = avio_size(pFormatCtx->pb);
            avformat_close_input(&pFormatCtx);
            avformat_free_context(pFormatCtx);
    }


    Как показала практика, этот код не скачивает файл полностью, а лишь начальный кусок.
    Ответ написан
    1 комментарий
  • Как настроить перерисовку окна диалога при его деактивации [MFC C++]?

    SerJook
    @SerJook
    кодер
    Попробуйте переопределить ON_WM_NCACTIVATE и ON_WM_ACTIVATE:

    void CMFCApplication1Dlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) {
        Default();
    }
    
    BOOL CMFCApplication1Dlg::OnNcActivate(BOOL active)
    {
        if (m_nFlags & WF_STAYACTIVE)
            active = TRUE;
        return(BOOL)DefWindowProc(WM_NCACTIVATE, active, 0L);
    }


    Взято отсюда: https://stackoverflow.com/questions/53768653/mfcs-...
    Ответ написан
    Комментировать
  • Работа с графикой. С++ builder. Как нарисовать рамку вокруг рисунка?

    SerJook
    @SerJook
    кодер
    В зависимости от того, какая рамка вам нужна, я сделал в классе MyBitmap 2 метода: AddBorderOutside() и AddBorderInside().
    Я без понятия, скомпилируется ли код в C++ Builder, потому что я использовал Visual Studio.

    Код под спойлером
    #include <fstream>
    #include <ios>
    #include <ctime>
    #include <iostream>
    #include <windows.h>
    
    class MyBitmap {
        BITMAPFILEHEADER header_;
        BITMAPINFOHEADER info_;
        bool loaded_;
        char* pixels_;
        size_t data_size_;
        size_t row_padded_;
    public:
        MyBitmap(const char* fileName) {
            loaded_ = false;
            pixels_ = 0;
            std::ifstream bmp(fileName, std::ios::binary);
            if (!bmp) {
                return;
            }
            bmp.read((char*)&header_, sizeof(header_));
            if (!bmp) {
                return;
            }
            if (header_.bfType != 'MB') {
                std::cout << "Format is not supported" << std::endl;
                return;
            }
            bmp.read((char*)&info_, sizeof(info_));
    
            if (!bmp) {
                return;
            }
    
            if (info_.biBitCount != 24) {
                std::cout << "Format is not supported" << std::endl;
                return;
            };
    
            row_padded_ = (info_.biWidth * 3 + 3) & (~3);
            int height = info_.biHeight; 
            data_size_ = row_padded_ * height;
            pixels_ = new char[data_size_];
            bmp.read(pixels_, data_size_);
    
            if (bmp) {
                loaded_ = true;
            }
            return;
        }
    
        bool Save(const char* fileName) {
            if (!loaded_) {
                return false;
            }
            std::ofstream f(fileName, std::ios::binary);
            
            if (!f) {
                return false;
            }
            f.write((char*)&header_, sizeof(header_));
            f.write((char*)&info_, sizeof(info_));
            f.write(pixels_, data_size_);
            if (f) {
                return true;
            }
            return false;
        }
    
        void AddBorderInside(int borderSize = 15) {
            for (int i = 0; i < info_.biWidth; i++) {
                for (int j = 0; j < info_.biHeight; j++) {
                    if (i < borderSize || i >= info_.biWidth - borderSize 
                        || j < borderSize || j >= info_.biHeight - borderSize) {
                        int pos = row_padded_* j + i * 3;
                        pixels_[pos] = rand() % 256;
                        pixels_[pos + 1] = rand() % 256;
                        pixels_[pos + 2] = rand() % 256;
                    }
                }
            }
        }
    
        void AddBorderOutside(int borderSize = 15) {
            int new_width = info_.biWidth + borderSize * 2;
            int new_row_padded = (new_width * 3 + 3) & (~3);
            int new_height = info_.biHeight + borderSize * 2;
            int new_data_size = new_row_padded * new_height;
    
            char* new_pixels_ = new char[new_data_size];
            for (int i = 0; i < info_.biHeight; i++) {
                int old_pos = row_padded_* i;
                int new_pos = new_row_padded * (borderSize+i) +3 * borderSize;
                memcpy(new_pixels_ + new_pos, pixels_ + old_pos, info_.biWidth * 3);
            }
    
            delete[] pixels_;
            info_.biWidth = new_width;
            info_.biHeight = new_height;
            pixels_ = new_pixels_;
            row_padded_ = new_row_padded;
            data_size_ = new_data_size;
            AddBorderInside(borderSize);
        }
    
        bool IsLoaded() const {
            return loaded_;
        }
    
        ~MyBitmap() {
            delete[] pixels_;
        }
    
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        srand(time(0));
        MyBitmap bmp("input.bmp");
    
        if (!bmp.IsLoaded()) {
            std::cout << "Unable to load bitmap" << std::endl;
            return 1;
        }
        bmp.AddBorderOutside();
        if (!bmp.Save("output.bmp")) {
            std::cout << "Unable to save bitmap" << std::endl;
        }
    	return 0;
    }
    Ответ написан
    Комментировать
  • Qt checkbox this combobox?

    SerJook
    @SerJook
    кодер
    Посмотрите, как сделано здесь
    https://habr.com/ru/post/215289/
    Ответ написан
    Комментировать
  • Как передать cookies из WinInet в WinSock?

    SerJook
    @SerJook
    кодер
    Сначала посылаете запрос с помощью WinInet, потом вызываете функцию InternetGetCookie с нужным вам URL и получаете куки. Но учтите, что она может вернуть не все куки:

    InternetGetCookie does not return cookies that the server marked as non-scriptable with the "HttpOnly" attribute in the Set-Cookie header.


    Полученные таким образом куки отправляете через сокеты (Добавив в заголовки запроса HTTP-заголовок "Cookie")
    Ответ написан
    Комментировать
  • Как сделать приложение независимым от VC++ Redistributable?

    SerJook
    @SerJook
    кодер
    Подключай статический рантайм, и тогда не будет зависимости.
    Свойства солюшена -> C\C++ -> Code generation -> Runtime Library -> Multi-threaded (/MT)
    5c461267175c3212801722.png
    Ответ написан
  • Как правильно вставить данные на форму и отправить (На сайте)?

    SerJook
    @SerJook
    кодер
    Вы пытаетесь отправить запрос в неправильном формате.
    Вам скорее всего нужен формат application/x-www-form-urlencoded.
    Нужно использовать не id полей, а их имена (name). Также возможно в запрос нужно включить кнопку отправки(submit button), если у нее есть имя. Часто на стороне сервера проверяют наличие кнопки в запросе.

    QNetworkRequest request(QUrl("http://site.net/index.php"));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
    
    QUrlQuery postData;
    postData.addQueryItem("username", login);
    postData.addQueryItem("password", pass);
    postData.addQueryItem("submit_button", "Submit!");
    
    QNetworkAccessManager * pManager = new QNetworkAccessManager(this);
    QNetworkReply * reply = pManager->post(request, postData.toString(QUrl::FullyEncoded).toUtf8());
    Ответ написан
  • Что делает SetProcessDPIAware() ???

    SerJook
    @SerJook
    кодер
    Пользователь может выставить масштаб отличный от 100% в настройках экрана. Вызывая эту функцию (SetProcessDPIAware), вы сообщаете системе, что интерфейс вашего приложения умеет сам правильно масштабироваться при высоких значениях DPI (точки на дюйм). Если вы не выставите этот флаг, то интерфейс вашего приложения может выглядеть размыто при высоких значениях DPI.

    Но Microsoft рекомендует не вызывать эту функцию, а прописать этот флаг в манифесте приложения.
    Ответ написан
    1 комментарий
  • Какой аналог ComputeHash класса HMACSHA1 из C# есть в C++?

    SerJook
    @SerJook
    кодер
    Можно использовать openssl

    #include <openssl/hmac.h>
    // ...
    std::string key = ... ;
    unsigned char timeArray[8] = ... ;
    unsigned char* hashedData = HMAC(EVP_sha1(), &key[0], key.length(), timeArray, sizeof(timeArray), NULL, NULL);  
    // hashedData указывает на 20 байт хэша
    Ответ написан
    Комментировать
  • Как узнать путь процесса по его имени?

    SerJook
    @SerJook
    кодер
    Будет работать на Windows Vista и новее. Используется функция QueryFullProcessImageName.

    #include <windows.h>
    #include <tlhelp32.h>
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        PROCESSENTRY32 entry;
        entry.dwSize = sizeof(PROCESSENTRY32);
    
        HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    
        if (Process32First(snapshot, &entry) == TRUE) {
            while (Process32Next(snapshot, &entry) == TRUE) {
                if (_tcsicmp(entry.szExeFile, _T("explorer.exe")) == 0) {
                    HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, entry.th32ProcessID);
    
                    if (hProcess) {
                        TCHAR path[MAX_PATH];
                        DWORD cchExeName = MAX_PATH;
                        
                        if (QueryFullProcessImageName(hProcess, 0, path, &cchExeName) != 0) {
                            _tprintf(_T("%s\r\n"), path);
                        } 
    
                        CloseHandle(hProcess);
                    }   
                }
            }
        }
    
        CloseHandle(snapshot);
    
        return 0;
    }
    Ответ написан
  • Как при выводе текста из файла C++ запретить заменять Знаки препинания?

    SerJook
    @SerJook
    кодер
    Можно читать посимвольно и сравнивать каждый символ с разделителями. Складывать токены (найденные слова и разделители) в массив и выводить по мере наполнения в нужном порядке.

    #include <iostream>
    #include <string>
    #include <fstream>
    
    using namespace std;
    
    int main(int argc, const char * argv[]) {
        ifstream file("file.txt");
        if (!file) {
            std::cout << "Unable to open file" << std::endl;
        }
        string separators = " \t\r\n,.!?;:";
        int i = 0;
        char c;
        bool lastWasSep = true;
        std::string tokens[4];
        std::string curToken;
    
        while (file.get(c)) {
            bool isSep = separators.find(c) != string::npos;
            if (lastWasSep == isSep) {
                curToken += c;
            } else {
                tokens[i++] = curToken;
                curToken = c;
            }
            lastWasSep = isSep;
    
            if (i == 4) {
                cout << tokens[0] << tokens[3] << tokens[2] << tokens[1];
                i = 0;
            }
        }
        tokens[i++] = curToken;
        if (i == 4) {
            cout << tokens[0] << tokens[3] << tokens[2] << tokens[1];
        } else {
            for (int j = 0; j < i; j++) {
                cout << tokens[j];
            }
        }
    
        return 0;
    }
    Ответ написан
    Комментировать
  • В какой среде разрабатывают интерфейс для программ на C++?

    SerJook
    @SerJook
    кодер
    Я разрабатываю интерфейс в Visual Studio в редакторе диалогов и использую библиотеку WTL.
    Только вам не советую, потому что это очень устаревший подход и библиотека.
    Ответ написан
    Комментировать
  • Можно ли в Qt соединить сигналы с разными параметрами с одним единственным слотом?

    SerJook
    @SerJook
    кодер
    У вас соединение только с помощью строк SIGNAL() SLOT()?

    Вот вариант для нового способа соединения:
    Если все параметры могут быть преобразованы в QVariant и используется С++11, можно попробовать как-то так:

    signals:
        void someSignal1(QString a);
        void someSignal2(int a, QString b);
        void someSignal3(float a, int b, QString c);
    ...
       void someSlot(QVariant arg1,QVariant arg2, QVariant arg3);


    и соединение сигналов и слотов:
    connect(sender, &Sender::someSignal1, std::bind( &Receiver::someSlot, receiver, std::placeholders::_1, QVariant(), QVariant() ));
    connect(sender, &Sender::someSignal2, std::bind( &Receiver::someSlot, receiver, std::placeholders::_1, std::placeholders::_2, QVariant()));
    connect(sender, &Sender::someSignal3, std::bind( &Receiver::someSlot, receiver, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3 ));


    Проще я не смог придумать
    Ответ написан
    2 комментария