How to intercept project save event in visual studio 2017 sdk? - visual-studio-2017

It's possible to intercept the project save event in visual studio 2017 sdk?
UPDATE
I'm currently developing an extension of visual studio 2017 where I need to know when any change is persisted.
Ex: When I add a new reference in the project (I know there are events for when the reference is added / changed / removed but did not meet my need), the project is marked as pending to be saved. I need to intercept it when it's saved (better if it is before saving).
I tried the Dte.Events.DocumentEvents.DocumentSaved event, but it is not triggered in the save project; DTE.Events.SolutionEvents and DTE.Events.SolutionItemEvents have no event of the type I need.
It is possible?

The correct one in this case would be to use implement IVsRunningDocTableEvents3 overriding the OnBeforeSave method.
In this way, I know exactly when a project is to be saved and perform what it needs.
Ex.:
uint cookie;
var runningDocumentTable = (IVsRunningDocumentTable)GetGlobalService(typeof(SVsRunningDocumentTable));
runningDocumentTable.AdviseRunningDocTableEvents(new RunningDocTableEventsHandler(), out cookie);
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
namespace YourProject
{
internal class RunningDocTableEventsHandler : IVsRunningDocTableEvents3
{
#region Methods
public int OnAfterFirstDocumentLock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining)
{
return VSConstants.S_OK;
}
public int OnBeforeLastDocumentUnlock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining)
{
return VSConstants.S_OK;
}
public int OnAfterSave(uint docCookie)
{
return VSConstants.S_OK;
}
public int OnAfterAttributeChange(uint docCookie, uint grfAttribs)
{
return VSConstants.S_OK;
}
public int OnBeforeDocumentWindowShow(uint docCookie, int fFirstShow, IVsWindowFrame pFrame)
{
return VSConstants.S_OK;
}
public int OnAfterDocumentWindowHide(uint docCookie, IVsWindowFrame pFrame)
{
return VSConstants.S_OK;
}
public int OnAfterAttributeChangeEx(uint docCookie, uint grfAttribs, IVsHierarchy pHierOld, uint itemidOld, string pszMkDocumentOld, IVsHierarchy pHierNew, uint itemidNew, string pszMkDocumentNew)
{
return VSConstants.S_OK;
}
public int OnBeforeSave(uint docCookie)
{
/////// MY CODE ////////
return VSConstants.S_OK;
}
#endregion Methods
}
}

The DTE.Events.DocumentEvents works with opened project files, not entire project system. Each project loaded and displayed in the solution explorer is loaded by the project system for that project's type. So different version of project has its own project system implementation.
According to your requirement, you need to implement IVsSolutionEvents3 to be notified of a project being loaded/unloaded. And register that object as a listener in your package initialization code via the SVsSolutionBuildManager service.
Then implement IVsHierarchyEvents to be notified of project changes and Call AdviseHierarchyEvents on the IVsHierarchy object passed to the IVsSolutionEvents3's OnAfterProjectOpen implementation to register the event listener object.
More detailed explanation, please refer to below thread.
Visual Studio SDK - Handling File Add, Remove, and Rename Events

Related

ShowWindow fails to focus on Win10 Calculator app [duplicate]

I have an application which may only have one instance of itself open at a time. To enforce this, I use this code:
System.Diagnostics.Process[] myProcesses = System.Diagnostics.Process.GetProcesses();
System.Diagnostics.Process me = System.Diagnostics.Process.GetCurrentProcess();
foreach (System.Diagnostics.Process p in myProcesses)
{
if (p.ProcessName == me.ProcessName)
if (p.Id != me.Id)
{
//if already running, abort this copy.
return;
}
}
//launch the application.
//...
It works fine. I would also like it to be able to focus the form of the already-running copy. That is, before returning, I want to bring the other instance of this application into the foreground.
How do I do that?
SetForegroundWindow works, to a point:
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
// ...
if (p.Id != me.Id)
{
//if already running, focus it, and then abort this copy.
SetForegroundWindow(p.MainWindowHandle);
return;
}
// ...
This does bring the window to the foreground if it is not minimized. Awesome.
If the window IS minimized, however, it remains minimized.
It needs to un-minimize.
Solution via SwitchToThisWindow (Works!):
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
[STAThread]
static void Main()
{
System.Diagnostics.Process me = System.Diagnostics.Process.GetCurrentProcess();
System.Diagnostics.Process[] myProcesses = System.Diagnostics.Process.GetProcessesByName(me.ProcessName);
foreach (System.Diagnostics.Process p in myProcesses)
{
if (p.Id != me.Id)
{
SwitchToThisWindow(p.MainWindowHandle, true);
return;
}
}
//now go ahead and start our application ;-)
}
I had the same problem and SwitchToThisWindow() worked the best for me. The only limitation is that you must have XP sp1 installed. I played with SetForegroundWindow, ShowWindow, and they both had problems pulling the window into view.
C# equivalent of Tom Juergens's answer. Works like a charm for me.
private const int SW_SHOWNORMAL = 1;
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool ShowWindow(IntPtr hwnd, int nCmdShow);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetForegroundWindow(IntPtr hwnd);
public void SetForeground()
{
Process[] processes = Process.GetProcessesByName("process name");
foreach (Process p in processes) {
ShowWindow(p.MainWindowHandle, SW_SHOWNORMAL);
SetForegroundWindow(p.MainWindowHandle);
}
}
Same as OP, I found that SetForegroundWindow alone wasn't enough when the window was minimized. Since I didn't want to use SwitchToThisWindow, I chose ShowWindow followed by SetForegroundWindow.
Works well for me!
private const SW_SHOWNORMAL = 1
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Function ShowWindow(ByVal hwnd As IntPtr, ByVal nCmdShow As integer) As Boolean
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Private Function SetForegroundWindow(ByVal hwnd As IntPtr) As Boolean
End Function
Sub SetForeground()
Dim processes As Process() = Process.GetProcessesByName("myprocess")
For Each p as Process in processes
ShowWindow(p.MainWindowHandle, SW_SHOWNORMAL)
SetForegroundWindow(p.MainWindowHandle)
Next
End Sub
I believe you will want to use SetForegroundWindow
MSDN Example
Complete Side Note...
You can use
Process.GetProcessesByName(me.ProcessName)
instead of looping over all the processes running on the system...
UPDATE
PInvoke Rules for this sort of thing...
Can you grab MainWindowHandle property of the Process object and send it a WM_USER message that you can interpret as "some other instance wants to bring me to the front".
It is a very frequent behavior in desktop applications, I regularly have to do this when I create a new WPF application. So I have created a SingletonApp class which inherits from Application :
public class SingletonApp : Application
{
private static readonly System.Threading.Mutex mutex;
private static readonly string processName;
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int flags);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hwnd);
static SingletonApp()
{
processName = Process.GetCurrentProcess().ProcessName;
mutex = new System.Threading.Mutex(false, $"Local\\{processName}");
}
/// <summary>
/// A base class for application needing to prevent multiple instances
/// </summary>
public SingletonApp()
{
if (!mutex.WaitOne(0, false))
{
// Give focus to existing instance before shutdown
BringToFront(processName);
Current.Shutdown();
}
}
public void BringToFront(string processName)
{
Process process = Process.GetProcessesByName(processName).FirstOrDefault();
if (process != null)
{
// In case of window is minimized
ShowWindow(process.MainWindowHandle, 1); // 1 = Normal
SetForegroundWindow(process.MainWindowHandle);
}
}
}
To use it, you just have to inherit from SingletonApp instead of Application in your App.xaml.cs :
public partial class App : SingletonApp
Don't forget to update App.xaml too :
<utils:SingletonApp x:Class="MyApp.App"
[...]
xmlns:utils="clr-namespace:MyApp.Utils"
Startup="App_OnStartup">
With this it becomes very easy to implement this behavior in every new desktop client.

MS Visual C++ Multithreading accessing allocated variables causes access violation

I have an issue with an MFC dialog based application build with MSVC 2013. To make the main dialog accessible also during more elaborate functions, I'm using multi-threading. A click on a button in the dialog calls a "worker function" that is worked out by another thread.
Here's an excerpt of the class:
class CpiezcamDlg : public CDialogEx
{
protected:
virtual BOOL OnInitDialog();
public:
CWinThread *m_thread1;
void StartSweepAndImageThread()
{
m_thread1 = AfxBeginThread(SweepAndImageThreadProc, this);
}
private:
static UINT SweepAndImageThreadProc(LPVOID pParam)
{
CpiezcamDlg *pThis = (CpiezcamDlg *)pParam;
UINT nRet = pThis->DoSweepAndImage();
return nRet;
}
UINT DoSweepAndImage();
UINT16 steps;
CString *imgs_name;
};
Clicking a button calls StartSweepAndImageThread which itself calls SweepAndImageThreadProc and finally DoSweepAndImage. In the function DoSweepAndImage, variables of the class are accessed (read and write). Amongst others, there is imgs_name. The usage is:
UINT CpiezcamDlg::DoSweepAndImage()
{
// ...
CString str;
str.Format(_T("Test"));
AddStageListText(str);
imgs_name[i] = str;
// ...
}
while imgs_name is initialized like
steps = 4;
imgs_name = new CString[steps];
in the OnInitDialog function.
The problem is that when pressing the mention button I receive
0xC0000005: Access violation reading location 0xFDFDFDF9.
exactly on imgs_name[i] = str;. When using a statical array, that is instead of CString *imgs_name; I define CString imgs_name[4];, everything works well. However, I very much would like to have that CString variable a dynamical one. Thanks in advance for your help!
PS: When I evaluated this in a serial way, i.e. when running the DoSweepAndImage function in the main thread, everything goes well. That's why I assume the access violation is due to the multi-threading.
#Wimmel: The loop over i in DoSweepAndImage is
for (UINT16 i = 0; i < steps; i++)

ActiveX and COM for interprocess communication

I have a closed source program that generates ActiveX events, and I need to modify mine so that these events can be received. So we have two separate executables, and no GUI stuff is used. So far I got to this point, which only works if the event is generated and received by the same process:
[event_source(native)]
class CSource {
public:
__event void MyEvent(int nValue);
};
[event_receiver(native)]
class CReceiver {
public:
void MyHandler(int nValue) { ... }
void hookEvent(CSource* pSource) {
__hook(&CSource::MyEvent, pSource, &CReceiver::MyHandler);
}
void unhookEvent(CSource* pSource) {
__unhook(&CSource::MyEvent, pSource, &CReceiver::MyHandler);
}
};
int main() {
CSource source;
CReceiver receiver;
receiver.hookEvent(&source);
__raise source.MyEvent(123);
receiver.unhookEvent(&source);
}
Now, the event_source is in the application I need to interface with. How can I connect the receiver and the source when they are in two separate processes?
Either an explanation or some references will be useful.
You don't want attributed C++ since even though it is still supported, reality is that it has been deprecated since at the very least VS 2008
You need event_receiver(com, not native type since ActiveX events are in question
The items above suggest that you don't use attributes and instead use IDispEventImpl or IDispEventSimpleImpl class to implement receiver of ActiveX control events (the article gives code snippet and references sample project).

TDD for plupload with Django/Splinter

I'm trying to set up tests for a upload using the plupload queue widget.
I'm using Splinter for in-browser test, but I couldn't find a way to make it happen. Splinter has some methods to attach files, but only if it's a simple file field.
Another way would be click the button to browse the files, and choose the file... but I don't think it's possible using Splinter (or selenium), is it?
Or with drag-n-drop of the files.
Anyone has any suggestion of the best way to automatize theses tests?
Its possible to automate user actions done on PLUpload control using Selenium- WebDriver. Please find the WebDriver C# code below, which clicks on a flash button object and selects a file using keyboard events,
using System;
using System.Windows.Forms;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium;
using OpenQA.Selenium.Support;
using OpenQA.Selenium.Interactions;
using NUnit.Framework;
namespace BusinessCreation
{
class PlUpload
{
static void Main(string[] args)
{
IWebDriver driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://www.plupload.com/example_queuewidget.php");
driver.FindElement(By.XPath("//object[#data='/plupload/js/plupload.flash.swf']")).Click();
SendKeys.SendWait(#"C:\Users\Public\Pictures\Sample Pictures\Dock.jpg");
SendKeys.SendWait(#"{Enter}");
}
}
}
I had a similar problem with the PlUpload widget. Thank you to CheryJose for putting me on the right track.
First of all I had to create a small class to find out which windows were open and return them as a dictionary of windows.
public static IDictionary<string, IntPtr> GetOpenWindows()
{
IntPtr lShellWindow = GetShellWindow();
Dictionary<string, IntPtr> lWindows = new Dictionary<string, IntPtr>();
EnumWindows(delegate(IntPtr hWnd, int lParam)
{
if (hWnd == lShellWindow) return true;
if (!IsWindowVisible(hWnd)) return true;
int lLength = GetWindowTextLength(hWnd);
if (lLength == 0) return true;
StringBuilder lBuilder = new StringBuilder(lLength);
GetWindowText(hWnd, lBuilder, lLength + 1);
lWindows[lBuilder.ToString()] = hWnd;
return true;
}, 0);
return lWindows;
}
public delegate bool EnumDelegate(IntPtr hWnd, int lParam);
public delegate bool EnumedWindow(IntPtr handleWindow, ArrayList handles);
[DllImport("USER32.DLL")]
public static extern bool EnumWindows(EnumDelegate enumFunc, int lParam);
[DllImport("USER32.DLL")]
public static extern IntPtr GetShellWindow();
[DllImport("USER32.DLL")]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("USER32.DLL")]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("USER32.DLL")]
public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
In the Selenium page code I click on the button to launch the PlUpload window and put in a short wait. (This is not shown in the code)
Then I use the code below to find all open windows
IDictionary<string, IntPtr> getOpenWindows = GetOpenWindows();
Switch to the PlUpload window (the name of the window is different across browsers. Be Aware!)
IntPtr hWnd = getOpenWindows["File Upload"];
SetForegroundWindow(hWnd);
Type in the path for the file
SendKeys.SendWait(filename);
Press Enter
SendKeys.SendWait(#"{Enter}");
The PlUpload window will close so we switch back to the browser window (in this case Firefox)
hWnd = getOpenWindows["Mozilla Firefox"];
SetForegroundWindow(hWnd);
There are a couple of issues with this as the window titles are different depending on which browser is being used, so this will need to be taken into account for a complete solution. In addition, when this section of code is executing do not bring any other windows to the foreground as this window will receive the 'SendKeys' rather than the required window.

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