Feeds:
Posts
Comments

Archive for the ‘VC++ 2005’ Category

While it’s an absolute tragedy that C++ does not directly support compiled Xaml, you can use Xaml dynamically from a C++ Avalon app using XamlReader::Load. Let me show you how to do that, using a simple example. You can create your Xaml file, either using a text editor or using a temporary dummy C# or VB project.

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    >
  <Canvas Background="#FF008000">
    <TextBox HorizontalAlignment="Left"
             Width="240" Height="30"
             Name="mTextBox" />
    <Button  HorizontalAlignment="Left"
             Width="75" Height="23"
             Name="mButton"
             Canvas.Top="45">Set Title</Button>
  </Canvas>
</Window>

Now here’s the C++ code that will load this Xaml, show the window, and also hook events to the member controls. The code is mostly self-explanatory if you understand basic .NET event handling.

ref struct EventHelper
{
    static void OnBtnClick(Object^ sender, RoutedEventArgs^ e)
    {
        Window^ mainwnd = Application::Current->MainWindow;
        TextBox^ txtbox = (TextBox^)mainwnd->FindName("mTextBox");
        mainwnd->Title = txtbox->Text;
    }
};

[STAThread]
int main(array<System::String^>^args)
{
    Stream^ st = File::OpenRead(
        "C:\\SomePath\\Window1.xaml");
    Window^ mainwnd = (Window^)XamlReader::Load(st);
    mainwnd->Height = 400;
    mainwnd->Width = 600;
    mainwnd->Title = "Dynamically load Xaml";
    //FindName will find the element with the specified identifier
    Button^ btn = (Button^)mainwnd->FindName("mButton");
    btn->Click += gcnew RoutedEventHandler(&EventHelper::OnBtnClick);
    st->Close();
    return (gcnew Application())->Run(mainwnd);
}

This Avalon stuff is pretty powerful I can tell you. Expect more entries as I figure out more stuff :nerd:

Read Full Post »

This is my latest Code Project article, and it shows you how to use the Windows Forms 2.0 MenuStrip and ToolStrip controls in your MFC applications to give them an Office 2003 look and feel. These Forms controls are pretty well written, and if you change the XP theme/style, they change accordingly, just like Word or Excel would!

Read Full Post »

9 times out of 10, when I select a class name or a keyword and hit F1, the Document Explorer shows me an “Information Not Found” page. But at the same time, the index on the left has selected the topic I am looking for, which means all I need to do is to double click on that topic and the expected page loads. So it’s truly mysterious to me why the Document Explorer says it cannot find the required information! Am I the only one who gets these sort of errors? Pretty damned annoying when it happens all the time!

Read Full Post »

I was working on an app that uses CCW to access a managed library. One of the methods in the library returns an array<String^>^. The COM version of this method will have a SAFEARRAY** as the [out,retval] parameter. Not having a lot of COM experience, I was pretty surprised to find how little documentation there is on MSDN or any where else for that matter on using a SAFEARRAY. All I wanted to do was to enumerate the returned array. Eventually it turned out to be pretty easy. For the interested few, here’s what you need to do.

SAFEARRAY* pSA= NULL;
if(SUCCEEDED(pXXXX->GetXXXX(XXXXid, &pSA)))
{
    long lbound = 0, ubound = 0;

    SafeArrayGetLBound (pSA, 1, &lbound);
    SafeArrayGetUBound (pSA, 1, &ubound);

    BSTR* s = NULL;
    SafeArrayAccessData(pSA, (void**) &s);
    wcout << "XXXXXXXXXXXX" << endl;
    for(long i=lbound; i<=ubound; i++)
    {
        wcout << "\t" << s[i] << endl;
    }
    SafeArrayUnaccessData(pSA);
    SafeArrayDestroy (pSA);
}

Read Full Post »

The following code will not compile :-

#include <windows.h>
#include <wabdefs.h>

int main()
{
    return 0;
}

You’ll get a compiler error (C2371) saying that you are redefining WCHAR. The problem is that wabdefs.h defines WCHAR as a typedef for WORD, while winnt.h defines WCHAR as a typedef for wchar_t. In VC++ 2005, /Zc:wchar_t is on by default, which means that wchar_t is a totally different type from unsigned short, as older compilers would expect it to be. This is a definition clash and the bug is in winnt.h, and it’s amazing that the PSDK team didn’t pick this one. If you are an app developer, you can modify your local copy of winnt.h, but if you are a developer who works on a source code library, you are going to have some angry clients when you tell them that they need to edit their winnt.h to get the library to compile. This bug is a total pain in the ass and until the PSDK team fixes winnt.h, there’s no real workaround :grrr:

Read Full Post »

After a long gap, I’ve written another article for The Code Project.

The article is a simple introduction to using the CWinFormsControl MFC class to put a Windows Forms control on an MFC dialog.

Read Full Post »

Every day, every single day, somebody asks on the Microsoft NGs and the Code Project forums whether she can use VC++ 2005 to write native applications that do not use the .NET Framework. It’s amazing how the confusing naming used by the previous versions, where VC++ 2002 was called VC++.NET 7 and VC++ 2003 was called VC++.NET 7.1, had a telling effect on the minds of people.

Anyway, to anyone who’s still in doubt, the answer is, yes, you can write purely native applications with VC++ 2005, and those can be Win32 API applications, MFC/ATL applications, WTL applications and just about anything native really. The Express edition does not include MFC and ATL, which means that you are restricted to creating Win32 API-only applications (other than the managed project options which you are not interested in).

I think the marketing folks at Redmond who work on marketing VC++ 2005 need to start a serious campaign in trying to put the message out that VC++ can create native applications and is not a .NET only tool like C# or VB.NET. Too much stress is put on portraying VC++ as a mixed-mode programming engine, that the fact that it can still be used as a native coding environment is often overlooked. Oh well, maybe they intended it that way. :hmmm:

Read Full Post »

When you compile with /clr and you have a native class in your code (one that’s neither a ref class nor a value class), there are two entry points generated for its methods – a managed entry point and a native entry point. This allows both managed and native callers to call these methods, and the native entry point acts as a thunk to the managed entry point. Virtual functions are always called through the native entry point. Now, this results in a performance issue; when a managed caller calls a virtual function in a /clr compiled native class, there are two managed-unmanaged transitions that are required – the first managed-to-native transition to invoke the native entry point and the second native-to-managed transition to invoke the managed entry point – this is referred to as double thunking.

class N
{
public:
    N()
    {
        Console::WriteLine(__FUNCSIG__);
    }
    N(const N&)
    {
        Console::WriteLine(__FUNCSIG__);
    }
    ~N()
    {
        Console::WriteLine(__FUNCSIG__);
    }
};

class X
{
public:
    virtual void UseNVirt(N)
    {
        Console::WriteLine(__FUNCSIG__);
    }

Now, if you call UseNVirt as follows, you can see the effect of double thunking :-

    X* x = new X();
    Console::WriteLine();

    x->UseNVirt(n);
    Console::WriteLine();

/*** Output

__thiscall N::N(const class N &)
__thiscall N::N(const class N &)
__thiscall N::~N(void)
void __thiscall X::UseNVirt(class N)
__thiscall N::~N(void)

***/

The solution to this is to use __clrcall appropriately :-

class X
{
public:
    virtual void UseNVirt(N)
    {
        Console::WriteLine(__FUNCSIG__);
    }
    virtual void __clrcall UseNVirtClrCall(N)
    {
        Console::WriteLine(__FUNCSIG__);
    }

Now, if you call UseNVirtClrCall as follows, there’s no double thunking involved :-

    X* x = new X();
    Console::WriteLine();

    x->UseNVirtClrCall(n);
    Console::WriteLine();

/*** Output

__thiscall N::N(const class N &)
void __clrcall X::UseNVirtClrCall(class N)
__thiscall N::~N(void)

***/

So, my suggestion to those who are doing mixed mode programming would be to profusely use __clrcall except when you know for certain that the method could be invoked by a native caller. Note that VC++ 2005 does some optimizations on its own and implicitly adds __clrcall to any method with a managed type in its signature (including the return type).

Read Full Post »

Breaking change – OnNcHitTest

Alright, this is a really bad one. This line of code :-

ON_WM_NCHITTEST()

- which was compiling quite okay in VC++ 6 (and VC++ 7.1) suddenly throws this strange error message.

error C2440: 'static_cast' : cannot convert from 'UINT (__thiscall CPocket::* )(CPoint)' to 'LRESULT (__thiscall CWnd::* )(CPoint)'

And it also has a suggestion to fix the error that is even more confusing :-

Cast from base to derived requires dynamic_cast or static_cast

We are already using static_cast, aren’t we?

Guess what? The return type for OnNcHitTest has been changed from UINT to LRESULT (only in the MFC source, the MSDN documentation still says UINT as of Beta 2) to accommodate for negative return values. Crappy part is that this was wizard generated code – we didn’t even write it, damnit! The fix is to change UINT to LRESULT - though if you want to compile the same code for VC++ 6 and 7.1, you’d want to do what I did :-

//In header file

#if _MSC_VER >= 1400
	afx_msg LRESULT OnNcHitTest(CPoint point);
#else
	afx_msg UINT OnNcHitTest(CPoint point);
#endif	
//In cpp file

#if _MSC_VER >= 1400
	LRESULT CPocket::OnNcHitTest(CPoint point)
#else
	UINT CPocket::OnNcHitTest(CPoint point)
#endif
{
#if _MSC_VER >= 1400
	LRESULT nRet=CButton::OnNcHitTest(point);
#else
	UINT nRet=CButton::OnNcHitTest(point);
#endif
//...

Took me a while to figure that one out! It’s not even listed in the Breaking Changes page! :grrr:

Read Full Post »

I’ve run into more issues than I had expected – here’s another one. Pointers to member functions now require a fully qualified name and you also need to use the & operator. It’s not a big deal really, but if your code uses pointers to members in several places, it’s a bit of a task to fix them all. I thought of writing a regular expression so I could do it in one go, but then I reckoned that it’d take me more time to come up with a safe, working regexp than it’d take me to fix all the errors manually.

m_pfnGetPixels = Get8bitPixels; //error C3867

The right way is :-

m_pfnGetPixels = &CBFile::Get8bitPixels;

I wish there was a feature to sort the compiler errors in the Output window by error number. I’ve got 400-500 files in my solution and sometimes, it’s easier for me to work on one compiler error at a time. Say I am fixing the member function pointer issue mentioned above; I’d then be able to fix the issue in all my source files and then recompile to work on the next error. Right now, I have to do a top-to-bottom error fixing and it’s a bit confusing as I am dealing with different types of errors – more strain on the brain :-(

Read Full Post »

Older Posts »

Follow

Get every new post delivered to your Inbox.