Łączenie programu konsolowego z GUI

0

Cześć,
mam problem z połączeniem programu, który napisałem w trybie konsolowym z GUI zrobionym w Windows Forms. Aplikacja korzysta z biblioteki Directinput i umożliwia wyświetlenie nazwy joysticka oraz używania go jako myszki. Problem pojawia się, gdy próbuję dorobić do niej GUI w Windows Forms. Wiem, że w VS 13 nie ma już możliwości wybrania z menu aplikacji w Windows Forms, ale tworzyłem już takie aplikacje za pomocą tego poradnika:

i wszystko działało bez problemu. Oto kod działającego programu (wcześniej nie było klasy Joy i zamiast funkcji start() była funkcja main()):

#ifndef D_INPUT
#define D_INPUT
#include <dinput.h>
#include <iostream>
#endif

LPDIRECTINPUT8 di;			   // wskaznik interfejsu IDirectInput8
HRESULT hr;
LPDIRECTINPUTDEVICE8 joystick;
DIDEVICEINSTANCE pdidi;
DIDEVICEINSTANCE info;

BOOL CALLBACK
enumCallback(const DIDEVICEINSTANCE* instance, VOID* context)
{
	HRESULT hr;

	hr = di->CreateDevice(instance->guidInstance, &joystick, NULL);

	if (FAILED(hr)) {
		return DIENUM_CONTINUE;
	}
	return DIENUM_STOP;
}

BOOL CALLBACK
enumAxesCallback(const DIDEVICEOBJECTINSTANCE* instance, VOID* context)
{
	HWND hDlg = (HWND)context;

	DIPROPRANGE propRange;
	propRange.diph.dwSize = sizeof(DIPROPRANGE);
	propRange.diph.dwHeaderSize = sizeof(DIPROPHEADER);
	propRange.diph.dwHow = DIPH_BYID;
	propRange.diph.dwObj = instance->dwType;
	propRange.lMin = -50;
	propRange.lMax = +50;

	if (FAILED(joystick->SetProperty(DIPROP_RANGE, &propRange.diph))) {
		return DIENUM_STOP;
	}

	return DIENUM_CONTINUE;
}

class Joy
{
public:
	
	HRESULT
	poll(DIJOYSTATE *js)
	{
		HRESULT	hr;

		if (joystick == NULL)
		{
			return S_OK;
		}

		// Poll the device to read the current state
		hr = joystick->Poll();
		if (FAILED(hr)) {
			// DInput is telling us that the input stream has been
			// interrupted. We aren't tracking any state between polls, so
			// we don't have any special reset that needs to be done. We
			// just re-acquire and try again.
			hr = joystick->Acquire();
			while (hr == DIERR_INPUTLOST) {
				hr = joystick->Acquire();
			}

			// If we encounter a fatal error, return failure.
			if ((hr == DIERR_INVALIDPARAM) || (hr == DIERR_NOTINITIALIZED)) {
				return E_FAIL;
			}

			// If another application has control of this device, return successfully.
			// We'll just have to wait our turn to use the joystick.
			if (hr == DIERR_OTHERAPPHASPRIO) {
				return S_OK;
			}
		}
		// Get the input's device state
		if (FAILED(hr = joystick->GetDeviceState(sizeof(DIJOYSTATE), js))) {
			return hr; // The device should have been acquired during the Poll()
		}

		return S_OK;
	}
	void GetDesktopResolution(int& horizontal, int& vertical)
	{
		RECT desktop;

		// Get a handle to the desktop window
		const HWND hDesktop = GetDesktopWindow();

		// Get the size of screen to the variable desktop
		GetWindowRect(hDesktop, &desktop);

		horizontal = desktop.right;
		vertical = desktop.bottom;
	}

	void moveMouse(int dx, int dy)
	{
		POINT pt;
		int horizontal = 0;
		int vertical = 0;

		GetDesktopResolution(horizontal, vertical);

		GetCursorPos(&pt);

		pt.x += dx;
		pt.y += dy;

		if (pt.x < 0)
		{
			pt.x = 0;
		}
		if (pt.x > horizontal)
		{
			pt.x = horizontal;
		}

		if (pt.y < 0)
		{
			pt.y = 0;
		}
		if (pt.y > vertical)
		{
			pt.y = vertical;
		}

		SetCursorPos(pt.x, pt.y);
	}

	void clickMouse()
	{
		if (GetKeyState(VK_LBUTTON) >= 0)
		{
			mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
		}
	}
	void unclickMouse()
	{
		mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
	}

	void close()
	{
		if (joystick)
		{
			joystick->Unacquire();
		}
	}

	int start()
	{
		DIJOYSTATE js;										// struktura stanu joysticka

		// Create a DirectInput device
		if (FAILED(hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION,
			IID_IDirectInput8, (VOID**)&di, NULL))) {
			return hr;
		}

		if (FAILED(hr = di->EnumDevices(DI8DEVCLASS_GAMECTRL, enumCallback,
			NULL, DIEDFL_ATTACHEDONLY))) {
			return hr;
		}

		// sprawdzenie czy jest joystick
		if (joystick == NULL) {

			std::cout << "Joystick not found.\n";
			system("pause");
			return E_FAIL;
		}

		// ustawienia
		DIDEVCAPS capabilities;

		// zdefiniowanie formatu danych urzadzenia
		if (FAILED(hr = joystick->SetDataFormat(&c_dfDIJoystick)))
		{
			return hr;
		}

		// Powiazanie urzadzenia z oknem aplikacji
		if (FAILED(hr = joystick->SetCooperativeLevel(GetConsoleWindow(), DISCL_NONEXCLUSIVE | DISCL_FOREGROUND))) {
			return hr;
		}

		// wczytanie ustawien joysticka
		capabilities.dwSize = sizeof(DIDEVCAPS);
		if (FAILED(hr = joystick->GetCapabilities(&capabilities))) {

			return hr;
		}

		// wyliczanie
		if (FAILED(hr = joystick->EnumObjects(enumAxesCallback, NULL, DIDFT_AXIS))) {
			return hr;
		}

		info.dwSize = sizeof(DIDEVICEINSTANCE);
		if (FAILED(hr = joystick->GetDeviceInfo(&info)))
		{
			return hr;
		}
		int i = 0;
		while (i < MAX_PATH && info.tszProductName[i] != 0)
		{
			std::cout << (char)info.tszProductName[i];
			i++;
		}
		std::cout << std::endl;
		system("pause");

		while (1)
		{
			poll(&js);

			if (js.rgbButtons[0] != 0)
				clickMouse();
			else
				unclickMouse();
			//clickMouse(js.rgbButtons[0]);

			for (int i = 0; i < 11; i++)
			{
				if (js.rgbButtons[i] != 0) std::cout << "Przycisk " << i + 1 << std::endl;
			}


			std::cout << "X: " << js.lX << std::endl;
			std::cout << "Y: " << js.lY << std::endl;
			std::cout << "Z: " << js.lZ << std::endl;

			moveMouse(js.lX, js.lY);

			//Sleep(400);
			std::cout << std::endl;
			system("cls");
		}

		close();

		system("pause");
	}
};

Wywołanie w konstruktorze klasy MyForm:

#pragma once
#include "Joy.cpp"

(...)
	public ref class MyForm : public System::Windows::Forms::Form
	{
	public:
		MyForm(void)
		{
			InitializeComponent(); 
			Joy joy;
			joy.start();
		}

Błędy jakie otrzymuję:
http://pastebin.com/u9F0Paqr

Chodzi mi o samo uruchomienie, wiem, że wyświetlanie czegoś w konsoli w aplikacji okienkowej nie ma sensu. Gdy próbowałem uruchomić program z funkcjami enumCallback i enumAxesCallback wewnątrz klasy Joy, ale generowało to inne błędy.

Bardzo proszę o pomoc.
Z gór dziękuję za każdą odpowiedź.

0

Wiem, że w VS 13 nie ma już możliwości wybrania z menu aplikacji w Windows Forms, ale tworzyłem już takie aplikacje za pomocą tego poradnika:

Nie podoba mi się ten poradnik, bo robi to inaczej niż poprzednie wersje Visuala gdy wybierało się projekt Windows Forms.

Żeby otrzymać projekt identyczny z tym generowanym pod VS2010 i starszymi, trzeba zacząć od CLR Console Program a nie od Empty Project - a kod funkcji main wkleić do osobno tworzonego pliku z domyślną funkcją main a nie do formy.

Wtedy dostajesz prawidłowo skonfigurowany precompiled header.

#pragma once
#include "Joy.cpp"

Musisz ten kod podzielić na plik .h i plik .cpp, i inkludować tylko h.

0

Na początku pliku cpp dodaj

#include "stdafx.h"
0

Zmienne globalne (już pomijając że powinno ich nie być) powinny być w pliku .cpp
Jeśli muszą być widoczne przez inne pliki .cpp (czyli muszą być w pliku .h) to trzeba je powtórzyć w .h ale ze słowem extern:

// .cpp
LPDIRECTINPUT8 di;

// .h
extern LPDIRECTINPUT8 di; // opcjonalnie

1 użytkowników online, w tym zalogowanych: 0, gości: 1