Quantcast
Channel: Windows Programming
Viewing all 45 articles
Browse latest View live

Finding Installed Applications with VC++

$
0
0

Finding applications installed on a machine (the ones that you see in Control Panel Add/Remove programs) could be a little bit tricky, because there isn’t a bulletproof API or method. Each of the available methods has its own weak points. WMI is slow and can actually be disabled on a machine. MSI API only shows applications installed with an MSI, and reading directly from the Windows Registry is not an officially supported alternative. Thus it is an open point which one is the most appropriate, though the official answer will probably be MSI API.

In this post I will go through all of these three methods and show how to query for the installed applications and display the name, publisher, vendor and installation location (if available). Notice these are just some samples, and if you want to use this in your applications you’ll probably want to do additional things like better error checking. Because I want the code to work both with ANSI and UNICODE I will use the following defines

#include 
#include 

#ifdef _UNICODE
#define tcout       wcout
#define tstring     wstring
#else
#define tcout       cout
#define tstring     string
#endif

WMI
Win32_Product is a WMI class that represents a product installed by Windows Installer. For fetching the list of installed applications with WMI I will reuse the WMIQuery class I first shown in this post. You need to include Wbemidl.h and link with wbemuuid.lib.

In the code shown below WmiQueryValue() is a function that reads a property from the current record and returns it as an STL string (UNICODE or ANSI). WmiEnum() is a function that fetches and displays in the console all the installed applications.

class WMIQuery
{
   IWbemLocator* m_pLocator;
   IWbemServices* m_pServices;

public:
   WMIQuery():
      m_pLocator(NULL),
      m_pServices(NULL)
   {
   }

   bool Initialize()
   {
      // Obtain the initial locator to WMI
      HRESULT hr = ::CoCreateInstance(
         CLSID_WbemLocator,
         0,
         CLSCTX_INPROC_SERVER,
         IID_IWbemLocator, (LPVOID *) &m_pLocator);

      if (FAILED(hr))
      {
         cerr << "Failed to create IWbemLocator object. Err code = 0x" << hex << hr << endl;
         return false;
      }

      // Connect to WMI through the IWbemLocator::ConnectServer method
      // Connect to the root\cimv2 namespace with the current user
      hr = m_pLocator->ConnectServer(
         _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
         NULL,                    // User name. NULL = current user
         NULL,                    // User password. NULL = current
         0,                       // Locale. NULL indicates current
         NULL,                    // Security flags.
         0,                       // Authority (e.g. Kerberos)
         0,                       // Context object
         &m_pServices             // pointer to IWbemServices proxy
         );

      if (FAILED(hr))
      {
         cerr << "Could not connect. Error code = 0x" << hex << hr << endl;
         m_pLocator->Release();
         m_pLocator = NULL;
         return false;
      }

      // Set security levels on the proxy
      hr = ::CoSetProxyBlanket(
         m_pServices,                 // Indicates the proxy to set
         RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
         RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
         NULL,                        // Server principal name
         RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx
         RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
         NULL,                        // client identity
         EOAC_NONE                    // proxy capabilities
         );

      if (FAILED(hr))
      {
         cerr << "Could not set proxy blanket. Error code = 0x" << hex << hr << endl;
         m_pServices->Release();
         m_pServices = NULL;
         m_pLocator->Release();
         m_pLocator = NULL;
         return false;
      }

      return true;
   }

   IEnumWbemClassObject* Query(LPCTSTR strquery)
   {
      IEnumWbemClassObject* pEnumerator = NULL;
      HRESULT hr = m_pServices->ExecQuery(
         bstr_t("WQL"),
         bstr_t(strquery),
         WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
         NULL,
         &pEnumerator);

      if (FAILED(hr))
      {
         cerr << "Query for operating system name failed. Error code = 0x" << hex << hr < endl;
         return NULL;
      }

      return pEnumerator;
   }

   ~WMIQuery()
   {
      if(m_pServices != NULL)
      {
         m_pServices->Release();
         m_pServices = NULL;
      }

      if(m_pLocator != NULL)
      {
         m_pLocator->Release();
         m_pLocator = NULL;
      }
   }
};

tstring WmiQueryValue(IWbemClassObject* pclsObj,
                      LPCWSTR szName)
{
    tstring value;

    if(pclsObj != NULL && szName != NULL)
    {
        VARIANT vtProp;

        HRESULT hr = pclsObj->Get(szName, 0, &vtProp, 0, 0);
        if(SUCCEEDED(hr))
        {
            if(vtProp.vt == VT_BSTR && ::SysStringLen(vtProp.bstrVal) > 0)
            {
#ifdef _UNICODE
                value = vtProp.bstrVal;
#else
                int len = ::SysStringLen(vtProp.bstrVal)+1;
                if(len > 0)
                {
                    value.resize(len);
                    ::WideCharToMultiByte(CP_ACP, 
                                          0, 
                                          vtProp.bstrVal, 
                                          -1, 
                                          &value[0], 
                                          len, 
                                          NULL, 
                                          NULL);
                }
#endif
            }
        }
    }

    return value;
}

void WmiEnum()
{
    HRESULT hres;

    // Initialize COM.
    hres =  ::CoInitializeEx(0, COINIT_MULTITHREADED);
    if (FAILED(hres))
    {
        cout << "Failed to initialize COM library. Error code = 0x" << hex << hres << endl;
        return;
    }

    // Set general COM security levels
    hres =  ::CoInitializeSecurity(
        NULL,
        -1,                          // COM authentication
        NULL,                        // Authentication services
        NULL,                        // Reserved
        RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication
        RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
        NULL,                        // Authentication info
        EOAC_NONE,                   // Additional capabilities
        NULL                         // Reserved
        );

    if (FAILED(hres))
    {
        cout << "Failed to initialize security. Error code = 0x" << hex << hres << endl;
        ::CoUninitialize();
        return;
    }
    else
    {
        WMIQuery query;
        if(query.Initialize())
        {
            IEnumWbemClassObject* pEnumerator = query.Query(_T("SELECT * FROM Win32_Product"));

            if(pEnumerator != NULL)
            {
                // Get the data from the query
                IWbemClassObject *pclsObj;
                ULONG uReturn = 0;

                while (pEnumerator)
                {
                    HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);

                    if(0 == uReturn)
                    {
                        break;
                    }

                    // find the values of the properties we are interested in
                    tstring name = WmiQueryValue(pclsObj, L"Name");
                    tstring publisher = WmiQueryValue(pclsObj, L"Vendor");
                    tstring version = WmiQueryValue(pclsObj, L"Version");
                    tstring location = WmiQueryValue(pclsObj, L"InstallLocation");

                    if(!name.empty())
                    {
                        tcout << name << endl;
                        tcout << "  - " << publisher << endl;
                        tcout << "  - " << version << endl;
                        tcout << "  - " << location << endl;
                        tcout << endl;
                    }

                    pclsObj->Release();
                }

                pEnumerator->Release();
            }
        }
    }

    // unintializa COM
    ::CoUninitialize();
}

A sample from the output of this WmiEnum() function looks like this:

Java(TM) 6 Update 25
– Oracle
– 6.0.250
– C:\Program Files\Java\jre6\

Java(TM) SE Development Kit 6 Update 25
– Oracle
– 1.6.0.250
– C:\Program Files\Java\jdk1.6.0_25\

Microsoft .NET Framework 4 Client Profile
– Microsoft Corporation
– 4.0.30319
-

Microsoft Sync Framework Services v1.0 SP1 (x86)
– Microsoft Corporation
– 1.0.3010.0
-

Microsoft ASP.NET MVC 2 – Visual Studio 2010 Tools
– Microsoft Corporation
– 2.0.50217.0
-

Adobe Reader X (10.0.1)
– Adobe Systems Incorporated
– 10.0.1
– C:\Program Files\Adobe\Reader 10.0\Reader\

One can notice that the code is relatively long, but most important it is very slow.

MSI API
Two of the MSI API functions can help fetching the list of installed applications:

  • MsiUnumProductsEx: enumerates through one or all the instances of products that are currently advertised or installed (requires Windows Installer 3.0 or newer)
  • MsiGetProductInfoEx: returns product information for advertised and installed products

In order to use these functions you need to include msi.h and link to msi.lib.

In the code below, MsiQueryProperty() is a function that returns the value of product property (as a tstring as defined above) by calling MsiGetProductInfoEx. MsiEnum() is a function that iterates through all the installed applications and prints in the console the name, publisher, version and installation location.

tstring MsiQueryProperty(LPCTSTR szProductCode, 
                         LPCTSTR szUserSid,
                         MSIINSTALLCONTEXT dwContext,
                         LPCTSTR szProperty)
{
    tstring value;

    DWORD cchValue = 0;
    UINT ret2 = ::MsiGetProductInfoEx(
        szProductCode,
        szUserSid,
        dwContext,
        szProperty,
        NULL,
        &cchValue);

    if(ret2 == ERROR_SUCCESS)
    {
        cchValue++;
        value.resize(cchValue);

        ret2 = ::MsiGetProductInfoEx(
            szProductCode,
            szUserSid,
            dwContext,
            szProperty,
            (LPTSTR)&value[0],
            &cchValue);
    }

    return value;
}

void MsiEnum()
{
    UINT ret = 0;
    DWORD dwIndex = 0;
    TCHAR szInstalledProductCode[39] = {0};
    TCHAR szSid[128] = {0};
    DWORD cchSid;
    MSIINSTALLCONTEXT dwInstalledContext;

    do
    {
        memset(szInstalledProductCode, 0, sizeof(szInstalledProductCode));
        cchSid = sizeof(szSid)/sizeof(szSid[0]);

        ret = ::MsiEnumProductsEx(
            NULL,           // all the products in the context
            _T("s-1-1-0"),  // i.e.Everyone, all users in the system
            MSIINSTALLCONTEXT_USERMANAGED | MSIINSTALLCONTEXT_USERUNMANAGED | MSIINSTALLCONTEXT_MACHINE,
            dwIndex,
            szInstalledProductCode,
            &dwInstalledContext,
            szSid,
            &cchSid);

        if(ret == ERROR_SUCCESS)
        {
            tstring name = MsiQueryProperty(
                szInstalledProductCode,
                cchSid == 0 ? NULL : szSid,
                dwInstalledContext,
                INSTALLPROPERTY_INSTALLEDPRODUCTNAME);

            tstring publisher = MsiQueryProperty(
                szInstalledProductCode,
                cchSid == 0 ? NULL : szSid,
                dwInstalledContext,
                INSTALLPROPERTY_PUBLISHER);                

            tstring version = MsiQueryProperty(
                szInstalledProductCode,
                cchSid == 0 ? NULL : szSid,
                dwInstalledContext,
                INSTALLPROPERTY_VERSIONSTRING);

            tstring location = MsiQueryProperty(
                szInstalledProductCode,
                cchSid == 0 ? NULL : szSid,
                dwInstalledContext,
                INSTALLPROPERTY_INSTALLLOCATION);            

            tcout << name << endl;
            tcout << "  - " << publisher << endl;
            tcout << "  - " << version << endl;
            tcout << "  - " << location << endl;
            tcout << endl;

            dwIndex++;
        }

    } while(ret == ERROR_SUCCESS);
}

And this is a sample for the WmiEnum() function.

Java(TM) 6 Update 25
– Oracle
– 6.0.250
– C:\Program Files\Java\jre6\

Java(TM) SE Development Kit 6 Update 25
– Oracle
– 1.6.0.250
– C:\Program Files\Java\jdk1.6.0_25\

Microsoft .NET Framework 4 Client Profile
– Microsoft Corporation
– 4.0.30319
-

Microsoft Sync Framework Services v1.0 SP1 (x86)
– Microsoft Corporation
– 1.0.3010.0
-

Microsoft ASP.NET MVC 2 – Visual Studio 2010 Tools
– Microsoft Corporation
– 2.0.50217.0
-

Adobe Reader X (10.0.1)
– Adobe Systems Incorporated
– 10.0.1
– C:\Program Files\Adobe\Reader 10.0\Reader\

Windows Registry
Installed applications are listed in Windows Registry under HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall. The KB247501 article explains the structure of the information under this Registry key. Make sure you read it if you decide to use this approach.

In the code shown below, RegistryQueryValue() is a function that queries the value of a name/value pair in the registry and returns the value as a tstring. RegistryEnum() is a function that prints to the console all the installed application as found in the registry.

tstring RegistryQueryValue(HKEY hKey,
                           LPCTSTR szName)
{
    tstring value;

    DWORD dwType;
    DWORD dwSize = 0;

    if (::RegQueryValueEx(
        hKey,                   // key handle
        szName,                 // item name
        NULL,                   // reserved
        &dwType,                // type of data stored
        NULL,                   // no data buffer
        &dwSize                 // required buffer size
        ) == ERROR_SUCCESS && dwSize > 0)
    {
        value.resize(dwSize);

        ::RegQueryValueEx(
            hKey,                   // key handle
            szName,                 // item name
            NULL,                   // reserved
            &dwType,                // type of data stored
            (LPBYTE)&value[0],      // data buffer
            &dwSize                 // available buffer size
            );
    }

    return value;
}

void RegistryEnum()
{
    HKEY hKey;
    LONG ret = ::RegOpenKeyEx(
        HKEY_LOCAL_MACHINE,     // local machine hive
        _T("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"), // uninstall key
        0,                      // reserved
        KEY_READ,               // desired access
        &hKey                   // handle to the open key
        );
    
    if(ret != ERROR_SUCCESS)
        return;

    DWORD dwIndex = 0;
    DWORD cbName = 1024;
    TCHAR szSubKeyName[1024];

    while ((ret = ::RegEnumKeyEx(
        hKey, 
        dwIndex, 
        szSubKeyName, 
        &cbName, 
        NULL,
        NULL, 
        NULL, 
        NULL)) != ERROR_NO_MORE_ITEMS)
    {
        if (ret == ERROR_SUCCESS)
        {
            HKEY hItem;
            if (::RegOpenKeyEx(hKey, szSubKeyName, 0, KEY_READ, &hItem) != ERROR_SUCCESS)
                continue;

            tstring name = RegistryQueryValue(hItem, _T("DisplayName"));
            tstring publisher = RegistryQueryValue(hItem, _T("Publisher"));
            tstring version = RegistryQueryValue(hItem, _T("DisplayVersion"));
            tstring location = RegistryQueryValue(hItem, _T("InstallLocation"));

            if(!name.empty())
            {
                tcout << name << endl;
                tcout << "  - " << publisher << endl;
                tcout << "  - " << version << endl;
                tcout << "  - " << location << endl;
                tcout << endl;
            }

            ::RegCloseKey(hItem);
        }
        dwIndex++;
        cbName = 1024;
    }
    ::RegCloseKey(hKey);
}

And a sample output of the RegistryEnum() function:

Java(TM) SE Development Kit 6 Update 25

– Oracle
– 1.6.0.250
– C:\Program Files\Java\jdk1.6.0_25\

Microsoft Visual Studio 2005 Tools for Office Runtime

– Microsoft Corporation
– 8.0.60940.0
-

MSDN Library for Visual Studio 2008 – ENU

– Microsoft
– 9.0.21022
– C:\Program Files\MSDN\MSDN9.0\

Microsoft SQL Server Compact 3.5 SP2 ENU

– Microsoft Corporation
– 3.5.8080.0
– C:\Program Files\Microsoft SQL Server Compact Edition\

Microsoft .NET Framework 4 Client Profile

– Microsoft Corporation
– 4.0.30319
-


C++ Renaissance at Microsoft

$
0
0

At the beginning of this year, Microsoft announced a “C++ renaissance”. Quoting from the description of a Channel 9 video with Craig Symonds and Mohsen Agsen:

C++ is currently undergoing a renaissance. This means that, by definition, the language, compilers and compositional tooling are evolving and coalescing into a state that maximizes native developer efficiency, productivity, and creativity across hardware and software domains.

Everybody agrees that Microsoft made C++ a sort of second class citizen in the past years, while the company invested a lot in the .NET framework. Many developers have switched from native development to managed (.NET) simply because it offers a more productive environment. And the postponing of the ISO standard committee in releasing the new C++0x standard only made things worse.

However, with the completion of the new C++ standard this year, Microsoft, apparently, plans to change that, and make C++ again appealing to developers. They already made C++0x features available in the VS2010 C++ compiler and are working on implementing most of the rest for Visual Studio vNext. They are also investing in tools (now labeled Application Lifecycle Management), and for instance are bringing intellisence to C++/CLI. One of the most important areas of development is parallelism, where they are developing the PPL and Agents libraries and now the C++ AMP that they just announced. And also recently the Kinect for Windows SDK beta that provides Kinect capabilities to developers who build applications with C++ (and other laguanges). And in the mean time they hired Erich Gamma in the Visual Studio team.

But this is not enough in my opinion. Improvements in language and tools are an important part, but not everything. It is equally necessary for Microsoft to evangelize it, using any necessary means. Unless they can spread the word, the work might pass unnoticed. To be honest, I was very reluctant about this part, half an year ago, when they announced the “renaissance”. However, looking back at what they done I’d say they are on the right track. Of course, there is still a lot of work to match the “advertising” effort put into .NET. But right now C++ is getting more attention at conferences such as PDC or TechEd, or their publishing assets, such as Channel 9, MSDN or their team blogs. So I tried to assemble a collection of videos, blogs, books and code samples related to C++ or native development that they published since the announcement of the renaissance. So far it looks good, in my opinion.

Channel 9
E2E: Herb Sutter and Erik Meijer – Perspectives on C++
Craig Symonds and Mohsen Agsen: C++ Renaissance
Windows 7 Taskbar Integration for MFC Applications
Tony Goodhew: VC++ Developer Communication – Questions and Answers
Talkin’ C++ with Kate Gregory
MVP Summit 2011: Meet C++ MVPs Angel, PJ, Tom and Sheng
Talkin’ C++ with Alon, Marius, Bruno, and Jim
Talkin’ C++ with Boris Jabes: C++ Intellisense, Game Development, and Boris Faces His Demons
Application Restart and Recovery on Windows 7 in Native Code
Parallel Programming for C++ Developers: Tasks and Continuations, Part 1 of 2
Parallel Programming for C++ Developers: Tasks and Continuations, Part 2 of 2
Conversation with Herb Sutter: Perspectives on Modern C++(0x/11)
First Look: New ALM Tools for VC++ Developers
Modern Native C++ Development for Maximum Productivity
Mohsen Agsen – C++ Today and Tomorrow
Herb Sutter: C++ Questions and Answers
Herb Sutter – Heterogeneous Computing and C++ AMP
Daniel Moth: Blazing-fast code using GPUs and more, with C++ AMP
C9 Lectures: Stephan T Lavavej – Advanced STL, 1 of n
C9 Lectures: Stephan T Lavavej – Advanced STL, 2 of n
C9 Lectures: Stephan T Lavavej – Advanced STL, 3 of n
C9 Lectures: Stephan T Lavavej – Advanced STL, 4 of n
C9 Lectures: Stephan T Lavavej – Advanced STL, 5 of n

Visual C++ Team Blog
Grr… My VC++ Project Is Building Slower in VS2010. What Do I Do Now? (A Step by Step Guide)
C++/CLI IntelliSense in Visual Studio vNext
Exception Boundaries: Working With Multiple Error Handling Mechanisms
Troubleshooting Tips for IntelliSense Slowness
Build Related Improvement in VS2010 SP1
Converting An MFC Ribbon To Designer Format
Enforcing Correct Concurrent Access of Class Data

Parallel Programming in Native Code Blog
Sorting in PPL
How to pick your parallel sort?
The Concurrency Runtime and Visual C++ 2010: Lambda Expressions
The Concurrency Runtime and Visual C++ 2010: Automatic Type Deduction
The Concurrency Runtime and Visual C++ 2010: The decltype Type Specifier
The Concurrency Runtime and Visual C++ 2010: Rvalue References
The Concurrency Runtime and Visual C++ 2010: Transporting Exceptions between Threads
Building Responsive GUI Applications with PPL Tasks

MSDN Magazine
Writing a Debugging Tools for Windows Extension
Writing a Debugging Tools for Windows Extension, Part 2: Output
Writing a Debugging Tools for Windows Extension, Part 3: Clients and Callbacks
Agile C++ Development and Testing with Visual Studio and TFS

Books & Publications
Parallel Programming with Microsoft Visual C++
The Visual C++ Weekly

Code & Samples
Code samples for the Concurrency Runtime and Parallel Pattern Library in Visual Studio 2010
Bing Maps Trip Optimizer
Hilo: Developing C++ Applications for Windows 7
All-in-One Code Framework

Windows Runtime

$
0
0

Windows Runtime, or shortly WinRT, is a new runtime (siting on top of the Windows kernel) that allows developers to write Metro style applications for Windows 8, using a variety of languages including C/C++, C#, VB.NET or JavaScript/HTML5. Microsoft has started rolling out information about Windows 8 and the new runtime at BUILD.

(source www.zdnet.com)

WinRT is a native layer (written in C++ and being COM-based) that is intended as a replacement, or alternative, to Win32, and enables development of “immersive” applications, using the Metro style. Its API is object oriented and can be consumed both from native or managed languages, as well as JavaScript. At the same time the old Win32 applications will continue to run just as before and you can still (and most certainly will) develop Win32 applications.

Microsoft has created a new language called C++ Component Extension, or simply C++/CX. While the syntax is very similar to C++/CLI, the language is not managed, it’s still native. WinRT components built in C++/CX do not compile to managed code, but to 100% native code. A good news for C++ developers is that they can use XAML now to build the UI for immersive applications. However, this is not available for classical, Win32 applications.

You can get a glimpse of the new system and the tools by downloading and installing the Windows Developer Preview with tools, that includes the following:

  • 64-bit Windows Developer Preview
  • Windows SDK for Metro style apps
  • Microsoft Visual Studio 11 Express for Windows Developer Preview
  • Microsoft Expression Blend 5 Developer Preview
  • 28 Metro style apps including the BUILD Conference app

Notice this is a pre-beta release and you might encounter various problems.

Before you start here are several additional articles that you might want to read:

There are also several new forums available on MSDN forums for developing Metro style applications, which you can use for addressing technical questions. Hopefully thee will be answers from Microsoft people working in this area.

C++, WinRT and Partial Classes

$
0
0

Partial classes are finally available to C++. Sort of. It’s not part of the new C++11 standard, it’s part of the C++/CX language developed by Microsoft for targeting WinRT on Windows 8.

Partial classes mean that you can define a class spanned across several files. Why is this great? Because it allows developers and automatic code generator tools (such as designers) to edit parts of the same class without interfering one with another. WinRT allows C++ developers to write UI in XAML. This could not have been possible without the support for partial classes.

Partial classes:

  • are available only for ref classes; native classes are not supported
  • are introduced with the partial keyword in all definitions but one

Here is an example:

// foo.private.h
#pragma once

partial ref class foo // <- here the partial keyword is used
{
private:
   int _id;
   Platform::String^ _name;
};
// foo.public.h
#pragma once
#include "foo.private.h"

ref class foo // <- partial keyword is not used here
{
public:
   int GetId();
   Platform::String^ GetName();
};
// foo.cpp
#include "pch.h"
#include "foo.public.h"

int foo::GetId() {return _id;}
Platform::String^ foo::GetName {return _name;}

What happens when you add a new page to a C++ Metro style application? The wizard generates three files: a XAML file and a header and cpp file as the code behind. Let's say the page is called MainPage. In this case the three files are MainPage.xaml (code below is a dummy example), MainPage.xaml.h and MainPage.xaml.cpp.

<UserControl x:Class="DemoApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="768" d:DesignWidth="1366">

    <StackPanel Name="firstPanel">
        <Button Name="firstButon" />
    </StackPanel>
    
</UserControl>
//
// MainPage.xaml.h
// Declaration of the MainPage.xaml class.
//

#pragma once

#include "pch.h"
#include "MainPage.g.h"

namespace DemoApp
{
   public ref class MainPage
   {
      public:
         MainPage();
         ~MainPage();
   };
}
//
// MainPage.xaml.cpp
// Implementation of the MainPage.xaml class.
//

#include "pch.h"
#include "MainPage.xaml.h"

using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Data;
using namespace DemoApp;

MainPage::MainPage()
{
   InitializeComponent();
}

MainPage::~MainPage()
{
}

You can notice that the objects firstPanel and firstButton are not defined in the header for MainPage and second, MainPage.xaml.h includes MainPage.g.h. So what is this? This is a designer generated file, which together with MainPage.g.cpp completes the definition of the MainPage ref class. These files are not generated until you start a build. After you do that you can find them in the output folder (Debug or Release for instance). This is how they look:

#pragma once
//------------------------------------------------------------------------------
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
//------------------------------------------------------------------------------

namespace Windows {
    namespace UI {
        namespace Xaml {
            namespace Controls {
                ref class StackPanel;
                ref class Button;
            }
        }
    }
}

namespace DemoApp
{
    partial ref class MainPage : public Windows::UI::Xaml::Controls::UserControl, 
                                                     public Windows::UI::Xaml::Markup::IComponentConnector
    {
    public:
        void InitializeComponent();
        void Connect(int connectionId, Platform::Object^ pTarget);

    private:
        Windows::UI::Xaml::Controls::StackPanel^ firstPanel;
        Windows::UI::Xaml::Controls::Button^ firstButon;
    };
}
//------------------------------------------------------------------------------
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
//------------------------------------------------------------------------------
#include "pch.h"

#include "MainPage.xaml.h"


using namespace Windows::Foundation;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Markup;
using namespace MyDemoApplication1;

void MainPage::InitializeComponent()
{
    // Call LoadComponent on ms-resource://DemoApp/Files/MainPage.xaml
    Windows::UI::Xaml::Application::LoadComponent(this, ref new Windows::Foundation::Uri("ms-resource://DemoApp/Files/MainPage.xaml"));

    // Get the StackPanel named 'firstPanel'
    firstPanel = safe_cast<Windows::UI::Xaml::Controls::StackPanel^>(static_cast<IFrameworkElement^>(this)->FindName("firstPanel"));

    // Get the Button named 'firstButon'
    firstButon = safe_cast<Windows::UI::Xaml::Controls::Button^>(static_cast<IFrameworkElement^>(this)->FindName("firstButon"));

}

void MainPage::Connect(int connectionId, Platform::Object^ pTarget)
{
}

The following image illustrates the grouping of these files:

MainPage.xaml is a XAML files, which can be edited both by the designer or manually by the developer (basically with the designer is still the developer that models the UI). The other files are C++/CX files. MainPage.xaml.h and MainPage.xaml.cpp are the files the developer writes, while MainPage.g.h and MainPage.g.cpp are edited by the designer. Do not modify the code in these files, because you could either mess up the designer, or all your changes would get lost when the file is regenerated.

WinRT and winmd Files

$
0
0

If you tried the Win8 Developer Preview and built WinRT components (native or managed) you noticed the .winmd files. The name stands for Windows Meta Data and the format of these files is the same used by the .NET framework for the CLI, i.e. ECMA-335. That means you can actually read these files with a tool such as ILDASM or Reflector, or of course, through .NET Reflection.

If you look in C:\Windows\System32\WinMetadata folder you’ll find the WinMD files for the Windows Runtime. You can browse the content of these files with one of the aforementioned disassemblers.

Here are two dummy WinRT components, one developed in C++/CX and one in C#.

Native WinRT component in C++/CX Managed WinRT component in C#
namespace WinRTNativeComponent
{
    public ref class MyWinRTComponent sealed
    {
        int _id;
		String^ _name;

    public:
		MyWinRTComponent () {}
		~MyWinRTComponent () {}

        property int Id
        {
            int get() { return _id; }
            void set(int value) { _id = value; }
        }

		property String^ Name
		{
			String^ get() {return _name;}
			void set(String^ value) { _name= value; }
		}

        bool Update(int id, String^ name)
		{
			{
				if(_id == id)
				{
					_name = name;
					return true;
				}

				return false;
			}
		}
    };
}
namespace WinRTManagedComponent
{
    public sealed class MyWinRTComponent
    {
        public int Id { get; set; }
        public string Name { get; set; }

        bool Update(int id, string name)
        {
            if (Id == id)
            {
                Name = name;
                return true;
            }

            return false;
        }
    }
}

In the case of the native component, the output includes a DLL and a WINMD file (and of course a PDB file). In the case of the managed component, the output is either a DLL only or a WINMD only (plus the associated PDB file), depending on the Output type as defined in the project properties. If the type is Class Library the output is a DLL; this is enough if your component is supposed to be consumed from a managed language. However, if the component should be consumed from C++/CX or Javascript, then the project type must be set to WinMD File. In this case the DLL is replaced by a WinMD file, that contains, at least in the current version, both the matadata (as implied by the name) and the implementation.

Native WinRT component in C++/CX Managed WinRT component in C#

It should be possible to use reflection with winmd files. However, the reflection capabilities of .NET 4.5 in this developer preview seem to be very limited. The only available Load method in the Assembly class is

public static Assembly Load(AssemblyName assemblyRef);

Trying to load the winmd file fails with a FailLoadException with the message “Could not load file or assembly ‘Winmdreflection, ContentType=WindowsRuntime’ or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0×80131515)”.

try
{
    var assembly = Assembly.Load(
        new AssemblyName()
        {
            Name = "WinRTManagedComponent",
            ContentType = AssemblyContentType.WindowsRuntime
        });
}
catch (Exception ex)
{                
}

It is possible though to read information for the types described in an winmd file in native code using the IMetaDataImport/IMetaDataImport2 COM interfaces. You can find an example here. But this has the drawback that you have to instantiate an object first and then query for its type information.

To use a Windows Runtime component in a Metro application (managed or native) you have to add a reference to it. That is pretty straight forward. In the following example I’m adding a reference in a C++ Metro application to the two WinRT components, one native and one managed, shown earlier. To do this, you can go to the project’s property page and open the Common Properties > Frameworks and References page, or use the References command from the project’s context menu which opens that page directly. You can add a reference to a project from the same solution, to a Windows component or you can browse for the winmd file.

Having done that you can instantiate the WinRT components.

auto obj1 = ref new WinRTManagedComponent::MyWinRTComponent();
obj1->Id = 1;
obj1->Name = L"marius";

auto obj2 = ref new WinRTNativeComponent::MyWinRTComponent();
obj2->Id = 1;
obj2->Name = L"marius";

Things I like about native development with C++/CX

$
0
0

Visual Studio 11 brings many new things for native development, including support for new features from C++11 (unfortunately not all), or ability to write Metro apps with C++/CX including modeling the UI with XAML. In this post I will talk a bit about three favorite features that I noticed immediately after trying VS11 from Windows 8 Developer Preview.

Use of namespaces
Finally, I see namespaces promoted in native code. Yes, it’s C++/CX and they were probably forced to use namespaces for a consistent experience from the various languages that target the Windows Runtime, but it’s a very nice change to the default templates for C++ projects where everything is put in the global namespace. I can only hope they will improve that in this version or the next for standard C++ applications (whether Win32 console apps or MFC apps).

namespace Sample
{
    public ref class MainPage
    {
        public:
            MainPage();
            ~MainPage();
    };
}

UPDATE: looks like I wasn’t clear enough, I’m not saying namespaces is a new C++ feature (duh), I’m saying Visual Studio templates for C++ don’t promote that. Create a Win32 project, an MFC project, and ATL project, there are no namespaces. You’d have to code everything manually, but if you do it, you mess the wizards. So, what I’m saying is that I hope we can see namespaces promoted for other project and item templates too.

Partial classes
I already wrote about partial classes, but I want to reiterate this feature. Partial classes gives you the ability to define a class in several files. This is great because developers and code generator tools such as designers can edit different parts of the same class without interfering one with the other. This feature made it possible for supporting XAML user interfaces in C++/CX Metro applications.

I’m actually wondering why isn’t this already part of standard C++ and I can only wish that the next version (which hopefully will not take another decade to conclude) will include this feature.

Better Syntax Highlighting
Below is a comparison for the same piece of code highlighted by Visual Studio 2010 on the left, and Visual Studio.vNext (11) on the right.

There is hardly any formatting in VS10. However, on the other hand, the highlighting in VS11 is beautiful. User defined types (including library types) are displayed with another color than the built-in types (such as int), including in their definition. STL types (string, vector, etc.) are finally identified as types and displayed with the appropriate color. Also the name of parameters is displayed in italics which makes them easily identifiable. There are other things about the highlighting, but these striking changes.

A tale of two flags: DS_CONTROL and WS_EX_CONTROLPARENT

$
0
0

I recently ran into problems with an MFC application that was hosting some Windows Form user control in a modal dialog; the application hanged after it lost focus. The problem was the window received WM_GETDLGCODE message in an infinite loop making it impossible to handle anything else. After a lot of digging, I found that the cause was the missing WS_EX_CONTROLPARENT style of the window that hosted the WinForms control. What I want to do is summarizing the information about this Window style. The most information I’ve been able to pull came from Raymond Chen’s blog The Old New Thing.

First of all, there are two styles: DS_CONTROL and WS_EX_CONTROLPARENT.

WS_EX_CONTROLPARENT

The window itself contains child windows that should take part in dialog box navigation. If this style is specified, the dialog manager recurses into children of this window when performing navigation operations such as handling the TAB key, an arrow key, or a keyboard mnemonic.

WS_EX_CONTROLPARENT is a extended window style. It tells the dialog manager that it should treat the children of the window with this flag as direct children of the window’s parent (got that?). Raymond has a simple figure in this blog post When embedding a dialog inside another, make sure you don’t accidentally create duplicate control IDs.

DS_CONTROL

Creates a dialog box that works well as a child window of another dialog box, much like a page in a property sheet. This style allows the user to tab among the control windows of a child dialog box, use its accelerator keys, and so on.

DS_CONTROL is a style for dialog templates. The dialog manager translates this style into window styles and extended window styles. It removes WS_CAPTION and WS_SYSMENU (if existing) and adds WS_EX_CONTROLPARENT.

Bottom line is, the WS_EX_CONTROLPARENT style tells function that do control searches (such as GetNextDlgTabItem) that they should treat the dialog marked with the flag as a container of other controls (and iterate them) and not a single, big, control.

More readings:
What is the DS_CONTROL style for?
The dialog manager, part 2: Creating the frame window
Why doesn’t the TAB key work on controls I’ve marked as WS_TABSTOP?
Why do we need IsDialogMessage at all?

And references to similar problems as my own:
endless messages WM_GETDLGCODE when focus is lost
WS_EX_CONTROLPARENT

Keyboard input and TAB navigation between WPF controls in a Win32 application

$
0
0

It is possible to host WPF controls in a Win32 application, and the other way around, but because of the differences betweeb these technologies there are various issues that can appear. One of these is handling of keyboard input. Without diving too much into differences between WPF and Win32, I will show how to provide keyboard input for WPF controls hosted in a Win32 applications. For reading about the differences and the interoping between the two I suggest WPF and Win32 Interoperation.

Hosting a WPF Control in Win32

To host a WPF control in a Win32 application you need to follow several steps.

  • Create a new HwndSource, setting the parent window as it’s parent. This is a key object, that enables displaying of WPF content in a Win32 window.
  • Instantiate the WPF control or window
  • Assign the reference to this instance of the WPF control or window RootVisual property of the HwndSource object.

To simplify this process, I have this small helper class:

#pragma once

#include <vcclr.h>

class CWpfControlWrapper
{
   HWND m_hwndWPF;
   gcroot<System::Windows::Interop::HwndSource^> m_source;
   gcroot<System::Windows::Controls::Control^> m_control;

public:
   CWpfControlWrapper(void):m_hwndWPF(NULL) {}
   ~CWpfControlWrapper(void) {}

   template <typename T>
   T^ Control()
   {
      System::Windows::Controls::Control^ obj = m_control;
      return dynamic_cast<T^>(obj);
   }

   BOOL CreateControl(System::Type^ type, 
                      HWND parent, 
                      DWORD style, 
                      int x, int y, 
                      int width, int height)
   {
      System::Windows::Interop::HwndSourceParameters^ sourceParams = 
         gcnew System::Windows::Interop::HwndSourceParameters("WpfControlWrapper");

      sourceParams->PositionX = x;
      sourceParams->PositionY = y;
      sourceParams->Height = height;
      sourceParams->Width = width;
      sourceParams->ParentWindow = System::IntPtr(parent);
      sourceParams->WindowStyle = style;
      m_source = gcnew System::Windows::Interop::HwndSource(*sourceParams);

      m_control = (System::Windows::Controls::Control^)System::Activator::CreateInstance(type);
      m_source->RootVisual = m_control;

      m_hwndWPF = (HWND)m_source->Handle.ToPointer();      

      return m_hwndWPF == NULL ? FALSE : TRUE;
   }
};

With this class I can create WPF controls like this:

CWpfControlWrapper btn1;
btn1.CreateControl(System::Windows::Controls::Button::typeid, 
                   m_hWnd, 
                   WS_CHILD|WS_VISIBLE|WS_TABSTOP, 
                   10, 10, 210, 24);
btn1.Control<System::Windows::Controls::Button>()->Content = "Button 1";

Enabling Keyboard Input

While you can use the mouse with these WPF controls added like this, the keyboard in not enabled. To provide keyboard input for the WPF controls, we need to hook the HwndSource, adding a handler that receives all window messages. We must handle the WM_GETDLGCODE message to let the system know what kind of messages we want to handle on our own (in the WPF control).

This is how we add the hook:

m_source->AddHook(gcnew System::Windows::Interop::HwndSourceHook(
                  &CWpfControlWrapper::ChildHwndSourceHook));

And this is how the hook procedure looks (defined as a static member of my CWpfControlWrapper):

static System::IntPtr ChildHwndSourceHook(
  System::IntPtr hwnd, 
  int msg, 
  System::IntPtr wParam, 
  System::IntPtr lParam, 
  bool% handled)
{
  if (msg == WM_GETDLGCODE)
  {
     handled = true;
     return System::IntPtr(DLGC_WANTCHARS | DLGC_WANTTAB | DLGC_WANTARROWS | DLGC_WANTALLKEYS);
  }

  return System::IntPtr::Zero;
}

By returning all these dialog codes will let the system know that the window wants to process arrow keys, tab keys, all keys and receive the WM_CHAR message.

Enabling TAB Navigation

Even though the WPF controls now have keyboard input, it turns our that navigating with TAB (forward) or TAB+SHIFT (backwards) does not work.

Here is an example where I have an MFC application with four WPF controls, two buttons and two text boxes. One button and one text box, as well as the OK and CANCEL buttons have tab stops.

CWpfControlWrapper btn1;
btn1.CreateControl(System::Windows::Controls::Button::typeid, 
                  m_hWnd, 
                  WS_CHILD|WS_VISIBLE|WS_TABSTOP, 
                  10, 10, 210, 24);
btn1.Control<System::Windows::Controls::Button>()->Content = "Button 1 (tab stop)";

CWpfControlWrapper btn2;
btn2.CreateControl(System::Windows::Controls::Button::typeid, 
                  m_hWnd, 
                  WS_CHILD|WS_VISIBLE, 
                  10, 40, 210, 24);
btn2.Control<System::Windows::Controls::Button>()->Content = "Button 2 (no tab stop)";

CWpfControlWrapper edit1;
edit1.CreateControl(System::Windows::Controls::TextBox::typeid, 
                   m_hWnd, 
                   WS_CHILD|WS_VISIBLE|WS_TABSTOP, 
                   10, 70, 210, 24);
edit1.Control<System::Windows::Controls::TextBox>()->Text = "edit 1 (tab stop)";

CWpfControlWrapper edit2;
edit2.CreateControl(System::Windows::Controls::TextBox::typeid, 
                   m_hWnd, 
                   WS_CHILD|WS_VISIBLE, 
                   10, 100, 210, 24);
edit2.Control<System::Windows::Controls::TextBox>()->Text = "edit 2 (no tab stop)";

The sample dialog box looks like this:

Pressing the TAB key should allow navigating from button 1 to edit 1, then button OK, button CANCEL and then back to button 1. Button 2 and edit 2, not having the tab stop style defined, should not be included in the navigation.

As already mentioned, this does not work, however. After reading about a solution for this problem, it looked like the key lied in the IKeyboardInputSink interface, that both HwndSource and HwndHost implement. This interface provides a keyboard sink for components that manage tabbing, accelerators, and mnemonics across interop boundaries and between HWNDs. Apparently the solution was to:

  • derive the HwndSource class
  • override the TabInto method (actually, since this is a sealed method you’d have to define a new override for it) and implement there the tabbing logic
  • use this derived HwndSource to present WPF content in a Win32 window

Though I tried several things I didn’t manage to make it work. However, since I already had a hook for all window messages, and explicitly asked for receiving WM_CHAR, it was possible to use this to handle TAB and TAB+SHIFT. So here is an addition to the ChildHwndSourceHook above:

else if(msg == WM_CHAR)
{
   if(wParam.ToInt32() == VK_TAB)
   {
      handled = true;
      HWND nextTabStop = FindNextTabStop((HWND)hwnd.ToPointer(), 
                                         (GetKeyState(VK_SHIFT) & 0x8000) != 0x8000);
      if(nextTabStop)
         ::SetFocus(nextTabStop);
   }
}

So if we get a WM_CHAR and the wParam is VK_TAB, then we query the parent for the next tab stop (for forward navigation if SHIFT was not pressed, or backwards navigation if SHIFT was also pressed). If there is such a tab stop we set focus on that window.

The FindNextTabStop method (added as a member of the CWpfControlWrapper class) looks like this:

static HWND FindNextTabStop(HWND wnd, bool forward)
{
  HWND nextstop = NULL;
  HWND nextwnd = wnd;
  do
  {
     // get the next/previous window in the z-order
     nextwnd = ::GetWindow(nextwnd, forward ? GW_HWNDNEXT : GW_HWNDPREV);

     // if we are at the end of the z-order, start from the top/bottom
     if(nextwnd == NULL) 
        nextwnd = ::GetWindow(wnd, forward ? GW_HWNDFIRST : GW_HWNDLAST);

     // if we returned to the same control then we iterated the entire z-order
     if(nextwnd == wnd)
        break;

     // get the window style and check the WS_TABSTOP style
     DWORD style = ::GetWindowLongPtr(nextwnd, GWL_STYLE);
     if((style & WS_TABSTOP) == WS_TABSTOP)
        nextstop = nextwnd;
  }while(nextstop == NULL);
  
  return nextstop;
}

It does the following:

  • it gets the next/previous window in the z-order (which defines the tab stop order)
  • when it reaches the end/top of the z-order, it starts all over again, which enables looping through the child windows of the parent
  • if the next child the in z-order is the current control, then it finished looping through the children of the parent and it stops
  • if the current child in the z-order has the WS_TABSTOP style set, then this is the window we are looking for

With this defined, it is possible to use the TAB key to navigate between the WPF controls on a Win32 window.

Here is the MFC demo application that you can try: Mfc-Wpf Tabbing (224).


error C3510: cannot locate dependent type library ” {bed7f4ea-1a96-11d2-8f08-00a0c9a6186d} v.2.4

$
0
0

Problem

I have recently migrated a C# 2.0 project registered for COM interop to .NET 4.5 and when I imported the type library in a C++ project with no_registry, suddenly I got some errors because the type library could not be imported. Here are the steps to reproduce:

  • create a .NET Class Library project and set platform target to .NET framework 4.5
  • check Register for COM interop
  • build the project
  • import the type library in a C++ project:
    #import "DemoClassLibrary.tlb" no_dual_interfaces no_registry
    

The result is the following error:

1>[...]: error C3510: cannot locate dependent type library '' {bed7f4ea-1a96-11d2-8f08-00a0c9a6186d} v.2.4
1>[...]: fatal error C1083: Cannot open type library file: '[...]\democlasslibrary.tlb': Error loading type library/DLL.

Solution

Searching for the solution I found that this was a known issue when you have both CLR 2.0 and 4.0 installed on the same machine. See this KB article: VC++ 2010 #import with no_registry fails with error C1083 or C3510. Unfortunately I was unable to fix the problem with the solution indicated there.

There are two tools that can generate a type library from an assembly:

  • tlbexp.exe: generates a type library from a specified .NET assembly
  • regasm.exe: registers metadata from an assembly to the Windows Registry, but in addition can create a type library from for the input assembly when /tlb switch is used.

When a project specifies to register for COM interop what Visual Studio does is similar to calling regasm.exe with /codebase switch specified. Since I had before problems with interop assemblies automatically generated by Visual Studio (with tlbimp.exe) I though it would be the same (only the other way around). Therefore I unchecked “register for COM interop” and added as a custom build step registration with regasm.exe, like this:

c:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe DemoClassLibrary.dll /tlb:DemoClassLibrary.tlb

Not very surprisingly, the generated file was different and the #import command executed without problems.

Problem solved!

Cause

The question that arises is why are the two files, generated with Visual Studio and with regasm.exe, different? You can see they are different if you open them in an hex editor. But if you just use oleview.exe, the disassembled type library looks identical.

The obvious answer that occurred to me, but eventually proved wrong, was that Visual Studio is not actually using regasm.exe to register the assembly and generate the type library. It actually uses a MSBuild task for that.

When the RegisterForComInterop property is set in a .csproj an MSBuild task is executed.

1>Using "RegisterAssembly" task from assembly "Microsoft.Build.Tasks.v4.0, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
1>Task "RegisterAssembly" (TaskId:32)
1>  Task Parameter:Assemblies=[...]\DemoClassLibrary.dll (TaskId:32)
1>  Task Parameter:TypeLibFiles=[...]\DemoClassLibrary.tlb (TaskId:32)
1>  Task Parameter:AssemblyListFile=obj\DemoClassLibrary.csproj.UnmanagedRegistration.cache (TaskId:32)
1>  Task Parameter:CreateCodeBase=True (TaskId:32)
1>  Registering assembly "[...]\DemoClassLibrary.dll" for COM Interop. (TaskId:32)
1>  Exporting and registering type library "[...]\DemoClassLibrary.tlb". (TaskId:32)
1>  Type 'P' exported. (TaskId:32)
1>  Type 'P' exported. (TaskId:32)
1>Done executing task "RegisterAssembly". (TaskId:32)

The task can be found in Microsoft.Common.targets (in c:\Windows\Microsoft.NET\Framework\v4.0.30319\)

  <!--
    ============================================================
                                        UnmanagedRegistration

    Registers the main assembly for COM interop.
    ============================================================
    -->
  <PropertyGroup>
    <UnmanagedRegistrationDependsOn></UnmanagedRegistrationDependsOn>
  </PropertyGroup>
  <Target
      Name="UnmanagedRegistration"
      Condition="'$(RegisterForComInterop)'=='true' and '$(OutputType)'=='library'"
      DependsOnTargets="$(UnmanagedRegistrationDependsOn)"
        >

    <PropertyGroup>
      <RegisterAssemblyMSBuildArchitecture Condition="'$(RegisterAssemblyMSBuildArchitecture)' == ''">$(PlatformTargetAsMSBuildArchitecture)</RegisterAssemblyMSBuildArchitecture>
    </PropertyGroup>

    <PropertyGroup Condition="'$(TargetFrameworkAsMSBuildRuntime)' != '' and '$(RegisterAssemblyMSBuildArchitecture)' != ''">
      <!-- Falling back to the current runtime if we are targeting CLR2 and the task host doesn't exist will lead to 
           incorrect behavior in some cases, but it's the same incorrect behavior as Visual Studio 2010, and thus better
           than causing build breaks on upgrade to Win8 the way not doing so would.  For more details, see the 
           corresponding comment in GenerateResource. -->
      <RegisterAssemblyMSBuildRuntime 
          Condition="'$(RegisterAssemblyMSBuildRuntime)' == '' and 
                     $([MSBuild]::DoesTaskHostExist(`$(TargetFrameworkAsMSBuildRuntime)`, `$(RegisterAssemblyMSBuildArchitecture)`))">$(TargetFrameworkAsMSBuildRuntime)</RegisterAssemblyMSBuildRuntime>

      <!-- If the targeted runtime doesn't exist, fall back to current -->
      <RegisterAssemblyMSBuildRuntime Condition="'$(RegisterAssemblyMSBuildRuntime)' == ''">CurrentRuntime</RegisterAssemblyMSBuildRuntime>
    </PropertyGroup>

    <RegisterAssembly
        Assemblies="@(_OutputPathItem->'%(FullPath)$(TargetFileName)')"
        TypeLibFiles="@(_OutputPathItem->'%(FullPath)$(TargetName).tlb')"
        AssemblyListFile="@(_UnmanagedRegistrationCache)"
        CreateCodeBase="true"
        MSBuildRuntime="$(RegisterAssemblyMSBuildRuntime)"
        MSBuildArchitecture="$(RegisterAssemblyMSBuildArchitecture)"
        Condition="!Exists('@(_UnmanagedRegistrationCache)')"/>

    <ItemGroup>
      <FileWrites Include="@(_OutputPathItem->'%(FullPath)$(TargetName).tlb')"/>
    </ItemGroup>
  </Target>

To check if I can reproduce, I have created MSBuild file (explicitreg.xml) with some hard-coded values that only runs that registration task.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="UnmanagedRegistration" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <UnmanagedRegistrationDependsOn></UnmanagedRegistrationDependsOn>
  </PropertyGroup>
  <Target
      Name="UnmanagedRegistration"
      DependsOnTargets="$(UnmanagedRegistrationDependsOn)"
        >

    <PropertyGroup>
      <RegisterAssemblyMSBuildArchitecture Condition="'$(RegisterAssemblyMSBuildArchitecture)' == ''">$(PlatformTargetAsMSBuildArchitecture)</RegisterAssemblyMSBuildArchitecture>
    </PropertyGroup>

    <PropertyGroup Condition="'$(TargetFrameworkAsMSBuildRuntime)' != '' and '$(RegisterAssemblyMSBuildArchitecture)' != ''">
      <RegisterAssemblyMSBuildRuntime 
          Condition="'$(RegisterAssemblyMSBuildRuntime)' == '' and 
                     $([MSBuild]::DoesTaskHostExist(`$(TargetFrameworkAsMSBuildRuntime)`, `$(RegisterAssemblyMSBuildArchitecture)`))">$(TargetFrameworkAsMSBuildRuntime)</RegisterAssemblyMSBuildRuntime>

      <!-- If the targeted runtime doesn't exist, fall back to current -->
      <RegisterAssemblyMSBuildRuntime Condition="'$(RegisterAssemblyMSBuildRuntime)' == ''">CurrentRuntime</RegisterAssemblyMSBuildRuntime>
    </PropertyGroup>

    <RegisterAssembly
        Assemblies="bin\Debug\DemoClassLibrary.dll"
        TypeLibFiles="bin\Debug\DemoClassLibrary.tlb"
        AssemblyListFile="obj\DemoClassLibrary.csproj.UnmanagedRegistration.cache"
        CreateCodeBase="true" />

    <ItemGroup>
      <FileWrites Include="bin\Debug\DemoClassLibrary.tlb"/>
    </ItemGroup>
  </Target>
</Project>
c:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe explicitreg.xml

But surprise: this produced the exact same output as the regasm.exe command. Comparing the diagnose logs from MSBuild (for the build of the .csproj and my custom file) I couldn’t spot any difference in the execution of the task. Also using the Process Monitor (procmon.exe from Sysinternals) to check access to the TLB file, I could clearly see the difference for the file writing, because different lengths were produced from Visual Studio build and explicit MSBuild run, though again I could not see any difference in the call stacks.

So, the actual cause for this behavior is still unknown to me and I would appreciate if anyone that knows the answer clarifies it.

Bindings for DataGridView hosted in an MFC application

$
0
0

A WinForms DataGridView control has the ability to automatically generate its columns and populate from a specified data source (which can be a DataSet, a simple list or something else). All you have to do is something like this:

var list = new List<Record>() {new Record() {Id = 1, Name = "item 1", Date = DateTime.Now}};

this.dataGridView.AutoGenerateColumns = true;
this.dataGridView.DataSource = list;

When you do the same in MFC, it doesn’t work (supposing that you followed all the steps for hosting a WinForms control in an MFC application as described in MSDN).

m_dgv->AutoGenerateColumns = true;
auto source = gcnew System::Collections::Generic::List<Record^>();
auto r1 = gcnew Record();
r1->Id = 1;
r1->Name = "item 1";
r1->Date = System::DateTime::Now;
source->Add(r1);

m_dgv->DataSource = source;

dgv1

After debugging through the .NET framework sources I realized the problem was that the BindingContext property of the DataGridView control was null. This property represents a manager of the list of bindings for the control. If this is null then the control will use the binding context of the parent, which is usually a WinForms form. However, in this MFC application there is no WinForms form and the parent of the DataGridView control is null, which means the control does not have a bindings manager, and no bindings can be set.

The solution is to explicitly set the BindingsContext property to an existing binding context (a new object) before setting the data source.

m_dgv->BindingContext = gcnew System::Windows::Forms::BindingContext();
m_dgv->DataSource = source;

dgv2

The lesson learned is that when you host a WinForms control in an MFC application some things won’t just work out of the box, if they rely on a parent form functionality. There is no such WinForms form and you might need to do additional manual initialization.

cppconlib: A C++ library for working with the Windows console

$
0
0

Many years ago I published on my blog a helper class for working with the Windows console that was wrapping the Windows console API. Looking back at it I realized it was a pretty naive implementation. So I decided to start a new and make something more flexible and easier to use. Hopefully, I was more successful. The result is a small C++ template library called cppconlib, available on codeplex.

cppconlib is built with C++11 features and requires Visual Studio 2012 or newer. The library is available in a single header called conmanip.h and provides a set of helper classes, functions and constants for manipulating a Windows console (using the Windows console functions). The library features the following components:

  • console_context<T>: represents a context object for console operations; its main purpose is restoring console settings; typedefs for the three consoles are available (console_in_context, console_out_context and console_err_context)
  • console<T>: represents a console objects providing operations such as changing the foreground and background colors, the input mode, screen buffer size, title, and others; typedefs for the three consoles are available (console_in, console_out and console_err)
  • manipulating functions that can be used with cout/wcout and cin/wcin: settextcolor()/restoretextcolor(), setbgcolor()/restorebgcolor(), setcolors(), setmode()/clearmode(), setposx()/setposy()/setpos().

The library can be downloaded from here. Detailed documentation is available here.

cppconlib

Examples

The following example prints some text in custom colors and then reads text in a different set of colors.

#include "conmanip.h"
using namespace conmanip;

#include <iostream>

int main()
{
   // create a console context object, used for restoring console settings
   console_out_context ctxout;
   // create a console object
   console_out conout(ctxout);

   // change the title of the console
   conout.settitle("cppconlib");

   // output text with colors
   std::cout 
      << settextcolor(console_text_colors::light_yellow)
      << setbgcolor(console_bg_colors::cyan)
      << "This text is colored: ";

   // read text with colors
   std::string text;
   std::cin 
      >> settextcolor(console_text_colors::cyan)
      >> setbgcolor(console_bg_colors::light_yellow)
      >> text;

   std::cout << std::endl;

   // restore console attributes (text and background colors)
   ctxout.restore(console_cleanup_options::restore_attibutes);

   return 0;
} // -> console settings are restored here when the context object goes out of scope

cppconlib2

The following code prints a rhomb to the console:

int main()
{
   console_out_context ctxout;
   console_out conout(ctxout);

   conout.settitle("cppconlib");

   int depth;
   std::cout << "Depth (1-9)? ";
   std::cin >> depth;

   int middle = conout.getsize().X/2;
   for(int i = 1; i <= depth; ++i)
   {
      std::cout << setposx(middle-i+1);

      for(int j = 1; j<=i; ++j)
      {
         std::cout << i << " ";
      }
      std::cout << "\n";
   }

   for(int i = depth-1; i >=1; --i)
   {
      std::cout << setposx(middle-i+1);

      for(int j = 1; j<=i; ++j)
      {
         std::cout << i << " ";
      }
      std::cout << "\n";
   }

   return 0;
}

cppconlib3

For more details and updates check the project at codeplex: https://cppconlib.codeplex.com.

UPDATE: A NuGet package for cppconlib is available.

Render the screen of a Windows Store App to a bitmap in Windows 8.1

$
0
0

In WPF, Silverlight and Windows Phone it is possible to render a visual object into a bitmap using the RenderTargetBitmap. This functionality, that I find pretty basic, was not available for Windows Store applications. Fortunately, Windows 8.1 provides that functionality for Windows Store applications too, through the same RenderTargetBitmap class.

There are some limitations though:

  • it should be used in the code behind (not declared in XAML) because you have to call RenderAsync
  • collapsed visual objects are not rendered (only visible ones)
  • in rare circumstances the content can be lost due to the interaction with lower level systems; in this case a specific exception is triggered
  • the rendered target bitmap does not automatically scale when the current DPI settings change
  • the maximum rendered size of a XAML visual tree is restricted by the maximum dimensions of a DirectX texture

Here is a demo Windows Store application that has several controls and a button that when pressed a screenshot of the area shown in red (it’s a grid) is taken. The bitmap is saved on disk, but also displayed as the source for the image control shown in the preview area.

wsas1

<Page>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Name="mainGrid">

      <TextBlock Text="Windows Store App Screenshot Demo" Style="{StaticResource HeaderTextBlockStyle}"
                 Grid.Column="0" Grid.ColumnSpan="5" Grid.Row="0"
                 Margin="0,30,0,30"
                 TextAlignment="Center" />

      <Grid Name="controlsGrid" Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="1" Margin="5,5,5,50">
      </Grid>
    </Grid>
</Page>

The handler for the Click button even looks like this:

async void btnScreenshot_Click(object sender, RoutedEventArgs e)
{
   var bitmap = await SaveScreenshotAsync(controlsGrid);

   imagePreview.Source = bitmap;
}

SaveScreenshotAsync is an async method that takes the reference to the FrameworkElement to be rendered to a bitmap (in this case the constrolsGrid) and returns a Task<RenderedTargetBitmap> that can be awaited on. As soon as we have the bitmap we set it as the source for the image control (imagePreview).

wsas2

async Task<RenderTargetBitmap> SaveScreenshotAsync(FrameworkElement uielement)
{
   var file = await PickSaveImageAsync();

   return await SaveToFileAsync(uielement, file);         
}      

async Task<RenderTargetBitmap> PickSaveImageAsync()
{
   var filePicker = new FileSavePicker();
   filePicker.FileTypeChoices.Add("Bitmap", new List() { ".bmp" });
   filePicker.FileTypeChoices.Add("JPEG format", new List() { ".jpg" });
   filePicker.FileTypeChoices.Add("Compuserve format", new List() { ".gif" });
   filePicker.FileTypeChoices.Add("Portable Network Graphics", new List() { ".png" });
   filePicker.FileTypeChoices.Add("Tagged Image File Format", new List() { ".tif" });
   filePicker.DefaultFileExtension = ".jpg";
   filePicker.SuggestedFileName = "screenshot";
   filePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
   filePicker.SettingsIdentifier = "picture picker";
   filePicker.CommitButtonText = "Save picture";

   return await filePicker.PickSaveFileAsync();
}

SaveScreenshotAsync is an async method that takes the FrameworkElement to be rendered to a bitmap and returns a Task<RenderedTargetBitmap> that can be awaited on. This method first prompts the user to select a destination file for the rendered bitmap. When the file is available it calls SaveToFileAsync to rendered the bitmap and write it to the file.

async Task<RenderTargetBitmap> SaveToFileAsync(FrameworkElement uielement, StorageFile file)
{
   if (file != null)
   {
      CachedFileManager.DeferUpdates(file);

      Guid encoderId = GetBitmapEncoder(file.FileType);

      try
      {
         using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
         {
            return await CaptureToStreamAsync(uielement, stream, encoderId);
         }
      }
      catch(Exception ex)
      {
         DisplayMessage(ex.Message);
      }

      var status = await CachedFileManager.CompleteUpdatesAsync(file);
   }

   return null;
}

Guid GetBitmapEncoder(string fileType)
{
   Guid encoderId = BitmapEncoder.JpegEncoderId;
   switch (fileType)
   {
      case ".bmp":
         encoderId = BitmapEncoder.BmpEncoderId;
         break;
      case ".gif":
         encoderId = BitmapEncoder.GifEncoderId;
         break;
      case ".png":
         encoderId = BitmapEncoder.PngEncoderId;
         break;
      case ".tif":
         encoderId = BitmapEncoder.TiffEncoderId;
         break;
   }

   return encoderId;
}

async void DisplayMessage(string error)
{
   var dialog = new MessageDialog(error);

   await dialog.ShowAsync();
}

SaveToFileAsync is an async method that takes the FrameworkElement to be rendered to a bitmap and the StorageFile when the bitmap is to be saved and returns a Task<RenderedTargetBitmap> that can be awaited on. The file is opened asynchronous for read-write access and the returned IRandomAccessStream is passed further together with the framework element and the bitmap encoder id (that specifies how the bitmap should be encoded, i.e. BMP, JPEG, PNG, GIF, etc.) to CaptureToStreamAsync.

async Task<RenderTargetBitmap> CaptureToStreamAsync(FrameworkElement uielement, IRandomAccessStream stream, Guid encoderId)
{
   try
   {
      var renderTargetBitmap = new RenderTargetBitmap();
      await renderTargetBitmap.RenderAsync(uielement);

      var pixels = await renderTargetBitmap.GetPixelsAsync();

      var logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
      var encoder = await BitmapEncoder.CreateAsync(encoderId, stream);
      encoder.SetPixelData(
          BitmapPixelFormat.Bgra8,
          BitmapAlphaMode.Ignore,
          (uint)renderTargetBitmap.PixelWidth,
          (uint)renderTargetBitmap.PixelHeight,
          logicalDpi,
          logicalDpi,
          pixels.ToArray());

      await encoder.FlushAsync();

      return renderTargetBitmap;
   }
   catch (Exception ex)
   {
      DisplayMessage(ex.Message);
   }

   return null;
}

CaptureToStreamAsync creates a new RenderTargetBitmap object and calls RenderAsync to render the visual tree of the framework element to a bitmap. After the bitmap is rendered it retries the image as a buffer of byes in the BGRA8 format. It then asynchronously creates a BitmapEncoder for the IRandomAccessStream stream that it received as an argument, it calls SetPixelData to set the pixels data (notice the BitmapPixelFormat.Bgra8 parameter that matches the pixels format returned by GetPixelsAsync) and later asynchronously flushes all the image data, basically writing it to the file. It then returns that RenderTargetBitmap object that it created, which is used eventually as the source for the image control.

Here is how the saved JPEG image (also seen in the preview screenshot above) looks likes:
wsas3

You can check the source code of the attached WinRT Screenshot demo (18). It requires Visual Studio 2013 and Windows 8.1.

Working with the Settings Charm for Windows 8.1 Store Applications

$
0
0

Windows 8 features a Settings charm to display both application (the top part) and system (the bottom part) settings (you get it from swiping from the side of the screen). The system provides two entry points, Permissions and Rate and Review, the later only for applications installed through the store.

You can customize the settings charm by adding new entry points. For instance, you may want to add an About pane. If your application uses network capabilities then you have to add a privacy policy, otherwise your application will not pass the Windows Store Certification.

charms settingscharm6

In this post I will show how you can add new entries to the settings charm for Windows 8.1 applications (this won’t work for Windows 8 applications). We have to use two classes:

  • SettingsPane: enables the app to control the Settings Charm pane. The app can add or remove commands, receive a notification when the user opens the pane, or open the pane programmatically.
  • SettingsFlyout: represents a control that provides in-context access to settings that affect the current app. This class is new to Windows 8.1

The following code adds a new entry to the settings pane called Privacy policy and provides a handler for the command. In the handler we create a new instance of a SettingsFlayout and show it.

internal static class PrivacyPolicy
{
  public static void Initialise()
  {
     SettingsPane settingsPane = SettingsPane.GetForCurrentView();

     settingsPane.CommandsRequested += (s, e) =>
     {
        SettingsCommand settingsCommand = new SettingsCommand(
          "PRIVACY_ID",
          "Privacy policy",    
          async command =>
          {
             var flyout = new SettingsFlyout();
             flyout.Title = "Privacy policy";

             var file = await StorageFile.GetFileFromApplicationUriAsync(
                new Uri("ms-appx:///Settings/PrivacyPolicy.txt"));
             var properties = await file.GetBasicPropertiesAsync();
             var stream = await file.OpenAsync(FileAccessMode.Read);
             var reader = new DataReader(stream.GetInputStreamAt(0));
             await reader.LoadAsync((uint)properties.Size);
             string text = reader.ReadString(reader.UnconsumedBufferLength);

             flyout.Content = new TextBlock()
             {
                Text = text,
                TextAlignment = Windows.UI.Xaml.TextAlignment.Left,
                TextWrapping = Windows.UI.Xaml.TextWrapping.Wrap,
                FontSize = 14
             };

             flyout.Show();
          }
        );
        e.Request.ApplicationCommands.Add(settingsCommand);
     };
  }
}

The text of the privacy policy is kept in a text file under the Settings folder. We asynchronously open and read the content of the file and when the text is available we create a new TextBlock control and use it as the content of the flyout content control.

Then we have to initialize the settings pane when the application starts.

protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    // ...
    
    // Ensure the current window is active
    Window.Current.Activate();

    PrivacyPolicy.Initialise();
}

When you start the application and swipe the right edge of the screen the charms bar shows up. Opening the Settings charm will now show two entries for the application: Privacy Policy and Permissions.
settingscharm2 settingscharm3

The next sample shows how to add an About page. It’s very similar actually.

internal static class AboutPage
{
  public static void Initialise()
  {
     SettingsPane settingsPane = SettingsPane.GetForCurrentView();

     settingsPane.CommandsRequested += (s, e) =>
     {
        SettingsCommand settingsCommand = new SettingsCommand(
          "ABOUT_ID",
          "About",    
          command =>
          {
             var flyout = new SettingsFlyout();
             flyout.Title = "About";

             var version = Package.Current.Id.Version;
             var versionstring = string.Format("{0}.{1}.{2}.{3}",
                version.Major, version.Minor, version.Build, version.Revision);

             flyout.Content = new TextBlock()
             {
                Text = "Created by Marius Bancila\r\nVersion "+
                       versionstring+
                       "\r\n\r\nThis is a demo app that shows how to work with Windows Settings Charm.",
                TextAlignment = Windows.UI.Xaml.TextAlignment.Left,
                TextWrapping = Windows.UI.Xaml.TextWrapping.Wrap,
                FontSize = 14
             };

             flyout.Show();
          }
        );
        e.Request.ApplicationCommands.Add(settingsCommand);
     };
  }
}

protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    // ...
    
    // Ensure the current window is active
    Window.Current.Activate();

    AboutPage.Initialise();
    PrivacyPolicy.Initialise();
}

Notice that the entries in the settings charm appear in the order they where added.
settingscharm4 settingscharm5

The content of the flyout can be any visual object (the simple TextBlock is used only for demo purposes). It is also possible to customize the flyout header, icon, background, etc. Here is the same About page with additional flyout settings.

var flyout = new SettingsFlyout();
flyout.Title = "About";
flyout.HeaderBackground = new SolidColorBrush(Colors.DeepSkyBlue);
flyout.HeaderForeground = new SolidColorBrush(Colors.Black);
flyout.IconSource = new BitmapImage(new Uri("ms-appx:///Images/about.png"));
flyout.Background = new SolidColorBrush(Colors.Wheat);

settingscharm7

Here is some additional reading: Guidelines for app settings (Windows Store apps).

You Chemical Name – My First Windows Store App

$
0
0

My first Windows Store app (for Window 8.1) is now available in Windows Store. It’s called Your Chemical Name and shows names (and text) using chemical elements symbols in the Breaking Bad style.

yourchemicalname11

The application allows to:

  • customize the appearance of text, colors, background
  • customize the position of the text on the background
  • save image to a file
  • post image on a facebook album
  • share image with other apps

yourchemicalname12

yourchemicalname13

yourchemicalname14

You save the images to disk or share them on facebook or with apps supporting the Windows Share Charm.

yourchemicalname15

Here are a few screenshots:
yourchemicalname2

yourchemicalname3

yourchemicalname5

More about the application here.

Download Your Chemical Name from Windows Store.

CRT Refactored in Visual Studio “14″

$
0
0

Visual Studio “14″ CTP ships with a refactored C Runtime. The first thing you’ll notice is that msvcrXX.dll has been replaced by three new DLLs: appcrtXX.dll, desktopcrtXX.dll and vcruntimeXX.ddl (where XX stands for the version number so in this version it’s appcrt140.dll, desktopcrt140.dll and vcruntime140.dll).

crtdlls
You can see in this image that both desktopcrt140.dll and vcruntime140.dll depend on appcrt140.dll.

These three new DLLs export run-time routines in different categories, with some of them overlapping, as shown by the bellow table (assembled by directly analyzing the exports of the three modules).


Function

Appcrt140.dll

Desktopcrt140.dll

Vcruntime140.dll
Buffer Manipulation
Byte Classification
Character Classification
Console and Port I/O
Data Alignment
Data Conversion
Debug Routines
Directory Control
Error Handling
Exception Handling
File Handling
Floating-Point Support
Low-Level I/O
Process and Environment Control
Robustness
Searching and Sorting
Stream I/O
String Manipulation
System Calls
Time Management

Breaking CRT routines in several DLLs is not the only change. The CRT has been rewritten for safety and const correctness. Many of the routines have been re-written in C++. Here is a random example: the _open function, that was available in open.c was implemented like this in Visual Studio 2013:

int __cdecl _topen (
        const _TSCHAR *path,
        int oflag,
        ...
        )
{
        va_list ap;
        int pmode = 0;
        int fh = -1;
        errno_t retval = 0;
        int unlock_flag = 0;

        _VALIDATE_RETURN( (path != NULL), EINVAL, -1);

        va_start(ap, oflag);
        pmode = va_arg(ap, int);
        va_end(ap);

        __try {
/* Last parameter passed as 0 because we don't want to
validate pmode from open */
            retval = _tsopen_nolock( &unlock_flag,
                                 &fh,
                                 path,
                                 oflag,
                                 _SH_DENYNO,
                                 pmode,
                                 0 );
        }
        __finally {
            if ( unlock_flag )
            {
                if (retval)
                {
                    _osfile(fh) &= ~FOPEN;
                }
                _unlock_fh(fh);
            }
        }

        if (retval)
        {
            errno = retval;
            return -1;
        }

        return fh;
}

In Visual Studio “14″ CTP it is available in function appcrt\open.cpp and looks like this:

template <typename Character>
static int __cdecl common_open(
    Character const* const path,
    int              const oflag,
    int              const pmode
    ) throw()
{
    typedef __crt_char_traits<Character> traits;

    _VALIDATE_RETURN(path != nullptr, EINVAL, -1);

    int fh = -1;
    int unlock_flag = 0;
    errno_t error_code = 0;
    __try
    {
        error_code = traits::tsopen_nolock(&unlock_flag, &fh, path, oflag, _SH_DENYNO, pmode, 0);
    }
    __finally
    {
        if (unlock_flag)
        {
            if (error_code)
            {
                _osfile(fh) &= ~FOPEN;
            }

            __acrt_lowio_unlock_fh(fh);
        }
    }

    if (error_code != 0)
    {
        errno = error_code;
        return -1;
    }

    return fh;
}

UPDATE

To read more about the refactoring see the VC++ team’s blog posts:


Changing Windows password complexity requirements

$
0
0

I recently encountered a problem creating new logins with SQL Server. Something that has worked for years suddenly stopped with the following error:

Password validation failed. The password does not meet Windows policy requirements because it is too short.

Since SQL Server was using Windows local security policy I went and checked that at Security Settings > Account Policies > Password Policy in Local Security Policy (available under Administrative Tools in Control Panel or by opening secpol.msc). As expected, these contained setting that I was not expecting, which were probably changed from the network by a system administrator.

However, I wanted to be able to enter shorter passwords, like 8 characters instead of 10, but this was disabled. Even if I was running as administrator, the option of changing this was disabled.

It is however still possible to modify these settings even if you cannot do it from the management console. You can do it from a command prompt as administrator.

  1. Open a command prompt running as administrator
  2. Run the following command to export the settings to a file. In my example, the target path is c:\temp\local.cfg, but it can be anything.

    secedit /export /cfg c:\temp\local.cfg
  3. Edit the file with notepad or another editor. The file is an INI file with sections and key-value pairs. The password settings are available under the [System Access] section. For changing the minimum length of the passwords modify the MinimumPasswordLength key.
  4. Save the file and run the following command to import the settings from the modified file.

    secedit /configure /db %windir%\security\local.sdb /cfg c:\temp\local.cfg /areas SECURITYPOLICY
  5. Close and open the Local Security Policy console again and check the settings.

What’s New in Visual Studio 2017 for C++ Development

$
0
0

Visual Studio 2017 has been officially launched today. The release notes contain a summary of all the changes available in the new version. This post is focused on the changes for C++ development.

The Visual C++ team has released a series of blog posts to document some of the new features. Here is a list of them:

Of all the changes and new features in VC++ 2017 (that are described in details in the articles mentioned above) there are several that I want to mention:

  • The C++ compiler is C++14 complete, but still lacks several C++98 and C++11 features. It also contains some features added to C++17.
  • The standard library implementation contains C++17 features including: any, optional, variant, string_view, make_from_tuple(). The complete list of improvements is available here.
  • Visual C++ 2017 runtime is compatible to the Visual C++ 2015 runtime. That means you can link to libraries build with VC++ 2015.
  • The C++ compiler version is 19.1, a minor release of the Visual C++ 2015 compiler (version 19.0). That means _MSC_VER is 1910. On the other hand, MFC and ATL are still on version 14.0 as in Visual C++ 2015. That means _MFC_VER and _ATL_VER ar both 0x0E00.
  • It is possible to open code from any folder with the Open Folder feature and get IntelliSense, navigation, building, and debugging capabilities without creating a solution and project first.
  • You can build your projects with CMake that is now supported in Visual Studio.
  • There is a built-in support for using another C++ compiler, such as Clang or GCC (mainly intended for building projects that target Android, Linux or Mac).
  • The C++ Core Checkers for enforcing the C++ Core Guidelines are now distributed with Visual Studio.
  • Installation of Visual Studio has been redesigned. Components are delivered in “workloads”, but individual components can be added or removed. For C++ there are five workloads: Universal Windows Platform development, Desktop Development with C++, Game development with C++, Mobile development with C++, and Linux development with C++.
  • Installation folder is not c:\Program Files (x86)\Microsoft Visual Studio 15.0 as with previous version, but c:\Program Files (x86)\Microsoft Visual Studio\2017\.

Here are a couple of screenshots from installing Visual Studio:

How to determine what CLR versions are installed using C++

$
0
0

You may have multiple versions of the .NET framework installed and used on your machine. The framework has two components: the set of assemblies that provide functionalities for your application, and the common language runtime (CLR) that handles the execution of the application. These two components are versioned separately. If you what to see what versions of the framework are installed, you have to query the Windows Registry. If you want to know what versions of the CLR are installed you could either use clrver.exe or do it programmatically. In this article, we will look at this later option and how to do it in C++.

How to: Determine Which .NET Framework Versions Are Installed

To query the installed CLR versions from C++ we have to:

#include <string>
#include <iostream>

#import <mscorlib.tlb> raw_interfaces_only rename( "value", "value2" ) rename( "ReportEvent", "InteropServices_ReportEvent" )

#include <metahost.h>
#pragma comment( lib, "Mscoree" )

_COM_SMARTPTR_TYPEDEF(ICLRMetaHost, IID_ICLRMetaHost);
_COM_SMARTPTR_TYPEDEF(ICLRRuntimeInfo, IID_ICLRRuntimeInfo);

int main()
{
   ICLRMetaHostPtr pMetaHost{ nullptr };
   HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
   if (FAILED(hr))
      return -1;

   IEnumUnknownPtr enumptr{ nullptr };
   hr = pMetaHost->EnumerateInstalledRuntimes(&enumptr);
   if (FAILED(hr))
      return -1;

   while (true)
   {
      ULONG fetched{ 0 };
      IUnknownPtr uptr{ nullptr };
      hr = enumptr->Next(1, &uptr, &fetched);
      if (hr == S_OK)
      {
         ICLRRuntimeInfoPtr crlri{ uptr };

         DWORD size{ 0 };
         hr = crlri->GetVersionString(nullptr, &size);
         if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) && size > 0)
         {
            std::wstring version(size, 0);
            hr = crlri->GetVersionString(&version.front(), &size);
            if (SUCCEEDED(hr))
               std::wcout << version << std::endl;
         }
      }
      else
         break;
   };

   return 0;
}

In order to call CLRCreateInstance we must include the metahost.h header and link with the Mscoree.lib static library.

To use the ICLRMetaHost and ICLRRuntimeInfo interfaces we must import the mscorlib.tlb type library. The _COM_SMARTPTR_TYPEDEF are used for defining COM smart pointers ICLRMetaHostPtr and ICLRRuntimeInfoPtr that automatically handle the reference counter of the underlying COM object.

The call to the EnumerateInstalledRuntimes method, when successful, returns a pointer to an IEnumUnknown interface. This enables enumerating through a component that contains multiple objects. Its method Next retrieves a specified number of items. In this implementation that number is 1. The return value is a pointer to the IUnknown interface, but what we are enumerating through are actually ICLRRuntimeInfo interfaces.

To retrieve the version info we must use the GetVersionString method of ICLRRuntimeInfo. The arguments are an array of wide characters that will receive the string and the size of the array. In order to retrieve the necessary size of the buffer, we have to first call the method with null for the first argument. In this case the function returns ERROR_INSUFFICIENT_BUFFER as a HRESULT (i.e. HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) and sets the second argument to the necessary size. After allocating the necessary buffer, we call the method again, providing the buffer and its size.

Running this program on my machine prints the following (which is the same as the output from clrver.exe).

v2.0.50727
v4.0.30319

My open-source projects are moved to GitHub

$
0
0

I used to have several open-source projects available on CodePlex. At the end of 2017, the site was put in read-only mode and it will probably be closed at some point. Therefore, I have decided to move the projects that could still be useful to GitHub.

MFC Collection Utilities
A small library that enables developers to use MFC containers (arrays, lists, maps) with range-based for loops. The library consists of a single header that you include in your MFC projects.

#include "mfciterators.h"

void func(CStringArray const & arr)
{
   for(auto const & str : arr)
   {
      // do something with str
   }
}

CMap<int, CString> map;
map.SetAt(1, "one");
map.SetAt(2, "two");http://mariusbancila.ro/blog/wp-admin/post-new.php#
map.SetAt(3, "three");
for(auto const & kvp : map)
{
   // do something with the key-value pair
   TRACE("%d-%s\n", kvp.key, kvp.value);
}

See:

 

cppconlib
A header-only C++ template library for manipulating the settings of a Windows console (colors, text position, input mode, etc.)

See:

Using the curl library from C++ on Windows

$
0
0

curl is a project containing a command line tool and a library that can be used to transfer data using a variety of protocols, including, of course, HTTP and HTTPS. The library API is written in C, but there are various C++ wrappers on top of it. One of those is curlcpp.

Here is an example, using curlcpp, of how to get weather data from https://openweathermap.org.

#include "curl_easy.h"
#include "curl_form.h"
#include "curl_ios.h"
#include "curl_exception.h"

std::stringstream get_response(std::string_view url)
{
   std::stringstream str;
   curl::curl_ios<std::stringstream> writer(str);

   curl::curl_easy easy(writer);

   easy.add<CURLOPT_URL>(url.data());
   easy.add<CURLOPT_FOLLOWLOCATION>(1L);
   try
   {
      easy.perform();
   }
   catch (curl::curl_easy_exception error)
   {
      auto errors = error.get_traceback();
      error.print_traceback();
   }

   return str;
}

int main()
{
   using namespace std::string_literals;

   auto appid = "0c7978..."s;
   auto location = "Timisoara"s;
   auto url = "https://api.openweathermap.org/data/2.5/weather?q=" + location + "&appid=" + appid;

   auto json = get_response(url);

   std::cout << json.str() << std::endl;

   return 0;
}

Here is how you get this working on Windows using Visual Studio 2017. The following instructions are for 32-bit version, but you can do the same for 64-bit.

For libcurl:

  • Download CURL from https://curl.haxx.se/download.html.
  • Unzip and open the solution projects\Windows\VC15\curl-all.sln.
  • Build configurations LIB Release - DLL Windows SSPI and LIB Debug - DLL Windows SSPI for the target platform that you need (Win32 or x64)
  • Copy the output to build\lib\x86\ (or build\lib\x64\). To have both release and debug builds in the same folder name the debug one libcurld.lib.

For curlcpp:

  • Clone or download CURLCPP from https://github.com/JosephP91/curlcpp.
  • Create a subfolder called build in the project’s main folder.
  • Execute CMake from the build folder to create a Visual Studio solution. Here is an example that assums curl is in the same folder as curlcpp.
    cmake -G "Visual Studio 15 2017" .. -DCURL_LIBRARY=..\curl\build\lib\x86\libcurld.lib -DCURL_INCLUDE_DIR=..\curl\include
  • Open the generated project and build it.
  • Copy the output to lib\x86 (where lib is a subfolder in the curlcpp project main folder). To be able to have both Debug and Release builds in the same folder rename the Debug build to curlcppd.lib.

For your project using libcurl and curlcpp:

  • Add CURL_STATICLIB to the preprocessor definitions.
  • Add curl\include and curlcpp\include to the list of Additional Include Directories. (Make sure you include the correct relative paths.)
  • Add curl and curlcpp output folders, curl\build\lib\x86 and curlcpp\lib\x86\, to the Additional Library Directories.
  • Add the following static libraries to the list of Additional dependencies: libcurld.lib;curlcppd.lib;Crypt32.lib;ws2_32.lib;winmm.lib;wldap32.lib;

Attached is a demo project with libcurl and curlcpp builds for both 32 and 64-bit platforms.

Viewing all 45 articles
Browse latest View live