Naivgating to a page using the XAML Hosting API in a Win32 program causes an access violation - c++

I'm using the XAML hosting API to host XAML content in my win32 program. I have successfully initialized the hosting framework and created DesktopWindowXamlSource objects. I have set the Content() of my DesktopWindowXamlSource to a Frame. My problem occurs whenever I try to navigate to a page with that Frame.
To create a Page for my program to use, I followed these steps:
Make IDL definition
namespace Program
{
[default_interface]
runtimeclass SettingsPage: Windows.UI.Xaml.Controls.Page
{
SettingsPage();
}
}
I build the project, copy the generated header and source file from project_root_folder\Debug\Generated Files\sources to the project's root. I then add the files using the Solution Explorer.
I delete the static_assert from each of the files.
I build the project, then I try to navigate to the page by using ContentFrame.Navigate(xaml_typename<winrt::Program::SettingsPage>);
The DesktopWindowXamlSource's content is set to ContentFrame. Every time I try to navigate to the page, I get this error:
Exception thrown at 0x00007FFA08C08106 (Windows.UI.Xaml.dll) in Program.exe: 0xC0000005: Access violation reading location 0x0000000000000000.
My Entrypoint and WindowProc:
#include "pchRT.h"
#include <Windows.h>
#include <windowsx.h>
#include "UIEngine.h"
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static UI::UIEngine* uiEngine{ nullptr };
switch (msg)
{
case WM_CREATE:
uiEngine = new UI::UIEngine{ reinterpret_cast<HMODULE>(GetWindowLongPtrW(hWnd, GWLP_HINSTANCE)), hWnd };
break;
case WM_GETMINMAXINFO:
{
const auto mmInfo{ reinterpret_cast<LPMINMAXINFO>(lParam) };
mmInfo->ptMinTrackSize.x = 876;
mmInfo->ptMinTrackSize.y = 565;
}
break;
case WM_SIZE:
if (uiEngine)
{
//...
}
break;
case WM_DESTROY:
delete uiEngine;
winrt::uninit_apartment();
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int nCmdShow)
{
PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY handlePolicy{0};
handlePolicy.HandleExceptionsPermanentlyEnabled = 1;
handlePolicy.RaiseExceptionOnInvalidHandleReference = 1;
SetProcessMitigationPolicy(ProcessStrictHandleCheckPolicy, &handlePolicy, sizeof PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY);
WNDCLASSEXW wc{
sizeof WNDCLASSEXW, CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, WindowProc, 0, 0, hInstance, nullptr,
reinterpret_cast<HCURSOR>(LoadImageW(nullptr, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED)),
reinterpret_cast<HBRUSH>(COLOR_WINDOWTEXT), nullptr, L"Settings Manager", nullptr
};
const auto hWnd{
CreateWindowExW(WS_EX_LAYERED, MAKEINTATOM(RegisterClassExW(&wc)), L"Settings Manager", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, nullptr, hInstance, nullptr)
};
SetLayeredWindowAttributes(hWnd, 0, 255, LWA_ALPHA);
ShowWindow(hWnd, nCmdShow);
MSG msg;
while (GetMessageW(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return 0;
}
UIEngine header:
#pragma once
#include "pchRT.h"
#include "resource.h"
#include "MainPage.h"
#include <Windows.h>
#include <dwmapi.h>
#include <string>
#include <fstream>
#include <memory>
#include <vector>
namespace UI
{
class UIEngine
{
HWND XamlIslandsWindow{}, CaptionIslandsWindow{}, Window;
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource DesktopWindowXamlSource;
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource CaptionXamlSource;
winrt::Windows::UI::Xaml::Controls::Grid CaptionGrid, PanelGrid{ nullptr };
winrt::Windows::UI::Xaml::Controls::Frame ContentFrame;
bool HandleOverlap;
RECT ClientArea;
HINSTANCE AppInstance;
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::Streams::IRandomAccessStream>
ExtractAndLoadResource(
int resourceId, LPCWSTR resourceType) const;
static winrt::Windows::UI::Xaml::FrameworkElement FindElement(
winrt::Windows::UI::Xaml::FrameworkElement const& startElement, PCWCH name);
public:
explicit UIEngine(HINSTANCE appInstance, HWND hWnd);
};
}
UIEngine implementation:
#include "pchRT.h"
#include "UIEngine.h"
using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Xaml::Media;
using namespace winrt::Windows::UI;
using namespace winrt::Windows::UI::Composition;
using namespace winrt::Windows::UI::Xaml::Input;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Numerics;
using namespace winrt::Windows::Storage::Streams;
using namespace winrt::Windows::UI::Xaml::Media::Imaging;
using namespace winrt::Windows::UI::Xaml::Controls::Primitives;
namespace UI
{
UIEngine::UIEngine(const HINSTANCE appInstance, const HWND hWnd) : Window(hWnd), HandleOverlap(false), AppInstance(appInstance)
{
init_apartment();
auto windowInterop{ DesktopWindowXamlSource.as<IDesktopWindowXamlSourceNative>() }, windowInterop2{
CaptionXamlSource.as<IDesktopWindowXamlSourceNative>()
};
check_hresult(windowInterop->AttachToWindow(hWnd));
check_hresult(windowInterop2->AttachToWindow(hWnd));
windowInterop->get_WindowHandle(&XamlIslandsWindow);
windowInterop2->get_WindowHandle(&CaptionIslandsWindow);
ClientArea.top *= -1;
SetWindowLongPtrW(CaptionIslandsWindow, GWL_EXSTYLE,
GetWindowLongPtrW(CaptionIslandsWindow, GWL_EXSTYLE) | WS_EX_TRANSPARENT);
EnableWindow(CaptionIslandsWindow, FALSE);
SetWindowPos(CaptionIslandsWindow, nullptr, 0, 1, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
SetWindowPos(XamlIslandsWindow, nullptr, 0, ClientArea.top, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
const Border captionBorder;
const AcrylicBrush captionBorderBrush;
captionBorderBrush.TintOpacity(0.65);
captionBorderBrush.TintColor({ 255, 25, 25, 25 });
captionBorderBrush.FallbackColor({ 255, 35, 35, 35 });
captionBorderBrush.BackgroundSource(AcrylicBackgroundSource::HostBackdrop);
captionBorder.Background(captionBorderBrush);
captionBorder.HorizontalAlignment(HorizontalAlignment::Left);
captionBorder.Width(75);
CaptionGrid.Children().Append(captionBorder);
CaptionXamlSource.Content(CaptionGrid);
ContentFrame.Navigate(xaml_typename<winrt::Program::SettingsPage>());
}
}
pchRT.h:
#pragma once
#include <Unknwn.h>
#include <winrt/base.h>
#include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
#include <winrt/Windows.UI.Xaml.Hosting.h>
#include <winrt/Windows.UI.Xaml.Media.h>
#include <winrt/Windows.UI.Xaml.Controls.h>
#include <winrt/Windows.UI.Xaml.Input.h>
#include <winrt/Windows.UI.h>
#include <winrt/Windows.UI.Input.h>
#include <winrt/Windows.UI.Xaml.h>
#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.UI.Xaml.Markup.h>
#include <winrt/Windows.UI.Xaml.Interop.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.UI.Xaml.Media.Imaging.h>
#include <winrt/Windows.UI.Xaml.Data.h>
My call stack consists of these function calls:
Windows.UI.Xaml.dll!00007ffa08c08106() Unknown
Windows.UI.Xaml.dll!00007ffa08c25edc() Unknown
Windows.UI.Xaml.dll!00007ffa08c27c22() Unknown
Windows.UI.Xaml.dll!00007ffa08c27da7() Unknown
Windows.UI.Xaml.dll!00007ffa08c27ead() Unknown
Windows.UI.Xaml.dll!00007ffa08c28006() Unknown
Windows.UI.Xaml.dll!00007ffa08c280e8() Unknown
Windows.UI.Xaml.dll!00007ffa08c281df() Unknown
Windows.UI.Xaml.dll!00007ffa08b7e225() Unknown
Windows.UI.Xaml.dll!00007ffa08b7e1af() Unknown
> Program.exe!winrt::impl::consume_Windows_UI_Xaml_Controls_INavigate<winrt::Windows::UI::Xaml::Controls::Frame>::Navigate(const winrt::Windows::UI::Xaml::Interop::TypeName & sourcePageType) Line 10998 C++
Program.exe!UI::UIEngine::UIEngine(HINSTANCE__ * appInstance, HWND__ * hWnd, tagRECT clientArea) Line 123 C++
Program.exe!WindowProc(HWND__ * hWnd, unsigned int msg, unsigned __int64 wParam, __int64 lParam) Line 33 C++
[External Code]
Program.exe!wWinMain(HINSTANCE__ * hInstance, HINSTANCE__ * __formal, wchar_t * __formal, int nCmdShow) Line 128 C++
[External Code]
I am compiling my code with the C++/WinRT flag -optimize, and I have included #include "UI.SettingsPage.g.cpp"

So I got this working. You need to follow these steps: Custom Control XAML Hosting API
While following the steps, ignore the directions Add a new UserControl and add a Page instead. Then, in your desktop application, navigate to the page from a Frame created within the UWP app.

Related

How to pass IWebBrowser2::Navigate2 arguments?

I want to implement Internet Explorer webview control on my window.
I found this answer, on how to do that.
There is a problem: Navigate2 method from the answer is different from the headers I have. In the posters’s code, seems it has only one argument, and maybe others are by default, but I have 5 arguments with the stupidest thing I have ever met - VARIANT type variables (also, in poster’s code it is _variant_t which is undefined for me).
Probably I will never understand the sEiFe logic, why to make instead of Navigate2(wchar_t *,...) cool stuff VARIANT * (I know about Navigate method), but can anyone provide an example of calling that method.
This full code
#include <Windows.h>
#include <Ole2.h>
#include "resource.h"
#include <iostream>
#include <atlbase.h> //activex
#include <atlwin.h> //windows
#include <atlcom.h>
#include "exdisp.h"
#include <comutil.h>
#pragma comment(lib, "comsuppw.lib")
//This will load the browser dll then library and will generate headers
//All the declarations will be in the namespace SHDocVw
//#import "shdocvw.dll"
using namespace std;
class CMyDialog : public CAxDialogImpl<CMyDialog>
{
public:
enum { IDD = IDD_DIALOG1 };
BEGIN_MSG_MAP(CMyDialog)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_HANDLER(IDCANCEL, BN_CLICKED, OnBnCancel)
COMMAND_HANDLER(IDOK, BN_CLICKED, OnBnOk)
END_MSG_MAP()
CComPtr<IWebBrowser2> ctrl;
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// Do some initialization code
HRESULT hr;
//IDC_EXPLORER_TEST is the ID of your control
GetDlgControl(IDC_EXPLORER_TEST, __uuidof(ctrl), (void**)&ctrl);
VARIANT address;
address.vt = VT_BSTR;
address.bstrVal = SysAllocString(L"google.com");
VARIANT empty;
empty.vt = VT_EMPTY;
hr = ctrl->Navigate2(&address, &empty, &empty, &empty, &empty);
SysFreeString(address.bstrVal);
/*
Also fails
_variant_t a = SysAllocString(L"google.com");
VARIANT f;
f.vt = VT_I2;
f.iVal = navBrowserBar;
_variant_t fr = SysAllocString(L"_self");
_variant_t h = SysAllocString(L" ");
hr = ctrl->Navigate2(&a, &f, &fr, &h, &h);
*/
LRESULT res = CAxDialogImpl<CMyDialog>::OnInitDialog(uMsg, wParam, lParam, bHandled);
return 0;
}
public:
LRESULT OnBnCancel(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
EndDialog(IDCANCEL);
return 0;
}
LRESULT OnBnOk(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
EndDialog(IDOK);
return 0;
}
};
CComModule _Module;
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
CMyDialog dlg;
dlg.DoModal();
return 0;
}
Returns an exception at method call because of 0x0 read violation.
It appears that you failed to check if GetDlgControl succeeded. When it fails, ctrl has an unspecified value and might be null.
Of course, that leaves the question why it would fail, but that's another issue.

"a function that returns 'auto' cannot be used before it is defined" error despite including the correct c++/winrt headers [duplicate]

This question already has an answer here:
Getting "a function that returns 'auto' cannot be used before it is defined" while using CoreDispatcher::RunAsync in C++/WinRT project
(1 answer)
Closed 3 years ago.
I am trying to convert a small win32 desktop app for consumption of c++/winrt components and XAML islands. I have followed the numerous article on the subject and have indeed been able to compile and run the application with some basic XAML controls. My problem arose when using FileOpenPicker and the subsequent error message indicating that "a function that returns 'auto' cannot be used before it is defined". I have seen others have solved this by including the relevant header files but I have already done that and I am still getting the error.
I have included the header files ; - I tried including in the pch file and in the source file itself.
#include "pch.h"
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.Storage.Pickers.h>
#include "360MediaPlayer.h"
using namespace winrt;
using namespace Windows::UI;
using namespace Windows::UI::Composition;
using namespace Windows::UI::Xaml::Hosting;
using namespace Windows::Foundation::Numerics;
using namespace Windows::Storage;
using namespace Windows::Storage::Pickers;
using namespace Windows::Media::Playback;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
#define MAX_LOADSTRING 100
// Global Variables:
HWND _hWnd;
HWND _childhWnd;
HINSTANCE _hInstance;
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
_hInstance = hInstance;
// The main window class name.
const wchar_t szWindowClass[] = L"Win32DesktopApp";
WNDCLASSEX windowClass = { };
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.lpfnWndProc = WndProc;
windowClass.hInstance = hInstance;
windowClass.lpszClassName = szWindowClass;
windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
//windowClass.hIconSm = LoadIcon(windowClass.hInstance, IDI_APPLICATION);
if (RegisterClassEx(&windowClass) == NULL)
{
MessageBox(NULL, L"Windows registration failed!", L"Error", NULL);
return 0;
}
_hWnd = CreateWindow(
szWindowClass,
L"Windows c++ Win32 Desktop App",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
if (_hWnd == NULL)
{
MessageBox(NULL, L"Call to CreateWindow failed!", L"Error", NULL);
return 0;
}
/* // Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_MY360MEDIAPLAYER, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
*/
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MY360MEDIAPLAYER));
// The call to winrt::init_apartment initializes COM; by default, in a multithreaded apartment.
winrt::init_apartment(apartment_type::single_threaded);
// Initialize the Xaml Framework's corewindow for current thread
WindowsXamlManager winxamlmanager = WindowsXamlManager::InitializeForCurrentThread();
// This DesktopWindowXamlSource is the object that enables a non-UWP desktop application
// to host UWP controls in any UI element that is associated with a window handle (HWND).
DesktopWindowXamlSource desktopSource;
// Get handle to corewindow
auto interop = desktopSource.as<IDesktopWindowXamlSourceNative>();
// Parent the DesktopWindowXamlSource object to current window
check_hresult(interop->AttachToWindow(_hWnd));
// This Hwnd will be the window handler for the Xaml Island: A child window that contains Xaml.
HWND hWndXamlIsland = nullptr;
// Get the new child window's hwnd
interop->get_WindowHandle(&hWndXamlIsland);
// Update the xaml island window size becuase initially is 0,0
SetWindowPos(hWndXamlIsland, 0, 200, 100, 800, 200, SWP_SHOWWINDOW);
//Creating the Xaml content
Windows::UI::Xaml::Controls::StackPanel xamlContainer;
xamlContainer.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
Windows::UI::Xaml::Controls::TextBlock tb;
tb.Text(L"Hello World from Xaml Islands!");
tb.VerticalAlignment(Windows::UI::Xaml::VerticalAlignment::Center);
tb.HorizontalAlignment(Windows::UI::Xaml::HorizontalAlignment::Center);
tb.FontSize(48);
MediaPlayer mpSphere = MediaPlayer();
FileOpenPicker foPicker = FileOpenPicker();
StorageFile file(foPicker.PickSingleFileAsync().get());
mpSphere.SetFileSource(file);
mpSphere.Play();
// xamlContainer.Children().Append(tb);
xamlContainer.UpdateLayout();
desktopSource.Content(xamlContainer);
//End XAML Island section
ShowWindow(_hWnd, nCmdShow);
UpdateWindow(_hWnd);
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
So the full error messsage I'm getting is the following:
Error C3779 'winrt::impl::consume_Windows_Foundation_IAsyncOperation<winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile>,TResult>::get': a function that returns 'auto' cannot be used before it is defined'
despite the presence of the header files as can be seen above. If I remove the code dealing with the Media file and leave only the XAML stuff, it runs. Anyone know what I'm missing? I can provide the full project if needed.
auto Keyword simple ask the compiler at compilation time to deduce the type with whatever you are type to use it as, maybe a return from a function, or a hard coded POD type like an int.
the issue with your code is your missing your include for winrt foundation, which is required for your code since its accessing Async functions, honestly most WinRT code requires the include for foundation
#include <winrt/Windows.Foundation.h>
using namespace winrt;
using namespace Windows::Foundation;
since you forgot to include the foundation include, the compiler had no way to deduce the type for which the error was thrown.....
please note that auto keyword is great for functions in the form of trailing return types, but i highly suggest you don't use them for variables for a number of reasons, a few notable ones being odd bugs with vector iterators, where even when included properly, inside a template function the auto keyword wont be able to deduce the type and will cause an error,
template <typename T>
auto findSomething(:std::string name)
-> T*
{
// the code here causes an error since we are trying to deduce the var inside a
// template function using auto
auto _Found = ::std::find_if(somevector.begin(), somevector.end(), [&](::std::pair<::std::string, ::std::unique_ptr<class Someclass>>& pair){ return (pair.first = name) ? true : false; });
if(_Found != somevector.end())
{
return static_cast<T*>(_Found->second.get());
}
return nullptr;
}
Corrected
template <typename T>
auto findSomething(:std::string name)
-> T*
{
::std::vector<::std::pair<::std::string, ::std::unique_ptr<class Someclass>>>::iterator _Found = ::std::find_if(somevector.begin(), somevector.end(), [&](::std::pair<::std::string, ::std::unique_ptr<class Someclass>>& pair){ return (pair.first = name) ? true : false; });
if(_Found != somevector.end())
{
return static_cast<T*>(_Found->second.get());
}
return nullptr;
}
if your dont want to type ::std::vector<::std::pair<::std::string, ::std::unique_ptr<class someclass>>>::iterator every time simply type alias your type wit the using keyword using myvectortype = ::std::vector<::std::pair<::std::string, ::std::unique_ptr<class someclass>>> that way you only need to type myvectortype::iterator....
hope this helped you fix your code.

DX11 DirectInput8Create causing LNK2019 error

I'm trying to create a GPU rendered particle system, and it uses this input class to handle mouse/keyboard input.
The issue is the line;
HRESULT result = DirectInput8Create(.....);
causes a LNK2019: Unresolved External Symbol error. I've included the necessary files, so I'm not sure why this is happening. Below is the Input.h and Input.cpp files respectively.
INPUT.H file
#ifndef _INPUT_
#define _INPUT_
#include <stdafx.h>
#include <dinput.h>
class Input{
private:
IDirectInputDevice8* _DIKeyboard;
IDirectInputDevice8* _DIMouse;
LPDIRECTINPUT8 _directInput;
LONG _mouseXabsolute, _mouseYabsolute, _mouseZabsolute;
LONG _mouseXrelative, _mouseYrelative, _mouseZrelative;
BYTE _keyboardState[256];
BYTE _leftMouseButton, _rightMouseButton;
int _screenWidth, _screenHeight;
HWND _hWnd;
POINT _point;
RECT _rect;
public:
Input();
~Input();
void unload();
bool initializeInput(HINSTANCE hInstance, HWND hWnd, int screenWidth, int screenHeight);
void updateInput();
BYTE* getKeyboardState();
LONG getMouseXRelative();
LONG getMouseYRelative();
LONG getMouseZRelative();
LONG getMouseXAbsolute();
LONG getMouseYAbsolute();
LONG getMouseZAbsolute();
BYTE getLeftMouseClick();
BYTE getRightMouseClick();
};
#endif
INPUT.CPP File
#include <stdafx.h>
#include <Input.h>
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
using namespace std;
Input::Input() : _DIKeyboard(), _DIMouse(), _directInput(), _point(), _rect(){
_mouseXabsolute = _mouseYabsolute = 0;
_mouseZabsolute = 1;
_mouseXrelative = _mouseXrelative = _mouseXrelative = 0;
}
Input::~Input(){
unload();
}
void Input::unload(){
if (_DIKeyboard) _DIKeyboard->Release();
if (_DIMouse) _DIMouse->Release();
if (_directInput) _directInput->Release();
}
bool Input::initializeInput(HINSTANCE hInstance, HWND hWnd, int screenWidth, int screenHeight){
_screenWidth = screenWidth;
_screenHeight = screenHeight;
_hWnd = hWnd;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////Create direct input, keyboard and mouse devices///////////////////////////////////////////////////
HRESULT result = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&_directInput, NULL);
if (FAILED(result)){
MessageBox(0, L"Could not create direct input!", L"Error", MB_OK);
return false;
}
...
...
...
}
I'd appreciate any help to solve this issue.
You should link to dinput8.lib static library:
#pragma comment(lib, "dinput8")
Besides, you should consider using Raw input APIs instead of DirectInput: https://msdn.microsoft.com/en-us/library/windows/desktop/ms645536(v=vs.85).aspx

Print text and images in C++ (WinAPI or QT)

In a basic program, I need to know how to make a text display widget and image display that can both be changed to different strings and images on command. These will display on a basic GUI.
Any specific help would be tremendously appreciated as I have been stuck on this for more than 10 weeks! Asking online here is my last resort.
I am making a basic program that asks questions (which is my text I want to print) and images for the questions come up underneath it. I have successfully made this program in a console command window (the code I will share below) but this of course meant no images could be displayed, so I am having to remake it in a GUI that supports images.
This is my first project ever done in C++, and only know the basics (the full extent of my limited knowledge got me through making that console command window program without help).
I first used WinAPI as it came with my computer in microsoft visual studio, and tried many different suggestions by other's similar questions already answered, but always either had one of two problems; 1. The code they supplied had many errors of which most read "_ is undefined" or wasn't imported properly, or 2. created basic text successfully but didn't specify how to change it after it had been created (I have had no successful image prints so far). I have tried 3 question/answers from cplusplus.com and 3 from stack overflow (links will be below), and all of them have had these 2 problems that are created from my lack of C++ bug fixing skills.
Suggestions using WinAPI would be prefferred over QT as I have no idea what I am doing in Qt and get double digit numbers worth of errors when I import code (even though I import the correct directories), whereas WinAPI doesn't get importing errors.
Code for command console program:
//G-Learning
//#author: James Monk
//#completed: 7/6/16
//#version 1.0
//These are the libraries (external files) to include at the start.
#include <cstdio>
#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;
//Defining the [global] variables that will be used throughout the program
int running = 1;
int menuSelection;
int questionsLeft = 5;
int questionTextPicked;
int questionImagePicked;
int questionRandomised;
int score = 0;
int userInput;
int userInputDummy;
string stringPointer;
int intPointer;
string questionText[10] = {
"Would this most likely be, (1) an enemy (2) a player?\n",
"Is this (1) how many hearts the player has inside their body, or (2) a number of lives the player has?\n",
"Is this (1) a health bar, or (2) a set of red lights?\n",
"Is this (1) a money counter, or (2) a yellow ball counter?\n",
"Would this be a good object to touch with your character? (1) no or (2) yes?\n",
"What would this object likely have in it? (1) rewards, or (2) punishments\n",
"What does 'Game Over' mean? (1) your session has ended, or (2) the game is no longer playable\n",
"What would an icon like this likely be for? (1) show wheels, or (2) options\n",
"In a racing game, what would this be for? (1) health bar, or (2) fuel tank meter\n",
"What would this button likely do? (1) exit or cancel, or (2) mark a spot with an x\n" };
//Defining what happens with the different functions
void introduction() {
printf("\nG-Learning is a program built to teach people who know little about games the basic features of them. \n\n\
Questions will be asked, and you will need to answer them by choosing the correct answer.\n\
You will need to press 1, 2, or 3 followed by enter to choose.\n\n\
Press any number key followed by enter to return to the main menu.\n\n");
cin >> userInputDummy;
menuSelection = 0;
}
void start() {
printf("\nThe questions will now start, good luck!\n\n");
while (questionsLeft > 0) {
questionTextPicked = (rand() % 10);
if (questionTextPicked == 0) {
questionRandomised = (rand() % 4);
questionImagePicked = (7 + questionRandomised);
}
else if (questionTextPicked == 4) {
questionRandomised = (rand() % 3);
questionImagePicked = (11 + questionRandomised);
}
else {
questionImagePicked = questionTextPicked;
}
printf("after calculations, questionTextPicked is %d, questionRandomised is %d, and questionImagePicked is %d\n\n", questionTextPicked, questionRandomised, questionImagePicked);
//answering questions should be here
stringPointer = questionText[questionTextPicked];
intPointer = questionAnswer[questionImagePicked];
printf("answer is %d\n\n", intPointer);
printf("%s\n", stringPointer, intPointer);
printf("answer is %d\n\n", intPointer);
cin >> userInput;
if (userInput == questionAnswer[questionImagePicked]) {
printf("\nCorrect!\n\n");
score++;
}
else {
printf("\nIncorrect answer.\n\n");
}
questionsLeft--;
if (questionsLeft > 0) {
printf("%d questions to go!\n\n", questionsLeft);
}
if (questionsLeft == 0) {
printf("All questions have been answered, you scored %d/5.\n\nReturning you to the main menu\n\n", score);
score = 0;
}
} //end of start's while loop
menuSelection = 0;
} //end of start's function
void exit() {
menuSelection = 0;
running = 0;
}
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//Main function, where everything starts
int main(int argc, char ** argv) {
while (running == 1) {
//Welcoming the user to the program, and asking them what they want to do (starts functions)
printf("welcome to G-Learning! Press a key to get started.\n1: Instructions\n2: Start\n3: Exit\n\n");
questionsLeft = 5; //Resetting this so that the start function can begin again
cin >> menuSelection;
if (menuSelection == 1) {
introduction();
}
else if (menuSelection == 2) {
start();
}
else if (menuSelection == 3) {
exit();
}
else {
printf("Invalid input, please use the 1, 2, or 3 key.");
}
}
return 0;
return EXIT_SUCCESS;
} //end of main function
Code for my best working WinAPI iteration (can print text, but not again on command; also without image functionality. Would like to know how to improve this one!):
//These are the libraries (external files) to include at the start.
#include <cstdio>
#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;
int textHorizontal = 10;
int textVertical = 10;
//Variables used in making the program window
int numberInput;
char charictorInput;
string stringInput;
const char g_szClassName[] = "myWindowClass";
HINSTANCE hInstance;
// Function to get the size of the text
int GetTextSize(LPSTR a0)
{
for (int iLoopCounter = 0; ; iLoopCounter++)
{
if (a0[iLoopCounter] == '\0')
return iLoopCounter;
}
}
LPSTR TextArray[] = {
"Hello World"
};
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
TextOut(hdc,
// Location of the text
textHorizontal,
textVertical,
// Text to print
TextArray[0],
// Size of the text, my function gets this for us
GetTextSize(TextArray[0]));
EndPaint(hwnd, &ps);
}
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int WINAPI WinMain(HINSTANCE hInstanace, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX WindowClass;
WindowClass.cbClsExtra = 0;
WindowClass.cbWndExtra = 0;
WindowClass.cbSize = sizeof(WNDCLASSEX);
WindowClass.lpszClassName = "1";
WindowClass.lpszMenuName = NULL;
WindowClass.lpfnWndProc = WndProc;
WindowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WindowClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WindowClass.style = 0;
WindowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
RegisterClassEx(&WindowClass);
HWND hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
"1",
"G-Learning by James Monk",
WS_OVERLAPPEDWINDOW,
315, 115,
1080, 720,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd, SW_SHOWNORMAL);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (VK_ESCAPE == msg.wParam)
break;
}
return 0;
}
I am limited to only 2 links, so to view the 3 cplusplus.com pages I tried and the 3 stack overflow pages I tried, the links to them are on a google document here:
https://docs.google.com/document/d/1IX2hxzAVka3UmVkaAgv-gXv_cwwmP3FkTYQuFWrrqyE/edit?usp=sharing
How I installed QT into Microsoft Visual Studio:
https://www.youtube.com/watch?v=P6Mg8FpFPS8
Thank you for reading through my issue and even more in advance for helping!
HINSTANCE hInstance;
int WINAPI WinMain(HINSTANCE hInstanace...
CreateWindowEx(... hInstance ...)
You have spelling errors here. hInstanace and hInstance are not the same. Visual Studio should give you warnings. Set the warning level to 4. Address all the warnings and fix them. Only in rare cases is it okay to ignore warnings.
Moreover, in declaration of WNDCLASSEX WindowClass; you missed initializing hInstance, so the code will go nowhere. In C++ 14 you can do this
WNDCLASSEX WindowClass = {0}
This will initialize all members to zero. Try to always do this when declaring data on stack. Also avoid putting random code in to message loop.
#include <cstdio>
#include <iostream>
#include <windows.h>
Above header files are for C input/output, C++ input/output, and WinAPI. Usually you don't need them all. Pick one.
LPSTR TextArray[] = {
"Hello World"
};
Above is a character array, or just "text". If you access TextArray[0] it gives you the character 'H'
int GetTextSize(LPSTR a0)
{
for (int iLoopCounter = 0; ; iLoopCounter++)
{
if (a0[iLoopCounter] == '\0')
return iLoopCounter;
}
}
Above code is the equivalent of strlen. Your code is all over the place. You have C++14 classes like std::string, C header files, useless functions like GetTextSize which is mostly for learning C/C++, more advanced WinAPI, and some mention of Qt cross development. I recommend you spend more time with a C++ book. Here is example of what you are trying to do:
#include <windows.h>
#include <string>
#include <vector>
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND combobox;
static std::vector<std::string> vec = {
"Would this most likely be, (1) an enemy (2) a player?\n",
"Is this (1) how many hearts the player has inside their body, or (2) a number of lives the player has?\n",
"Is this (1) a health bar, or (2) a set of red lights?\n",
"Is this (1) a money counter, or (2) a yellow ball counter?\n",
"Would this be a good object to touch with your character? (1) no or (2) yes?\n",
"What would this object likely have in it? (1) rewards, or (2) punishments\n",
"What does 'Game Over' mean? (1) your session has ended, or (2) the game is no longer playable\n",
"What would an icon like this likely be for? (1) show wheels, or (2) options\n",
"In a racing game, what would this be for? (1) health bar, or (2) fuel tank meter\n",
"What would this button likely do? (1) exit or cancel, or (2) mark a spot with an x\n"
};
switch (msg)
{
case WM_CREATE:
combobox = CreateWindow("ComboBox", 0, CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE, 0, 100, 700, 30, hwnd, HMENU(100), 0, 0);
for (auto line : vec) SendMessage(combobox, CB_ADDSTRING, 0, LPARAM(line.c_str()));
break;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
DestroyWindow(hwnd);
break;
case WM_COMMAND:
if (HIWORD(wParam) == CBN_SELCHANGE)
InvalidateRect(hwnd, NULL, TRUE);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
int sel = SendMessage(combobox, CB_GETCURSEL, 0, 0);
if (sel < 0) sel = 0;
TextOut(hdc, 0, 0, vec[sel].c_str(), vec[sel].size());
EndPaint(hwnd, &ps);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcx = { 0 };
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpszClassName = "ClassName";
wcx.lpfnWndProc = WndProc;
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
RegisterClassEx(&wcx);
HWND hwnd = CreateWindowEx(0, wcx.lpszClassName, "G-Learning by James Monk", WS_VISIBLE|WS_OVERLAPPEDWINDOW, 0,0,800,600, NULL, NULL, hInstance, NULL);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}

WinAPI window doesn't appear

And I can't figure out why. My code:
#include <windows.h>
#include <commctrl.h>
#include <cstdio>
#include <stdarg.h>
#include <string>
#include <cmath>
#include <vector>
#include "resources.hpp"
using std::string;
using std::vector;
struct undostruct{
/* add later */};
char buffer[2048];
HWND statusbar;
HINSTANCE hinst;
vector<undostruct> undo;
void show_error(const char* format,...){
va_list args;
va_start(args,format);
vsprintf(buffer,format,args);
va_end(args);
MessageBox(NULL,buffer,"ERROR",MB_OK);}
HWND create_tooltip(HWND parent,char* tip,unsigned uid,unsigned extraflags=0){
HWND tt=CreateWindowEx(WS_EX_TOPMOST,TOOLTIPS_CLASS,NULL,WS_POPUP|TTS_NOPREFIX|TTS_ALWAYSTIP,0,0,0,0,parent,NULL,NULL,NULL);
SetWindowPos(tt,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
TOOLINFO ti;
ti.cbSize=sizeof(TOOLINFO);
ti.uFlags=TTF_SUBCLASS|extraflags;
ti.hwnd=parent;
ti.hinst=NULL;
ti.uId=uid;
ti.lpszText=tip;
GetClientRect(parent,&ti.rect);
SendMessage(tt,TTM_ADDTOOL,0,(LPARAM)(LPTOOLINFO)&ti);
return tt;}
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
class Font{
private:
HFONT hfont;
public:
Font(const char* fname){
hfont=CreateFont(0,0,0,0,FW_NORMAL,false,false,false,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,fname);}
~Font(){
DeleteObject(hfont);}
operator HFONT(){
return hfont;}}courier("Courier New");
bool get_filename(char* fname,int len,HWND hwnd,bool save){
OPENFILENAME ofn;
ZeroMemory(&ofn,sizeof(OPENFILENAME));
ofn.lStructSize=sizeof(OPENFILENAME);
ofn.hwndOwner=hwnd;
ofn.lpstrFilter="Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0\0";
ofn.lpstrFile=fname;
ofn.nMaxFile=len;
ofn.lpstrTitle="Text Editor";
ofn.Flags=OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
if(save){
return GetSaveFileName(&ofn);}
else{
return GetOpenFileName(&ofn);}}
int WINAPI WinMain(HINSTANCE hprev,HINSTANCE hInst,LPSTR cmdline,int cmdshow){
WNDCLASSEX wcex;
//HACCEL haccel=LoadAccelerators(hInst,MAKEINTRESOURCE(ACCELS));
HWND hwnd;
MSG msg;
hinst=hInst;
//Register the window
wcex.cbSize=sizeof(WNDCLASSEX);
wcex.style=CS_HREDRAW|CS_VREDRAW;
wcex.lpfnWndProc=WndProc;
wcex.cbClsExtra=0;
wcex.cbWndExtra=0;
wcex.hInstance=hinst;
wcex.hIcon=NULL;
wcex.hCursor=NULL;
wcex.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName=MAKEINTRESOURCE(MAINMENU);
wcex.lpszClassName="ImageEditor";
wcex.hIconSm=NULL;
if(!RegisterClassEx(&wcex)){
show_error("Error %i: Failed to register the window.",GetLastError());
return -1;}
//Create the window
hwnd=CreateWindow("ImageEditor","Image Editor",WS_VISIBLE|WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hinst,NULL);
if(!hwnd){
show_error("Error %i: Failed to create the window.",GetLastError());
return -2;}
//Show/Update the window
ShowWindow(hwnd,cmdshow);
UpdateWindow(hwnd);
//Initialize common controls
/*INITCOMMONCONTROLSEX iccex;
iccex.dwICC=ICC_WIN95_CLASSES;
iccex.dwSize=sizeof(INITCOMMONCONTROLSEX);
InitCommonControlsEx(&iccex);*/
//Go into the main program loop
while(GetMessage(&msg,NULL,0,0)){
//if(!TranslateAccelerator(hwnd,haccel,&msg)){
TranslateMessage(&msg);
DispatchMessage(&msg);}//}
return msg.wParam;}
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam){
static int sizes[]={260,330,420,520};
switch(msg){
case WM_CREATE:
statusbar=CreateWindow(STATUSCLASSNAME,"",WS_CHILD|WS_BORDER|WS_VISIBLE,-100,-100,10,10,hwnd,NULL,hinst,NULL);
if(!statusbar){
show_error("Error %i: Failed to create the statusbar.",GetLastError());}
//Description|Characters|Size|Lines|Line|Column
SendMessage(statusbar,SB_SETPARTS,sizeof(sizes),(LPARAM)sizes);
break;
case WM_QUIT:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
//switch(LOWORD(wparam)){}
//break;
default:
return DefWindowProc(hwnd,msg,wparam,lparam);}
return 0;}
Also, my compiler doesn't recognize INITCOMMONCONTROLSEX when it should, which is commented out near the end of WinMain.
The most likely bug in this code is that you need to run InitCommonControls BEFORE creating a window. And forget that InitCommonControlsEx() code, you'll be better with a plain old InitCommonControls.
Remember to check every function's return value and use GetLastError().
Also, you're trying to reinvent the wheel and instead of rolling out your own window creating procedure I suggest you to take a look at how others do it, or even use WTL, it's not that difficult.