Quantcast
Viewing all 45 articles
Browse latest View live

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

This project has been moved to GitHub.

New location: https://github.com/mariusbancila/cppconlib

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.

Image may be NSFW.
Clik here to view.
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

Image may be NSFW.
Clik here to view.
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;
}

Image may be NSFW.
Clik here to view.
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

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.

Image may be NSFW.
Clik here to view.
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).

Image may be NSFW.
Clik here to view.
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:
Image may be NSFW.
Clik here to view.
wsas3

You can check the source code of the attached [download id=”11″]. It requires Visual Studio 2013 and Windows 8.1.

Working with the Settings Charm for Windows 8.1 Store Applications

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.

Image may be NSFW.
Clik here to view.
charms
Image may be NSFW.
Clik here to view.
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.
Image may be NSFW.
Clik here to view.
settingscharm2
Image may be NSFW.
Clik here to view.
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.
Image may be NSFW.
Clik here to view.
settingscharm4
Image may be NSFW.
Clik here to view.
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);

Image may be NSFW.
Clik here to view.
settingscharm7

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

You Chemical Name – My First Windows Store App

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.

Image may be NSFW.
Clik here to view.
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

Image may be NSFW.
Clik here to view.
yourchemicalname12

Image may be NSFW.
Clik here to view.
yourchemicalname13

Image may be NSFW.
Clik here to view.
yourchemicalname14

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

Image may be NSFW.
Clik here to view.
yourchemicalname15

Here are a few screenshots:
Image may be NSFW.
Clik here to view.
yourchemicalname2

Image may be NSFW.
Clik here to view.
yourchemicalname3

Image may be NSFW.
Clik here to view.
yourchemicalname5

More about the application here.

Download Your Chemical Name from Windows Store.

CRT Refactored in Visual Studio “14”

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).

Image may be NSFW.
Clik here to view.
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

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.

Image may be NSFW.
Clik here to view.

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.

Image may be NSFW.
Clik here to view.

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.
    Image may be NSFW.
    Clik here to view.
  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.
    Image may be NSFW.
    Clik here to view.

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

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:
Image may be NSFW.
Clik here to view.

Image may be NSFW.
Clik here to view.

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

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

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");https://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.)

Image may be NSFW.
Clik here to view.

See:

Using the curl library from C++ on Windows

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. In this article, I will show how to build these libraries for Windows with Visual Studio.

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;
   try
   {
      curl::curl_ios<std::stringstream> writer(str);
      curl::curl_easy easy(writer);

      easy.add<CURLOPT_URL>(url.data());
      easy.add<CURLOPT_FOLLOWLOCATION>(1L);

      easy.perform();
   }
   catch (curl::curl_easy_exception const & 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.

May good reads

June good reads

Working with the Settings Charm for Windows 8.1 Store Applications

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.

Image may be NSFW.
Clik here to view.
charms
Image may be NSFW.
Clik here to view.
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.
Image may be NSFW.
Clik here to view.
settingscharm2
Image may be NSFW.
Clik here to view.
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.
Image may be NSFW.
Clik here to view.
settingscharm4
Image may be NSFW.
Clik here to view.
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);

Image may be NSFW.
Clik here to view.
settingscharm7

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

You Chemical Name – My First Windows Store App

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.

Image may be NSFW.
Clik here to view.
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

Image may be NSFW.
Clik here to view.
yourchemicalname12

Image may be NSFW.
Clik here to view.
yourchemicalname13

Image may be NSFW.
Clik here to view.
yourchemicalname14

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

Image may be NSFW.
Clik here to view.
yourchemicalname15

Here are a few screenshots:
Image may be NSFW.
Clik here to view.
yourchemicalname2

Image may be NSFW.
Clik here to view.
yourchemicalname3

Image may be NSFW.
Clik here to view.
yourchemicalname5

More about the application here.

Download Your Chemical Name from Windows Store.

CRT Refactored in Visual Studio “14”

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).

Image may be NSFW.
Clik here to view.
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

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.

Image may be NSFW.
Clik here to view.

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.

Image may be NSFW.
Clik here to view.

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.
    Image may be NSFW.
    Clik here to view.
  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.
    Image may be NSFW.
    Clik here to view.

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

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:
Image may be NSFW.
Clik here to view.

Image may be NSFW.
Clik here to view.

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

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

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.)

Image may be NSFW.
Clik here to view.

See:

Using the curl library from C++ on Windows

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. In this article, I will show how to build these libraries for Windows with Visual Studio.

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;
   try
   {
      curl::curl_ios<std::stringstream> writer(str);
      curl::curl_easy easy(writer);

      easy.add<CURLOPT_URL>(url.data());
      easy.add<CURLOPT_FOLLOWLOCATION>(1L);

      easy.perform();
   }
   catch (curl::curl_easy_exception const & 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