WPF World Editor for my DirectX game engine - c++

I am working on a small game and game engine in C++ using DirectX. The purpose is educational & recreational.
My next goal is to build a simple world editor that uses the game engine. For this I will need to move the engine into a dll so it can be consumed by the game and/or by the editor. The world editor will be a stand-alone tool and not part of the game. The main purpose of the world editor will be to read in and display my (custom) scene file, and allow me to annotate/modify properties on world objects (meshes), clone objects, pick up and move objects about and drop them, scale objects, etc., and then save out the modified scene so it can later be read by the game.
It has been recommended that I use wxWidgets for the editor. A bit of research makes me feel that wxWidgets is a bit old and clunky, though I am sure very fine GUIs can be written using it. It's just a steep learning curve that I don't look forward to. I have gotten the samples to build and run, but it was a headache.
A little more research and I find that I can integrate DirectX into a WPF app using a D3DImage. I have done a little with WPF and do not find it too intimidating and there are plenty of good books available (there is only one old one for wxWidgets), as well as scads of information on the web. I have gotten the rotating triangle example working and it seemed pretty straightforward.
So my question is:
Will WPF allow me to build a decent little world editor app that re-uses my game engine?
My game engine currently uses RawInput for mouse and keyboard; how will this work with WPF?
How does WPF affect my message pump?
It looks like I will have to write a lot of functions (facade pattern?) to allow WPF to interact with my game engine. Is there an easy way to factor this out so it doesn't get compiled into the game?
Any other tips or ideas on how to proceed would be greatly appreciated!
Thank you.

You need to create a wrapper class that exposes certain functionality of your game.
For example. This function is in my c++ game engine editor wrapper.
extern "C" _declspec(dllexport) void SetPlayerPos(int id, const float x, const float y, const float z);
Then in your c# wpf application you can create a static class allowing you to use those functions
[DllImport(editorDllName, CallingConvention = CallingConvention.Cdecl)]
public static extern void SetPlayerPos(int id, float x, float y, float z);
You will have to have functions for your basic functionality of the game engine through the dll.
things like
EditorMain
RenderFrame / Update
DXShutdown
So then you can call editormain in your wpf app constructor
System.IntPtr hInstance = System.Runtime.InteropServices.Marshal.GetHINSTANCE(this.GetType().Module);
IntPtr hwnd = this.DisplayPanel.Handle;
NativeMethods.EditorMain(hInstance, IntPtr.Zero, hwnd, 1, this.DisplayPanel.Width, this.DisplayPanel.Height);
You will need to create a message filter class and initialize it in the constructor as well
m_messageFilter = new MessageHandler(this.Handle, this.DisplayPanel.Handle, this);
here's how your message filter class could look
public class MessageHandler : IMessageFilter
{
const int WM_LBUTTONDOWN = 0x0201;
const int WM_LBUTTONUP = 0x0202;
IntPtr m_formHandle;
IntPtr m_displayPanelHandle;
EngineDisplayForm m_parent;
public MessageHandler( IntPtr formHandle, IntPtr displayPanelHandle, EngineDisplayForm parent )
{
m_formHandle = formHandle;
m_displayPanelHandle = displayPanelHandle;
m_parent = parent;
}
public bool PreFilterMessage(ref Message m)
{
if (m.HWnd == m_displayPanelHandle || m.HWnd == m_formHandle)
{
switch (m.Msg)
{
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
{
NativeMethods.WndProc(m_displayPanelHandle, m.Msg, m.WParam.ToInt32(), m.LParam.ToInt32());
if (m.Msg == WM_LBUTTONUP)
{
m_parent.SelectActor();
}
return true;
}
}
}
return false;
}
public void Application_Idle(object sender, EventArgs e)
{
try
{
// Render the scene
NativeMethods.RenderFrame();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
for doing win forms and wpf interop look here
http://msdn.microsoft.com/en-us/library/ms742474.aspx

Related

VCL custom TGraphicControl messes up only on a remote desktop

In a C++ application (using C++Builder 10.3 and VCL), I use a custom class derived from TGraphicControl to draw a custom user interface and a small plot of changing data.
Everything works well in Windows 10 and Windows 7, but if I execute the application in a Remote Desktop session (via a native Windows service) with each redraw the graphics are messed up more.
The problem starts with disappearing elements and wrong LineTo endpoints, but sometimes the elements appear even in a different dialog instead.
Also, switching on a PC from direct to remote access causes dynamically inserted VCL TComboBox elements to get invalid parents and owners, followed by an error message that the TComboBox class is unknown.
I'm using ClientRect in my code. Is this perhaps the problem when working in remote sessions?
Code where I see the problem (it's a bit long and I have trouble making a minimal example without omitting possible causes of the problem)
cpp: https://pastebin.com/vpk3De7J (painter at line 228)
header: https://pastebin.com/3pLy4dEY
class CustomTrgDrawings : public TGraphicControl
{
private:
void __fastcall Paint(void);
public:
__fastcall CustomTrgDrawings(TComponent* Owner);
bool updating; //stops painting when true
};
__fastcall CustomTrgDrawings::CustomTrgDrawings(TComponent* Owner)
: TGraphicControl(Owner)
{
updating = true;
}
void __fastcall CustomTrgDrawings::Paint(void)
{
if (!updating)
return;
Canvas->Brush->Color = TColor(0x220022);
Canvas->Brush->Style = bsSolid;
Canvas->Pen->Color = TColor(0x222222);
Canvas->Pen->Style = psSolid;
Canvas->Pen->Width = 1;
Canvas->FillRect(ClientRect);
}
//---insertion in a vcl form
void __fastcall TMyForm::FormCreate(TObject *Sender)
{
//uses TLabel *myLabel as container
CustomTrgDrawings *drg = new CustomTrgDrawings(myLabel);
}

Render cycle in cocos2d-x

I have a game engine written my my team, it's component based. It has logic components and visual components. In visual components there is a function named updateVisual(delta) and everything is drawn there.
For example, let's take physic ball entity in world:
class LogicBallComponent
{
// ...
};
class VisualBallcomponent
{
sfml::Texture mBallTexture;
void updateVisual(float)
{
mBallTexture.translate(...);
GlobalDisplayManager::instance().draw(mBallTexture);
}
};
GlobalDisplayManager returns some window representation which creates gl-states, etc. (sf::RenderWindow in sfml). This system is easy to integrate.
Now I need to make android-game using my engine. I've chosen cocos2d-x to use for window creation, rendering, fonts, resources etc.
There is another way to do the job:
class Ball : public CLayer
{
bool Ball::init() {
CSprite* sprite = CSprite::create(...);
this->addChild(sprite, 0); // [!]
}
};
And I don't know how to use it in my way. Is there such possibility?
You should check out the function "void CCDisplayLinkDirector::mainLoop(void)", which is the main loop of coco2d-x rendering engine.
coco2d-x provides wrappers for periodic calling loop. In iOS you should check the function startMainLoop of CCDirectorCaller.mm in platform/ios.

C++ / SDL encapsulation design help

So I am semi-new to C++, and completely new to SDL. Most of my conceptual knowledge of OOP comes from Java and PHP. So bear with me.
I am trying to work out some simple design logic with my program / soon to be side-scroller. My problem lies with trying to make my 'screen' layer (screen = SDL_SetVideoMode(...)) accessible to all my other classes; Hero class, background layer, enemies, etc. I have been loosely following some more procedural tutorials, and have been trying to adapt them to a more object oriented approach. Here is a little bit of what I have so far:
main.cpp
#include "Game.h"
#include "Hero.h"
int main(int argc, char* argv[])
{
//Init Game
Game Game;
//Load hero
Hero Hero(Game.screen);
//While game is running
while(Game.runningState())
{
//Handle Window and Hero inputs
Game.Input();
Hero.userInput();
//Draw
Game.DrawBackground();
Hero.drawHero();
//Update
Game.Update();
}
//Clean up
Game.Clean();
return 0;
}
As you can see, I have a Game class, and a Hero class. The Game class is responsible for setting up the initial window, and placing a background. It also updates the screen as you can see.
Now, since my Game class holds the 'screen' property, which is a handle for SDL_SetVideoMode, I am stuck passing this into any other class (ex: Hero Hero(Game.screen);) that needs to update to this screen... say via SDL_BlitSurface.
Now, this works, however I am getting the idea there has GOT to be a more elegant approach. Like possibly keeping that screen handler on the global scope (if possible)?
TLDR / Simple version: What is the best way to go about making my window / screen handler accessible to all my subsequent classes?
I like the way you are doing it.
Though rather than passing the screen reference I would pass a reference to a game itself. Thus each hero object knows which game it belongs too, it can then ask the game object for the screen as required.
The reason I would do this is so that in a few years when your game is a wide and successful product and you convert it for online-play you really need to do no work. The game server will be able to easily support multiple game objects, each game object hosting multiple hero objects. As each hero object wants to draw it asks the game for the screen abd updates the screen (the screen can now very from game object to game object and still work perfectly (as long as they have the same interface).
class Game
{
public:
Game(Screen& screen)
: screen(screen)
{}
virtual ~Game() {}
virtual Screen& screen() { return theGameScreen;}
void update() { /* Draw Screen. Then draw all the heros */ }
private:
friend Hero::Hero(Game&);
friend Hero::~Hero();
void addHero(Hero& newHero) {herosInGame.push_back(&newHero);}
void delHero(Hero& newHeor) {/* Delete Hero from herosInGame */}
// Implementation detail about how a game stores a screen
// I do not have enough context only that a Game should have one
// So theoretically:
Screen& theGameScreen;
std::vector<Hero*> herosInGame;
};
class Hero
{
public:
Hero(Game& game)
: game(game)
{game.addHero(*this);}
virtual ~Hero()
{game.delHero(*this);}
virtual void Draw(Screen& screen) {/* Draw a hero on the screen */}
private:
Game& game;
};
Main.
#include "Game.h"
#include "Hero.h"
int main(int argc, char* argv[])
{
//Init Game
Screen aScreenObject
Game game(aScreenObject);
//Load hero
Hero hero(game); // or create one hero object for each player
//While game is running
while(game.runningState())
{
//Handle Window and Hero inputs
Game.Input();
Hero.userInput();
//Update
Game.update();
}
//Clean up
// Game.Clean(); Don't do this
// This is what the destructor is for.
}
I don't know if it's elegant, but what I do for the side-scrolling game I'm making is to make a show() function in each class than draws to the screen, and passing the screen handle as a parameter. Then whenever I want to draw something to the screen I just do foo.show(screen). The screen handle is in main().
The first, and honestly, easiest solution, is to use a global variable. Yes, yes, yes, everyone says global variables are horrible, but in this situation, it's perfectly fine.
The other solution, which is a bit more work, but can result in somewhat more portable code, is to encapsulate your drawing functions into a single, static class. This way, you can draw to the screen directly without having to pass around a variable, or have to lie awake at night thinking the code review police will get you because you used a global variable. Plus, this can potentially make it easier if you ever decide to port your game to a new library. Some quick and dirty pseudocode:
class Drawing
public:
static void Draw(x, y, sdl_surface graphic, sdl_rect & clip=null);
static void init(sdl_surface & screen);
private:
sdl_surface screen;
void Drawing::Draw(x, y, sdl_surface graphic, sdl_rect & clip=null)
{
sdl_blit(x, y, graphic, clip);
}
void Drawing::init(sdl_surface & screen)
{
this.screen=screen;
}
It sounds like you're looking for a way to implement the Singleton design pattern, where you would have a single Screen object. If you know you're only ever going to have a single Screen object it should work fine.
In this case you would implement a static method on the Game class:
class Game
{
public:
static Game *GetTheSceenObject();
private:
static Screen *theScreen; // details of initialisation ommitted
}
that would return a pointer to the single Screen object.
If there is a possibility that you'll end up using multiple SDL screens, though, it may be worth creating a Draw() method in your Hero class that is responsible for drawing the hero on each of the Screens managed by the Game class by iterating through a list provided by the Game class.
That functionality could be contained in the methods of a common DrawableThingy class that Hero and Enemy are derived from.
Passing Game.screen around is more OO (though it might be better to have a getter function) than having one instance of it that can be accessed from any class, because if you have one global version, you can't have more than one Game.screen at any one time.
However if you know you'll only ever need one in the entire lifetime of the program, you might consider making Game::Screen() a public static function in the Game class that returns a private static member screen. That way, anyone can call Game::Screen() and get the screen.
Example (assuming ScreenType is the type of screen and that you store a pointer to it):
class Game {
public:
static ScreenType* Screen() {
if (!screen)
screen = GetScreenType(args);
return screen;
}
}
private:
// if you don't already know:
// static means only one of this variable exists, *not* one per instance
// so there is only one no matter how many instances you make
// the same applies to static functions, which you don't need an instance to call
static ScreenType* screen;
};
// and somewhere in a .cpp file
ScreenType* Game::screen = NULL;
// and you use it like this
ScreenType* scr = Game::Screen();
// use scr

Glut: how to know when the window is moving?

I have a problem with glut, I would like to have a callback to know when the user is moving the window of my application, and I didn't found anything in glut.
My goal is to make an application only on windows, is it possible to do this with MFC keeping my glut code?
Thanks in advance
I couldn't find a call back function but you could do it by hand with glutGet:
int glutGet(GLenum state);
An example of what you might do is:
bool window_change(void)
{
int init_x = glutGet(GLUT_INIT_WINDOW_X);
int init_y = glutGet(GLUT_INIT_WINDOW_Y);
int pos_x = glutGet(GLUT_WINDOW_X);
int pos_y = glutGet(GLUT_WINDOW_Y);
return (init_x != pos_x || init_y != pos_y);
}
This will return true if it's moved from it's initial spot. If you want to see if it's moved since the last check, try:
bool window_change(void)
{
static int init_x = glutGet(GLUT_INIT_WINDOW_X);
static int init_y = glutGet(GLUT_INIT_WINDOW_Y);
int pos_x = glutGet(GLUT_WINDOW_X);
int pos_y = glutGet(GLUT_WINDOW_Y);
bool result = init_x != pos_x || init_y != pos_y;
init_x = pos_x;
init_y = pos_y;
return result;
}
You can set the window position by using the function: glutPositionWindow
void glutPositionWindow(int x, int y);
the idea from Bruce is very good. i think there is not another option while using GLUT.
i think this scenario is something that GLUT was not developed for. GLUT is a toolkit for OpenGL, which wraps window- and input-management across platforms. it has a lot of uses,
but why should it care, when its window is dragged?
i think if you (or your program) care, then you should implement your own window- and input-management anyway.
which leads me to your second question. you can use OpenGL with MFC (although my recommendation strongly depends on what you are planing). you should not use GLUT then, because MFC has its own way of handling input, windows, event management, rendering/drawing ...
if you really want to do it:
http://www.codeproject.com/KB/openGL/OpenGL_MFC_AppWizard.aspx
You might try using the glutTimerFunction to periodically call Bruce's example function. It will have to take an integer as a parameter used to identify the source of the callback request. The glutTimerFunction is also designed to only be called once, then it deletes itself. However, it can schedule a call on itself. I ran into this problem using PyOpenGL so I'm not going to go through the C agony of getting this to compile. From Bruce's generous example altered. Obviously a hack, but better than scrapping.
int main(void)
{
...
glutTimerFunc(0, window_change, 0);
}
void window_change(int id)
{
int init_x = glutGet(GLUT_INIT_WINDOW_X);
int init_y = glutGet(GLUT_INIT_WINDOW_Y);
int pos_x = glutGet(GLUT_WINDOW_X);
int pos_y = glutGet(GLUT_WINDOW_Y);
...
/* call back again after 1 second has passed */
glutTimerFunc (1000, window_change, id);
}
http://www.opengl.org/resources/faq/technical/glut.htm
GLUT is actually fairly limited, and does not expose all window events to the client. However it does provide a lot of boiler code plate for WGL (on Windows) and GLX (on X11) that is probably not worth rewriting.
When I had a hobby project that was using GL, and there were certain events that I couldn't handle via GLUT, what I did is fork the open source freeglut. That is, download the tarball, and edit the library's WindowProc (Windows) or XGetEvent() loop (on X) and simply add the missing callbacks to the library.
You'll have a dependency on your own GLUT modifications, but it'll work, and you won't have to write as much boiler-plate code as if you were targeting WGL or GLX directly.
You'll probably want to link it statically so it doesn't conflict with any other freeglut.

Transparent background for MFC-hosted Windows Forms UserControl

I am using CWinFormsControl to host a Windows Forms UserControl in an MFC dialog. I have set the property DoubleBufferd to true. According to the docs this results in AllPaintingInWmPaint and UserPaint to be set to true too (not sure if this matters). How can I force (or fake) the UserControl to draw its background transparent?
This is what I have set in the contructor of my UserControl:
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = Color.Transparent;
this.DoubleBuffered = true;
I have a potential solution that may work, although I would need more information on how your animated controls work to be sure. There is one unfortunate side effect in my solution, and that is that the DoubleBuffering property only works correctly in .NET control containers. When hosted in MFC, your controls will flicker on resize and other similar display-tearing refreshes. This may cause issues with animated controls, depending on how they are performing drawing work.
To start, I first looked for issues when hosting a .NET UserControl in MFC. After quite a while of reading through the instantiation code of CWinFormsControl::CreateControl() and everything beneath, nothing out of the ordinary came up. In fact, aside from the quirks of loading managed references, the code is identical to how transparent ActiveX controls are loaded.
After learning that piece of information, I used Spy++ to look at whether the .NET control is instantiated with a windowed container. Indeed, it is. After a rather lengthy investigation, this control container appears to be controlled by an instance of a utility class, System.Windows.Forms.Control.AxSourcingSite, which has no documentation and almost no visibility. This was a little bit surprising to me, as usually it is the reverse. MFC and the lesser used WTL have great support for in-place activation, and usually controls can work with whatever the host has setup, whether windowed or not.
From here, I checked on whether this same container exists when the .NET control is hosted in a .NET control container. I assumed that perhaps the control would have its own window, without any special adapters. Turns out, I was wrong. The control works the same way as in-place non-windowed controls. This means that in order to preserve behavior, a solution must allow the regular .NET activation to proceed as normal, and when windowed, it should do something else.
A close look at the MFC hosted version reveals an off-white background drawn in by the .NET UserControl. After more spading and testing, this off-white background is definitely drawn in by a hidden layer in the window message handling chain. This means we can hack together a solution by using AllPaintingInWmPaint.
To demonstrate this, here is the source code for a UserControl that can be hosted in both .NET and the MFC managed container. This control relies on the following things to work around the transparency issues.
Add a member variable, m_ReroutePaint, to allow us to know when we need to override the default WM_PAINT behavior.
Override base.CreateParams and add the WS_EX_TRANSPARENT flag. When this property is called, set m_ReroutePaint to true. This property was not called when the Control is activated in a .NET container.
Override the WndProc() method, and patch up WM_PAINT to our liking if we are rerouting painting activities.
Use BeginPaint()/EndPaint() via Interop to setup/teardown WM_PAINT. Use the provided HDC as the initializer for a Graphics object.
Here are some caveats:
The background color of the control cannot be changed through the BackColor .NET property after the control has been instantiated. One can add workarounds for this, but to keep the sample short and simple, I left out code to do this as the intended goal is for transparent controls. However, if you start with a background color that isn't transparent, the workaround is unnecessary. I did leave code in for this case.
In attaching a HDC to a Graphics object in the WM_PAINT handler via Graphics.FromHdc(), the documentation suggests that Graphics.ReleaseHdc() should be called. However, by doing this, a GDI handle leak occurs. I have left it commented out here, but perhaps someone with GDI+ internals knowledge can figure this out.
This UserControl was created in a project named 'UserCtrlLibrary1'. The DebugPrintStyle() items may be safely removed. Also, handlers were added for resize and paint, which are both in a separate designer file, but trivial to add. AllPaintingInWmPaint should be true through the lifetime of the control.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace UserCtrlLibrary1
{
public partial class CircleControl : UserControl
{
public CircleControl()
{
InitializeComponent();
DebugPrintStyle(ControlStyles.SupportsTransparentBackColor, "initial");
DebugPrintStyle(ControlStyles.AllPaintingInWmPaint, "initial");
DebugPrintStyle(ControlStyles.UserPaint, "initial");
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
DebugPrintStyle(ControlStyles.SupportsTransparentBackColor, "current");
DebugPrintStyle(ControlStyles.AllPaintingInWmPaint, "current");
DebugPrintStyle(ControlStyles.UserPaint, "current");
}
public void DebugPrintStyle(ControlStyles cs, string prefix)
{
Debug.Print("{0}: {1}={2}", prefix, cs.ToString(), this.GetStyle(cs).ToString());
}
bool m_ReroutePaint;
const int WS_EX_TRANSPARENT = 0x0020;
protected override CreateParams CreateParams
{
get
{
if (this.BackColor == Color.Transparent)
{
m_ReroutePaint = true;
CreateParams cp = base.CreateParams;
cp.ExStyle |= WS_EX_TRANSPARENT;
return cp;
}
else
{
return base.CreateParams;
}
}
}
private void CircleControl_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
using (SolidBrush b = new SolidBrush(Color.Orange))
{
g.FillEllipse(b, 0, 0, this.Width, this.Height);
}
}
private void CircleControl_Resize(object sender, EventArgs e)
{
this.Invalidate();
}
const int WM_PAINT = 0x000F;
[DllImport("user32.dll")]
static extern IntPtr BeginPaint(IntPtr hwnd, out PAINTSTRUCT lpPaint);
[DllImport("user32.dll")]
static extern bool EndPaint(IntPtr hWnd, [In] ref PAINTSTRUCT lpPaint);
[Serializable, StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[StructLayout(LayoutKind.Sequential)]
struct PAINTSTRUCT
{
public IntPtr hdc;
public bool fErase;
public RECT rcPaint;
public bool fRestore;
public bool fIncUpdate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] rgbReserved;
}
protected override void WndProc(ref Message m)
{
if ((m.Msg == WM_PAINT) && (m_ReroutePaint))
{
PAINTSTRUCT ps = new PAINTSTRUCT();
BeginPaint(this.Handle, out ps);
using (Graphics g = Graphics.FromHdc(ps.hdc))
{
using (PaintEventArgs e = new PaintEventArgs(g, new Rectangle(ps.rcPaint.Left, ps.rcPaint.Top, ps.rcPaint.Right - ps.rcPaint.Left, ps.rcPaint.Bottom - ps.rcPaint.Top)))
{
this.OnPaint(e);
}
// HACK: This is supposed to be required...
// but it leaks handles when called!
//g.ReleaseHdc(ps.hdc);
}
EndPaint(this.Handle, ref ps);
return;
}
base.WndProc(ref m);
}
}
}
In case anyone other than the OP would like to test this, here are the details to get this up and running in MFC. I created a MFC SDI project, without document-view architecture, with ActiveX control support. This results in generation of typical «project-name» class, ChildView class, and MainFrm classes.
Inside the ChildView.h header, add the following header material before the class (but after #pragma once). Alter the name of the .NET control library if yours is different.
#include <afxwinforms.h>
#using "UserCtrlLibrary1.dll"
using namespace UserCtrlLibrary1;
Add a member variable for the .NET control host. Arbitrarily, I placed mine under the Attributes section.
// Attributes
public:
CWinFormsControl<CircleControl> m_Circle;
Also, I added handlers for OnCreate() and OnSize(). public/protected visibility may be adjusted as you need.
// Generated message map functions
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
public:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
In ChildView.cpp, I added function bodies for all the items listed above. The message map also needs updates if you didn't use ClassWizard to add the windows message handlers.
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
ON_WM_CREATE()
ON_WM_SIZE()
END_MESSAGE_MAP()
void CChildView::OnPaint()
{
CPaintDC dc(this); // device context for painting
RECT rt;
this->GetClientRect(&rt);
rt.right = (rt.right + rt.left)/2;
dc.FillSolidRect(&rt, RGB(0xFF, 0xA0, 0xA0));
}
int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
RECT rt;
this->GetClientRect(&rt);
m_Circle.CreateManagedControl(WS_VISIBLE, rt, this, 1);
return 0;
}
void CChildView::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
RECT rt;
this->GetClientRect(&rt);
m_Circle.MoveWindow(rt.left, rt.top, rt.right - rt.left, (rt.bottom - rt.top)/2, TRUE);
}
These changes create an instance of the UserControl, and anchor it against the top half of the view. The OnPaint() handler draws a pink band in the left half of the view. Together, transparency should be apparent in the top left quadrant of the view.
To get the MFC project to compile and run, a copy of the UserCtrlLibrary1 output needs to be placed in the same location as the executables for UserCtrlMFCHost. Also, another copy needs to be placed in the same directory as the project source code files for the #using statement. Last, the MFC project should be modified to use the /clr compilation script. In the Configuration Properties section, General subsection, this switch is listed under Project Defaults.
One interesting thing of note, is that this allows the ^ suffix for access to managed classes. At some points in developing this solution, I debated adding methods to be called only when instantiated from MFC, but given that there are ways to detect windowed/non-windowed activation, this wasn't necessary. Other implementations may need this, though, so I feel it is good to point this out.
How to: Compile MFC and ATL code with /clr