Re: [osg-users] Visual C++ CLR Windows Forms app using OpenSceneGraph

153 views
Skip to first unread message

Bluish Joe

unread,
Jul 4, 2014, 9:52:19 AM7/4/14
to osg-...@lists.openscenegraph.org
I have the same issue (SEHException) and cannot find a way to embed OpenSceneGraph inside a Windows form.
Anyone can help, please?

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=60153#60153





_______________________________________________
osg-users mailing list
osg-...@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Trajce Nikolov NICK

unread,
Jul 4, 2014, 1:05:35 PM7/4/14
to OpenSceneGraph Users
Hi Joe,

is this for .NET Form? (C#,managed C++???)

if so, have a look at the osgMFCViewer how it is done, you can achieve it same way. The basic is to get the windows handle of your form (the HWND) and to pass it on in the traits as inheriteddata . If you provide a code sample I might help you by looking at or do some changes here or there

Nick
--
trajce nikolov nick

Bluish Joe

unread,
Jul 7, 2014, 4:41:41 AM7/7/14
to osg-...@lists.openscenegraph.org
Hi Trajce, very kind!
It's managed C++ (even if I would finally use OSG in a C++Builder application, but I fear I will need to build OSG in Visual Studio and make a a wrapper.......).

I tried many examples. I haven't tried osgviewerMFC because I haven't got the Visual Studio project files (CMake didn't create them for this project) and I'm new to MFC.
Anyway I usually get these errors:

1) Eccezione non gestita di tipo 'System.Runtime.InteropServices.SEHException' in TestOsgVS.exe. Informazioni aggiuntive: eccezione lanciata da un componente esterno.
when executing
Code:
osg::ref_ptr<osg::Node> model1 = osgDB::readNodeFile("C:\\Path\\to\\OpenSceneGraph-3.0.1-VS10.0.30319-x86-release-12741\\data\\cessna.osg");



2) Eccezione non gestita di tipo 'System.AccessViolationException' in TestOsgVS.exe
when executing
Code:
traits->inheritedWindowData = windata;



One of my test is this:


Code:
#pragma once

#include <osgDB/ReadFile>
//#include <osgUtil/Optimizer>
#include <osgViewer/Viewer>
//#include <osgViewer/api/Win32/GraphicsWindowWin32>
//#include <osgViewer/CompositeViewer>
#include <osgGA/TrackballManipulator>
#include <osgViewer/ViewerEventHandlers>

#include <iostream>
#include <Windows.h>
#include <string>

namespace TestOsgVS {

using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace std;

/// <summary>
/// Riepilogo per Form1
/// </summary>
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
//
//TODO: aggiungere qui il codice del costruttore.
//
}

protected:
/// <summary>
/// Liberare le risorse in uso.
/// </summary>
~Form1()
{
if (components)
{
delete components;
}
}
private: System::Windows::Forms::Panel^ pOSG;
private: System::Windows::Forms::Button^ button1;
protected:

private:
/// <summary>
/// Variabile di progettazione necessaria.
/// </summary>
System::ComponentModel::Container ^components;

osgViewer::Viewer* viewer;
osg::Camera* camera;

#pragma region Windows Form Designer generated code
/// <summary>
/// Metodo necessario per il supporto della finestra di progettazione. Non modificare
/// il contenuto del metodo con l'editor di codice.
/// </summary>
void InitializeComponent(void)
{
this->pOSG = (gcnew System::Windows::Forms::Panel());
this->button1 = (gcnew System::Windows::Forms::Button());
this->SuspendLayout();
//
// pOSG
//
this->pOSG->BackColor = System::Drawing::Color::FromArgb(static_cast<System::Int32>(static_cast<System::Byte>(255)), static_cast<System::Int32>(static_cast<System::Byte>(128)),
static_cast<System::Int32>(static_cast<System::Byte>(128)));
this->pOSG->Location = System::Drawing::Point(43, 29);
this->pOSG->Name = L"pOSG";
this->pOSG->Size = System::Drawing::Size(379, 265);
this->pOSG->TabIndex = 0;
//
// button1
//
this->button1->Location = System::Drawing::Point(482, 29);
this->button1->Name = L"button1";
this->button1->Size = System::Drawing::Size(177, 94);
this->button1->TabIndex = 1;
this->button1->Text = L"button1";
this->button1->UseVisualStyleBackColor = true;
this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
//
// Form1
//
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(716, 503);
this->Controls->Add(this->button1);
this->Controls->Add(this->pOSG);
this->Name = L"Form1";
this->Text = L"Form1";
this->ResumeLayout(false);

}
#pragma endregion


private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {

// load model from file
osg::ref_ptr<osg::Node> loadedModel =
osgDB::readNodeFile("C:\\Path\\to\\OpenSceneGraph-3.0.1-VS10.0.30319-x86-release-12741\\data\\cow.osgt");

//from osgviewerSDL example
osgViewer::Viewer viewer;
osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> gw = viewer.setUpViewerAsEmbeddedInWindow(50,50,200,200);
viewer.setSceneData(loadedModel.get());
viewer.setCameraManipulator(new osgGA::TrackballManipulator);
viewer.addEventHandler(new osgViewer::StatsHandler);
viewer.realize();

// draw the new frame
viewer.frame();
}
};
}



Many thanks for your help.[/list][/list]

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=60189#60189

Trajce Nikolov NICK

unread,
Jul 7, 2014, 6:59:43 AM7/7/14
to OpenSceneGraph Users
Hi Joe,

the first exception I believe is something to do with mixing unmanaged with managed code (shouldn't be the qualifier 'unsafe' used??? - sorry, but don't know the tricks of mixing unmanaged with managed code)

But, have a look here http://forum.openscenegraph.org/viewtopic.php?t=13944 , it was for C# sample.The unmanaged code is wrapped into dll of exposing a function (unmanaged) that is initializing and running the viewer from unmanaged dll.

The second exception is I believe you are not setting the inheriteddata. If you still want to try with mixing managed and unmanaged, You don't need to set up the viewer as embedded. Only pass the handle of the form's client area - something like 

traits->inheritedWindowData = new osgViewer::GraphicsWindowWin32::WindowData(this->Handle->ToInt32()) in your form init

Nick
--
trajce nikolov nick

Bluish Joe

unread,
Jul 7, 2014, 9:43:55 AM7/7/14
to osg-...@lists.openscenegraph.org
Thanks Trajce, now I'm understanding something more.
I tried using your code. I finally wrote a Win32 application (without CLR). This is the code:


Code:
#include "stdafx.h"
#include "TestOsgVSWin32.h"

#include <windows.h>

#include <osgViewer/Viewer>
#include <osgViewer/api/Win32/GraphicsWindowWin32>
#include <osg/GraphicsContext>

const LPCWSTR g_szClassName = L"myWindowClass";

// Step 4: the Window Procedure
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;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;

//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&wc))
{
MessageBox(NULL, L"Window Registration Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}

// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
L"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 600, 300,
NULL, NULL, hInstance, NULL);

if(hwnd == NULL)
{
MessageBox(NULL, L"Window Creation Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}

ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
EmbedOSG(hwnd);

// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}


void EmbedOSG(HWND handle)
{
// Local Variable to hold window size data
RECT rect;


// Create the viewer for this window
osgViewer::Viewer* v = new osgViewer::Viewer();


// Get the current window size
::GetWindowRect(handle, &rect);


// Init the GraphicsContext Traits
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;


// Init the Windata Variable that holds the handle for the Window to display OSG in.
osg::ref_ptr<osg::Referenced> windata = new osgViewer::GraphicsWindowWin32::WindowData(handle);


// Setup the traits parameters
traits->x = 0;
traits->y = 0;
traits->width = rect.right - rect.left;
traits->height = rect.bottom - rect.top;
traits->windowDecoration = false;
traits->doubleBuffer = true;
traits->sharedContext = 0;
traits->setInheritedWindowPixelFormat = true;
traits->inheritedWindowData = windata;


// Create the Graphics Context
osg::GraphicsContext* gc = osg::GraphicsContext::createGraphicsContext(traits.get());


// Init a new Camera (Master for this View)
osg::ref_ptr<osg::Camera> camera = new osg::Camera;


// Assign Graphics Context to the Camera
camera->setGraphicsContext(gc);


// Set the viewport for the Camera
camera->setViewport(new osg::Viewport(traits->x, traits->y, traits->width, traits->height));


// Set projection matrix and camera attribtues
camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
camera->setClearColor(osg::Vec4f(0.2f, 0.2f, 0.4f, 1.0f));
camera->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(traits->width)/static_cast<double>(traits->height), 1.0, 1000.0);


// Add the Camera to the Viewer
v->setCamera(camera.get());


// Setup the geometry for this control
//TODO seems to need example osghud
//v->setSceneData( createHUD(osg::Vec2(0,traits->height/2.f), osg::Vec2(traits->width,traits->height), handle) );


// Realize the Viewer
v->realize();

/* TODO skip for now
// Start the rendring thread and save it as user data for later clearance
osg::ref_ptr< RenderingThread > renderer = new RenderingThread(v);
renderer->startThread();
v->getCamera()->setUserData( renderer.get() );
*/
}



But I encounter the same issue:
System.AccessViolationException when doing
Code:
traits->inheritedWindowData = windata;


If I investigate more I see that this exception occures in this location in ref_ptr file:

Code:
inline ref_ptr& operator = (T* ptr)
{
if (_ptr==ptr) return *this;
T* tmp_ptr = _ptr;
_ptr = ptr;
if (_ptr) _ptr->ref();
// unref second to prevent any deletion of any object which might
// be referenced by the other object. i.e rp is child of the
// original _ptr.
if (tmp_ptr) tmp_ptr->unref(); <--System.AccessViolationException!
return *this;
}




------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=60195#60195

Trajce Nikolov NICK

unread,
Jul 7, 2014, 11:25:50 AM7/7/14
to OpenSceneGraph Users
I just did the same Win32 example and it works fine. Please, remove the comment from the RenderingThread since it is doing the rendering, otherwise you will not see the blue OSG window. Bellow is the code. As for the exceptions, I think you are mixing debug and release libs of OSG with your program. If you are running debug, then link against osgd.lib, osgViewerd.lib and OpenThreadsd.lib

// TestWin32.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "TestWin32.h"

#include <osgViewer/Viewer>
#include <osgViewer/api/Win32/GraphicsWindowWin32>
#include <OpenThreads/Thread>

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR 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);

class RenderingThread : public OpenThreads::Thread, public osg::Referenced
{
public:
RenderingThread(osgViewer::Viewer* viewer)
: m_Viewer(viewer)
, m_Running(false)
{
}

virtual void run()
{
m_Running = true;
while (m_Running)
{
m_Viewer->frame();
}

cancel();
}

void setIsRunning( bool running )
{
m_Running = running;
}

protected:
osg::ref_ptr<osgViewer::Viewer> m_Viewer;
bool m_Running;
};
        // TODO skip for now
        // Start the rendring thread and save it as user data for later clearance
        osg::ref_ptr< RenderingThread > renderer = new RenderingThread(v);
        renderer->startThread();
        v->getCamera()->setUserData( renderer.get() );
}

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

  // TODO: Place code here.
MSG msg;
HACCEL hAccelTable;

// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_TESTWIN32, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}

hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTWIN32));

// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage are only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TESTWIN32));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_TESTWIN32);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
   EmbedOSG(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND - process the application menu
//  WM_PAINT - Paint the main window
//  WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;

switch (message)
{
case WM_COMMAND:
wmId    = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;

case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
--
trajce nikolov nick

Chris Hanson

unread,
Jul 7, 2014, 1:43:16 PM7/7/14
to OpenSceneGraph Users
In the past, I've gotten an HWND from the managed side and created a context off of that in unmanaged C++ accessed via a C library wrapper.

If you can't get this to work, I can give more details.​

Trajce Nikolov NICK

unread,
Jul 7, 2014, 1:46:53 PM7/7/14
to OpenSceneGraph Users
Hi Chris,

> ... I've gotten an HWND from the managed side and created a context off of that in unmanaged C++ accessed via a C library wrapper.

That is my suggested approach (http://forum.openscenegraph.org/viewtopic.php?t=13944) as well. I did it for C# but it is same for managed C++. There are some rules of mixing managed and unmanaged C++ as well, I have seen such an approach while back when but can not recall the details.

Nick


On Mon, Jul 7, 2014 at 7:42 PM, Chris Hanson <xe...@alphapixel.com> wrote:
In the past, I've gotten an HWND from the managed side and created a context off of that in unmanaged C++ accessed via a C library wrapper.

If you can't get this to work, I can give more details.

_______________________________________________
osg-users mailing list
osg-...@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org




--
trajce nikolov nick

Bluish Joe

unread,
Jul 8, 2014, 4:32:32 AM7/8/14
to osg-...@lists.openscenegraph.org
Hi Trajce, you where right: I was mixing debug and release libs, now I fixed it and solved the problem!

Now I tried your code, it works well. Now I need to visualize a model in the viewer. You do setSceneData, passing the result of createHUD. What is createHUD?
I tried a differente way:


Code:
osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile(
"C:\\Path\\to\\OpenSceneGraph\\OpenSceneGraph-3.0.1-VS10.0.30319-x86-release-12741\\data\\cessna.osg");
v->setSceneData(loadedModel);



But does nothing, as loadedModel is 0x00000000 in debug. What am I doing wrong?
Many thanks for your help!

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=60203#60203

Trajce Nikolov NICK

unread,
Jul 8, 2014, 4:36:10 AM7/8/14
to OpenSceneGraph Users
Glad it works.

It can be few things. plugins not found (add the OpenSceneGraph/bin to your PATH), wrong path of the model ....

Nick


--
trajce nikolov nick
Reply all
Reply to author
Forward
0 new messages