Ответы пользователя по тегу Visual Studio
  • Ошибка в Visual studio opengl. Как решить?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Ошибка LNK2019 относится к стадии линковки и означает что среди всех объектов линковки так и не нашлось определение обозначенной в ошибке функции.

    __imp_glClear и __imp_glDrawArrays - это стандартные функции OpenGL, определены они в библиотеке opengl32.lib, которую и требуется подключить как внешнюю зависимость к твоему проекту.

    Зависимости в проект подключаются через свойства проекта Visual Studio.
    Ответ написан
    5 комментариев
  • Почему сплайны OpenGL прорисовываются не на всех компьютерах?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Дело в том, что функция glMap1[?] имеет довольно узкий коридор поддержки. Она была введена в OpenGL 1.0 и удалена из поддержки в OpenGL 3.2 Core Profile.

    Т.к. ты пользуешься wglCreateContext, система сама решает какой контекст ей для тебя создавать. Это может быть и контекст с версией 4.6, в котором уже нет поддержки функции glMap1f.
    Тебе стоит более точно указывать версию создаваемого контекста. Это можно сделать с помощью расширения WGL_ARB_create_context. Функция wglCreateContextAttribsARB позволяет задавать атрибуты для создаваемого контекста, среди которых ты можешь обозначить и требуемую версию.

    В качестве примера использования этого расширения можно взять такой код.
    Код примера
    // Sample code showing how to create a modern OpenGL window and rendering context on Win32.
    
    #include <windows.h>
    #include <gl/gl.h>
    #include <stdbool.h>
    
    typedef HGLRC WINAPI wglCreateContextAttribsARB_type(HDC hdc, HGLRC hShareContext,
            const int *attribList);
    wglCreateContextAttribsARB_type *wglCreateContextAttribsARB;
    
    // See https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_create_context.txt for all values
    #define WGL_CONTEXT_MAJOR_VERSION_ARB             0x2091
    #define WGL_CONTEXT_MINOR_VERSION_ARB             0x2092
    #define WGL_CONTEXT_PROFILE_MASK_ARB              0x9126
    
    #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB          0x00000001
    
    typedef BOOL WINAPI wglChoosePixelFormatARB_type(HDC hdc, const int *piAttribIList,
            const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
    wglChoosePixelFormatARB_type *wglChoosePixelFormatARB;
    
    // See https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_pixel_format.txt for all values
    #define WGL_DRAW_TO_WINDOW_ARB                    0x2001
    #define WGL_ACCELERATION_ARB                      0x2003
    #define WGL_SUPPORT_OPENGL_ARB                    0x2010
    #define WGL_DOUBLE_BUFFER_ARB                     0x2011
    #define WGL_PIXEL_TYPE_ARB                        0x2013
    #define WGL_COLOR_BITS_ARB                        0x2014
    #define WGL_DEPTH_BITS_ARB                        0x2022
    #define WGL_STENCIL_BITS_ARB                      0x2023
    
    #define WGL_FULL_ACCELERATION_ARB                 0x2027
    #define WGL_TYPE_RGBA_ARB                         0x202B
    
    static void
    fatal_error(char *msg)
    {
        MessageBoxA(NULL, msg, "Error", MB_OK | MB_ICONEXCLAMATION);
        exit(EXIT_FAILURE);
    }
    
    static void
    init_opengl_extensions(void)
    {
        // Before we can load extensions, we need a dummy OpenGL context, created using a dummy window.
        // We use a dummy window because you can only set the pixel format for a window once. For the
        // real window, we want to use wglChoosePixelFormatARB (so we can potentially specify options
        // that aren't available in PIXELFORMATDESCRIPTOR), but we can't load and use that before we
        // have a context.
        WNDCLASSA window_class = {
            .style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
            .lpfnWndProc = DefWindowProcA,
            .hInstance = GetModuleHandle(0),
            .lpszClassName = "Dummy_WGL_djuasiodwa",
        };
    
        if (!RegisterClassA(&window_class)) {
            fatal_error("Failed to register dummy OpenGL window.");
        }
    
        HWND dummy_window = CreateWindowExA(
            0,
            window_class.lpszClassName,
            "Dummy OpenGL Window",
            0,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            0,
            0,
            window_class.hInstance,
            0);
    
        if (!dummy_window) {
            fatal_error("Failed to create dummy OpenGL window.");
        }
    
        HDC dummy_dc = GetDC(dummy_window);
    
        PIXELFORMATDESCRIPTOR pfd = {
            .nSize = sizeof(pfd),
            .nVersion = 1,
            .iPixelType = PFD_TYPE_RGBA,
            .dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
            .cColorBits = 32,
            .cAlphaBits = 8,
            .iLayerType = PFD_MAIN_PLANE,
            .cDepthBits = 24,
            .cStencilBits = 8,
        };
    
        int pixel_format = ChoosePixelFormat(dummy_dc, &pfd);
        if (!pixel_format) {
            fatal_error("Failed to find a suitable pixel format.");
        }
        if (!SetPixelFormat(dummy_dc, pixel_format, &pfd)) {
            fatal_error("Failed to set the pixel format.");
        }
    
        HGLRC dummy_context = wglCreateContext(dummy_dc);
        if (!dummy_context) {
            fatal_error("Failed to create a dummy OpenGL rendering context.");
        }
    
        if (!wglMakeCurrent(dummy_dc, dummy_context)) {
            fatal_error("Failed to activate dummy OpenGL rendering context.");
        }
    
        wglCreateContextAttribsARB = (wglCreateContextAttribsARB_type*)wglGetProcAddress(
            "wglCreateContextAttribsARB");
        wglChoosePixelFormatARB = (wglChoosePixelFormatARB_type*)wglGetProcAddress(
            "wglChoosePixelFormatARB");
    
        wglMakeCurrent(dummy_dc, 0);
        wglDeleteContext(dummy_context);
        ReleaseDC(dummy_window, dummy_dc);
        DestroyWindow(dummy_window);
    }
    
    static HGLRC
    init_opengl(HDC real_dc)
    {
        init_opengl_extensions();
    
        // Now we can choose a pixel format the modern way, using wglChoosePixelFormatARB.
        int pixel_format_attribs[] = {
            WGL_DRAW_TO_WINDOW_ARB,     GL_TRUE,
            WGL_SUPPORT_OPENGL_ARB,     GL_TRUE,
            WGL_DOUBLE_BUFFER_ARB,      GL_TRUE,
            WGL_ACCELERATION_ARB,       WGL_FULL_ACCELERATION_ARB,
            WGL_PIXEL_TYPE_ARB,         WGL_TYPE_RGBA_ARB,
            WGL_COLOR_BITS_ARB,         32,
            WGL_DEPTH_BITS_ARB,         24,
            WGL_STENCIL_BITS_ARB,       8,
            0
        };
    
        int pixel_format;
        UINT num_formats;
        wglChoosePixelFormatARB(real_dc, pixel_format_attribs, 0, 1, &pixel_format, &num_formats);
        if (!num_formats) {
            fatal_error("Failed to set the OpenGL 3.3 pixel format.");
        }
    
        PIXELFORMATDESCRIPTOR pfd;
        DescribePixelFormat(real_dc, pixel_format, sizeof(pfd), &pfd);
        if (!SetPixelFormat(real_dc, pixel_format, &pfd)) {
            fatal_error("Failed to set the OpenGL 3.3 pixel format.");
        }
    
        // Specify that we want to create an OpenGL 3.3 core profile context
        int gl33_attribs[] = {
            WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
            WGL_CONTEXT_MINOR_VERSION_ARB, 3,
            WGL_CONTEXT_PROFILE_MASK_ARB,  WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
            0,
        };
    
        HGLRC gl33_context = wglCreateContextAttribsARB(real_dc, 0, gl33_attribs);
        if (!gl33_context) {
            fatal_error("Failed to create OpenGL 3.3 context.");
        }
    
        if (!wglMakeCurrent(real_dc, gl33_context)) {
            fatal_error("Failed to activate OpenGL 3.3 rendering context.");
        }
    
        return gl33_context;
    }
    
    static LRESULT CALLBACK
    window_callback(HWND window, UINT msg, WPARAM wparam, LPARAM lparam)
    {
        LRESULT result = 0;
    
        switch (msg) {
            case WM_CLOSE:
            case WM_DESTROY:
                PostQuitMessage(0);
                break;
            default:
                result = DefWindowProcA(window, msg, wparam, lparam);
                break;
        }
    
        return result;
    }
    
    static HWND
    create_window(HINSTANCE inst)
    {
        WNDCLASSA window_class = {
            .style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
            .lpfnWndProc = window_callback,
            .hInstance = inst,
            .hCursor = LoadCursor(0, IDC_ARROW),
            .hbrBackground = 0,
            .lpszClassName = "WGL_fdjhsklf",
        };
    
        if (!RegisterClassA(&window_class)) {
            fatal_error("Failed to register window.");
        }
    
        // Specify a desired width and height, then adjust the rect so the window's client area will be
        // that size.
        RECT rect = {
            .right = 1024,
            .bottom = 576,
        };
        DWORD window_style = WS_OVERLAPPEDWINDOW;
        AdjustWindowRect(&rect, window_style, false);
    
        HWND window = CreateWindowExA(
            0,
            window_class.lpszClassName,
            "OpenGL",
            window_style,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            rect.right - rect.left,
            rect.bottom - rect.top,
            0,
            0,
            inst,
            0);
    
        if (!window) {
            fatal_error("Failed to create window.");
        }
    
        return window;
    }
    
    int WINAPI
    WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd_line, int show)
    {
        HWND window = create_window(inst);
        HDC gldc = GetDC(window);
        HGLRC glrc = init_opengl(gldc);
    
        ShowWindow(window, show);
        UpdateWindow(window);
    
        bool running = true;
        while (running) {
            MSG msg;
            while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
                if (msg.message == WM_QUIT) {
                    running = false;
                } else {
                    TranslateMessage(&msg);
                    DispatchMessageA(&msg);
                }
            }
    
            glClearColor(1.0f, 0.5f, 0.5f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
            // Do OpenGL rendering here
    
            SwapBuffers(gldc);
        }
    
        return 0;
    }
    Ответ написан
    Комментировать
  • Как разрабатывать оконные приложения на С++ в Visual Studio 2019?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Самым простым решением для разработки GUI-приложений в среде MSVS2019 будет использование Qt. Собственно, для этого тебе потребуется Qt. Но разработку вести ты cможешь в VS.

    Вторым решением будет чуть более сложное: использование C++/CX вместе с UWP / Windows Forms.

    Третьим решением, еще более сложным, будет использование уже чистого C++ при поддержке MFC или WTL.

    И самым сложным решением будет прямое использование WinAPI.

    Помимо всего этого еще можно воспользоваться библиотекой wxWidgets и на ее базе разработать GUI для своего приложения.
    Ответ написан
    1 комментарий
  • Не могу запустить код в visual studio почему?

    @MarkusD
    все время мелю чепуху :)
    long long matr[1001][1001] - это будет 8016008 байт, 7.645МБ.
    Стандартный размер стека в MS Visual Studio задан в 1МБ. Естественно, при объявлении настолько большого массива ты сразу получишь Stack Overflow.

    Выходов из данной ситуации несколько.
    Выход первый - подойти к вопросу рассудительно. Тебе точно нужен именно статический массив в 8МБ именно на стеке? Я думаю что нет. Я думаю что тебе нужен std::vector, в котором ты сможешь легко разместить все 1002001 элементов. На самом деле и двумерность массива тебе тоже не очень нужна, т.к. на самом деле она тебя сейчас только запутывает. Через простую функцию от двух аргументов можно легко перейти от двух индексов к индексу в линейном массиве.

    Выход второй - вынести свой статический массив за пределы контекста функции. Это можно сделать, объявив этот массив как static или объявив его в глобальной области видимости.

    Выход третий, которым я советую не пользоваться без однозначного понимания своих действий.
    Можно изменить размер стека через настройки линкера.
    В свойствах проекта: Configuration Properties -> Linker -> System:
    Stack Reserve Size - значение в байтах, это максимальный размер стека для потока. Его можно изменить хоть до 32МБ и больше.

    Подвох с этим значением в том, что потоков у твоего приложения не один даже если само твое приложение является однопоточным. Вместе с твоим главным потоком работает еще несколько служебных. Их стек тоже будет расширен. Это все приводит к увеличению потребления памяти.
    Обычно размер стека по умолчанию не трогают или сжимают до 64КБ, т.к. большинству потоков этого более чем достаточно. А вот для требовательных потоков, обычно, отдельно расширяют стек до требуемых размеров в момент создания потока.
    Таким образом достигается контроль памяти. Даже сегодня бывают случаи, когда ее бывает мало.
    Ответ написан
    Комментировать
  • Как настроить локальное хранилище отладочных символов в Visual Studio?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    В дереве настроек студии есть раздел "Debugging", там есть подраздел "Symbols". Среди настроек этого подраздела есть поле "Cache symbols in this directory" для указания пути, куда, собственно, и стоит сохранять загруженные отладочные символы.
    Ответ написан
    Комментировать
  • Как проверить на утечки памяти?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Больше трех лет пользуюсь инструментом Visual Leak Detector. Это тихий и неприхотливый инструмент, требующий соблюдения всего двух правил: вписать один include в одном cpp и собрать отладочную конфигурацию проекта.

    После завершения отлаживаемого процесса, VLD пишет в (файл/консоль/debug output) все найденные утечки со стеками выделения утекшей памяти. К отчету об утечке, помимо стека, еще добавляется HEX dump самого участка памяти, чтобы можно было на глаз сориентироваться, что за память утекла.
    А если утечек нет, VLD утешительно говорит что все нормально.

    Проект является открытым, доступен на github, стабильно развивается, выкладывается для современных версий Visual Studio и доступен из Extensions Manager самой студии.

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

    Ну и, безусловно, всегда есть valgrind memcheck, который по своей сути является sandbox-ом памяти и с радостью покажет тебе не только утечку, но и любой heap corruption, любое неправомерное обращение к памяти, которое ты будешь просто не в состоянии отловить руками или глазами.
    Насколько я помню, за последние 2-3 года valgrind так и не стал кроссплатформенным.
    Ответ написан
    4 комментария
  • Как совместить 2 языка С++ и C#?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    2. Писать на С++/CLI. Только тут я не понимаю, как их совместить.
    Ну написал я код на С++/CLI, а как мне его в проект , написанный на С# вставить ?


    Этот вариант неплохо разжеван в этих двух вопросах.
    Можно ли совместить в одном проекте программы написанные на разных языках (C++, C#) в VS2012?
    Как динамически подключать библиотеки?

    Этот вариант на деле оказался самым удачным, потому что деление проекта на три части (C++; CLI; C#) так же строго делит и области ответственности. На стороне C# остается только интерфейс, на стороне CLI - только связь с низким уровнем, на стороне C++ - только низкий уровень.
    Целостность кода сохраняется, библиотеку низкого уровня можно с равной легкостью подключить как к библиотеке CLI, так и к другому низкоуровневому проекту.
    Ответ написан
  • Как динамически подключать библиотеки?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    lightalex , да, описанное тобой поведение возможно.
    У меня есть очень старый проект одной утилиты. Там практически реализовано необходимое тебе.

    Вот самая основа, которая может тебя заинтересовать.
    https://github.com/FrankStain/tex-conv/blob/master...
    Это - функция обнаружения и загрузки всех плагинов в определенной директории.

    https://github.com/FrankStain/tex-conv/blob/master...
    Это - функция выгрузки плагинов.
    Ответ написан
    4 комментария
  • Можно ли совместить в одном проекте программы написанные на разных языках (C++, C#) в VS2012?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    https://github.com/FrankStain/tex-conv
    Это пример такого проекта. Многозадачный конвертер текстур.

    На верхнем уровне лежит C# приложение с UI на WinForms, вся работа с пользователем выполнена именно тут.
    К верхнему уровню подключается C++/CLI ядро, представляющее собой библиотеку классов. Это ядро связывает верхний уровень с нижним, который представлен потенциально несчетным набором плагинов.

    Библиотека классов в C# используется как будто это рядовой модуль.

    Конкретно для твоего случая я порекомендую поступить так.
    • Нижний уровень - проект статической библиотеки, в которой будет весь твой C++ код.
    • Средний уровень - C++/CLI библиотека классов, в которую и линкуется нижний уровень, свяжет нижний уровень с верхним через свои классы.
    • Высокий уровень C# приложение, использующее классы среднего уровня.
    Ответ написан
    Комментировать
  • Какой смысл в фильтрах Visual Studio?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Фильтры в Visual C++ - это методика организации рабочего пространства. Это старая и проверенная методика, зарекомендовавшая себя в MSVC++ еще с очень старых времен.
    Система фильтров позволяет организовать любую лапшу из файлов сторонней библиотеки, в которой все сделано по принципу: "Работает == Не трогай". Этим она чрезвычайно полезна.
    Так же фильтры позволяют сделать более тонкую организацию в тех местах, где на уровне файловой структуры она бессмысленна.

    Я бы не был так поспешен, ругая инструмент за то, что им пользуются явно неорганизованные или неграмотные "специалисты". В подавляющем большинстве проектов ты просто видел невежество. И ничего больше.
    Да, фильтры никак не привязаны к реальным папкам, а это и не надо. Да, на диске все можно хранить в одной папке (и в этом реальный плюс фильтров). Да, фильтры позволяют организоваться только внутри пространства самой среды.
    Но и ничего больше.
    Многие люди не считают должным разделять заголовки и исходный код по разным папкам, пеняя на "слишком сложную" организацию Include Directories. Только это не проблема среды, это такой у людей стиль организации рабочего пространства.
    Ответ написан
    3 комментария
  • Как обойтись без библиотеки импорта?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Библиотека импорта для dll - это вспомогательный артефакт связывания основного образа программы с динамическим модулем.
    В общем - никак, раз уж явную загрузку тебе не предлагать. :)

    Иное дело - это твои хитромудреные манипуляции для установления зависимости между основным и динамическими модулями. Зачем тебе потребовалось явно указывать линковку с lib файлом?
    У каждого проекта студии есть список зависимостей (References). Если в проекте главного модуля программы установить зависимость от проекта динамической библиотеки, то msbuild все свяжет за тебя.

    А еще есть нестандартная но широко поддерживаемая #pragma comment(lib,"xxx.lib").
    Ответ написан
    Комментировать