Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This quickstart shows you how to implement the client initialization pattern that the MIP C++ SDK uses at runtime.
Note
Any client application that uses the MIP Protection SDKs requires the steps in this quickstart. Complete these quickstarts serially after application initialization and implementation of authentication delegate and consent delegate classes.
Prerequisites
If you haven't already, be sure to:
- Complete the steps in Microsoft Information Protection (MIP) SDK setup and configuration. This "Client application initialization" quickstart relies on proper SDK setup and configuration.
- Optionally:
- Review Profile and engine objects. The profile and engine objects are universal concepts, required by clients that use the MIP File/Policy/Protection SDKs.
- Review Authentication concepts to learn how authentication and consent are implemented by the SDK and the client application.
- Review Observer concepts to learn more about observers, and how they're implemented. The MIP SDK uses the observer pattern to implement asynchronous event notifications.
Create a Visual Studio solution and project
First, create and configure the initial Visual Studio solution and project that the other quickstarts build on.
Open Visual Studio 2022 or later, select the File menu, New, Project. In the New Project dialog:
Add the NuGet package for the MIP Protection SDK to your project:
In Solution Explorer, right-click the project node directly under the top solution node, and then select Manage NuGet packages...:
When the NuGet Package Manager tab opens in the Editor Group tabs area:
- Select Browse.
- Enter
Microsoft.InformationProtectionin the search box. - Select the
Microsoft.InformationProtection.Protectionpackage. - Select Install, and then select OK when the Preview changes confirmation dialog appears.
Implement observer classes to monitor the Protection profile and engine objects
Now create a basic implementation for a Protection profile observer class by extending the SDK's mip::ProtectionProfile::Observer class. The SDK instantiates the observer and uses it later to monitor the loading of the Protection profile object and add the engine object to the profile.
Add a new class to your project, which generates both the header (.h) and implementation (.cpp) files for you:
In Solution Explorer, right-click the project node again, select Add, and then select Class.
On the Add Class dialog:
- In the Class Name field, enter
profile_observer. Notice that Visual Studio automatically populates both the .h file and .cpp file fields based on the name you enter. - When finished, select OK.
- In the Class Name field, enter
After generating the .h and .cpp files for the class, Visual Studio opens both files in Editor Group tabs. Now update each file to implement your new observer class:
Update
profile_observer.hby selecting and deleting the generatedprofile_observerclass. Don't remove the preprocessor directives that the previous step generated (#pragma, #include). Then copy and paste the following source into the file after any existing preprocessor directives:#include <memory> #include "mip/protection/protection_profile.h" using std::exception_ptr; using std::shared_ptr; class ProtectionProfileObserver final : public mip::ProtectionProfile::Observer { public: ProtectionProfileObserver() { } void OnLoadSuccess(const std::shared_ptr<mip::ProtectionProfile>& profile, const std::shared_ptr<void>& context) override; void OnLoadFailure(const std::exception_ptr& Failure, const std::shared_ptr<void>& context) override; void OnAddEngineSuccess(const std::shared_ptr<mip::ProtectionEngine>& engine, const std::shared_ptr<void>& context) override; void OnAddEngineFailure(const std::exception_ptr& Failure, const std::shared_ptr<void>& context) override; };Update
profile_observer.cppby selecting and deleting the generatedprofile_observerclass implementation. Don't remove the preprocessor directives that the previous step generated (#pragma, #include). Then copy and paste the following source into the file after any existing preprocessor directives:#include <future> using std::promise; using std::shared_ptr; using std::static_pointer_cast; using mip::ProtectionEngine; using mip::ProtectionProfile; void ProtectionProfileObserver::OnLoadSuccess(const shared_ptr<ProtectionProfile>& profile, const shared_ptr<void>& context) { auto promise = static_pointer_cast<std::promise<shared_ptr<ProtectionProfile>>>(context); promise->set_value(profile); } void ProtectionProfileObserver::OnLoadFailure(const std::exception_ptr& error, const shared_ptr<void>& context) { auto promise = static_pointer_cast<std::promise<shared_ptr<ProtectionProfile>>>(context); promise->set_exception(error); } void ProtectionProfileObserver::OnAddEngineSuccess(const shared_ptr<ProtectionEngine>& engine, const shared_ptr<void>& context) { auto promise = static_pointer_cast<std::promise<shared_ptr<ProtectionEngine>>>(context); promise->set_value(engine); } void ProtectionProfileObserver::OnAddEngineFailure(const std::exception_ptr& error, const shared_ptr<void>& context) { auto promise = static_pointer_cast<std::promise<shared_ptr<ProtectionEngine>>>(context); promise->set_exception(error); }
Repeat step 1 to add a new class for the Protection engine observer,
engine_observer, to your project. This class generates both the header (.h) and implementation (.cpp) files for you.After generating the .h and .cpp files for the class, Visual Studio opens both files in Editor Group tabs. Now update each file to implement your new observer class:
Update
engine_observer.hby selecting and deleting the generatedengine_observerclass. Don't remove the preprocessor directives that the previous step generated (#pragma, #include). Then copy and paste the following source into the file after any existing preprocessor directives:#include <memory> #include "mip/protection/protection_engine.h" using std::vector; using std::exception_ptr; using std::shared_ptr; class ProtectionEngineObserver final : public mip::ProtectionEngine::Observer { public: ProtectionEngineObserver() {} void OnGetTemplatesSuccess(const vector<std::shared_ptr<mip::TemplateDescriptor>>& templateDescriptors, const shared_ptr<void>& context) override; void OnGetTemplatesFailure(const exception_ptr& Failure, const shared_ptr<void>& context) override; };Update
engine_observer.cppby selecting and deleting the generatedengine_observerclass implementation. Don't remove the preprocessor directives that the previous step generated (#pragma, #include). Then copy and paste the following source into the file after any existing preprocessor directives:#include "mip/protection/protection_profile.h" #include "engine_observer.h" using std::promise; void ProtectionEngineObserver::OnGetTemplatesSuccess(const vector<shared_ptr<mip::TemplateDescriptor>>& templateDescriptors,const shared_ptr<void>& context) { auto loadPromise = static_cast<promise<vector<shared_ptr<mip::TemplateDescriptor>>>*>(context.get()); loadPromise->set_value(templateDescriptors); }; void ProtectionEngineObserver::OnGetTemplatesFailure(const exception_ptr& Failure, const shared_ptr<void>& context) { auto loadPromise = static_cast<promise<vector<shared_ptr<mip::TemplateDescriptor>>>*>(context.get()); loadPromise->set_exception(Failure); };
Optionally, use Ctrl+Shift+B (Build Solution) to run a test compile and link of your solution to verify that it builds successfully before continuing.
Implement an authentication delegate and a consent delegate
The MIP SDK implements authentication through class extensibility, which provides a mechanism to share authentication work with the client application. The client must acquire a suitable OAuth2 access token and provide it to the MIP SDK at runtime.
Create an implementation for an authentication delegate by extending the SDK's mip::AuthDelegate class and overriding/implementing the mip::AuthDelegate::AcquireOAuth2Token() pure virtual function. Follow the steps detailed under File SDK application initialization quickstart. The Protection profile and Protection engine objects instantiate and use the authentication delegate later.
Implement a consent delegate
Now create an implementation for a consent delegate by extending the SDK's mip::ConsentDelegate class and overriding/implementing the mip::AuthDelegate::GetUserConsent() pure virtual function. Follow the steps detailed under File SDK application initialization quickstart. The Protection profile and Protection engine objects instantiate and use the consent delegate later.
Construct a Protection profile and engine
As mentioned, SDK clients that use MIP APIs require profile and engine objects. Complete the coding portion of this quickstart by adding code to instantiate the profile and engine objects:
From Solution Explorer, open the .cpp file in your project that contains the implementation of the
main()method. It defaults to the same name as the project containing it, which you specified during project creation.Remove the generated implementation of
main(). Don't remove preprocessor directives generated by Visual Studio during project creation (#pragma, #include). Append the following code after any preprocessor directives:
#include "mip/mip_context.h"
#include "auth_delegate.h"
#include "consent_delegate.h"
#include "profile_observer.h"
#include"engine_observer.h"
using std::promise;
using std::future;
using std::make_shared;
using std::shared_ptr;
using std::string;
using std::cout;
using mip::ApplicationInfo;
using mip::ProtectionProfile;
using mip::ProtectionEngine;
int main(){
// Construct/initialize objects required by the application's profile object
// ApplicationInfo object (App ID, name, version)
ApplicationInfo appInfo{"<application-id>",
"<application-name>",
"<application-version>"};
std::shared_ptr<mip::MipConfiguration> mipConfiguration = std::make_shared<mip::MipConfiguration>(appInfo,
"mip_data",
mip::LogLevel::Trace,
false,
mip::CacheStorageType::OnDisk);
std::shared_ptr<mip::MipContext> mMipContext = mip::MipContext::Create(mipConfiguration);
auto profileObserver = make_shared<ProtectionProfileObserver>(); // Observer object
auto authDelegateImpl = make_shared<AuthDelegateImpl>("<application-id>"); // Authentication delegate object (App ID)
auto consentDelegateImpl = make_shared<ConsentDelegateImpl>(); // Consent delegate object
// Construct/initialize profile object
ProtectionProfile::Settings profileSettings(
mMipContext,
mip::CacheStorageType::OnDisk,
consentDelegateImpl,
profileObserver);
// Set up promise/future connection for async profile operations; load profile asynchronously
auto profilePromise = make_shared<promise<shared_ptr<ProtectionProfile>>>();
auto profileFuture = profilePromise->get_future();
try
{
mip::ProtectionProfile::LoadAsync(profileSettings, profilePromise);
}
catch (const std::exception& e)
{
cout << "An exception occurred... are the Settings and ApplicationInfo objects populated correctly?\n\n"
<< e.what() << "'\n";
system("pause");
return 1;
}
auto profile = profileFuture.get();
// Construct/initialize engine object
ProtectionEngine::Settings engineSettings(
mip::Identity("<engine-account>"), // Engine identity (account used for authentication)
authDelegateImpl, // Reference to mip::AuthDelegate implementation
"", // ClientData field
"en-US"); // Locale (default = en-US)
// Set the engineId so it can be cached and reused.
engineSettings.SetEngineId("<engine-account>");
// Set up promise/future connection for async engine operations; add engine to profile asynchronously
auto enginePromise = make_shared<promise<shared_ptr<ProtectionEngine>>>();
auto engineFuture = enginePromise->get_future();
profile->AddEngineAsync(engineSettings, enginePromise);
std::shared_ptr<ProtectionEngine> engine;
try
{
engine = engineFuture.get();
}
catch (const std::exception& e)
{
cout << "An exception occurred... is the access token incorrect/expired?\n\n"
<< e.what() << "'\n";
system("pause");
return 1;
}
// Application shutdown. Null out profile and engine, call ReleaseAllResources();
// Application may crash at shutdown if resources aren't properly released.
engine = nullptr;
profile = nullptr;
mMipContext->ShutDown();
mMipContext = nullptr;
return 0;
}
Replace all placeholder values in the source code that you pasted in by using string constants:
Placeholder Value Example <application-id> The Microsoft Entra Application ID (GUID) assigned to the application that you registered in step #2 of the MIP SDK setup and configuration article. Replace 2 instances. "00001111-aaaa-2222-bbbb-3333cccc4444"<application-name> A user-defined friendly name for your application. It must contain valid ASCII characters (excluding ';') and ideally matches the application name you used in your Microsoft Entra registration. "AppInitialization"<application-version> User-defined version info for your application. It must contain valid ASCII characters (excluding ';'). "1.1.0.0"<engine-account> The account used for the engine's identity. When you authenticate with a user account during token acquisition, it must match this value. "user1@tenant.onmicrosoft.com"<engine-state> User-defined state to associate with the engine. "My App State"Now do a final build of the application and resolve any errors. Your code should build successfully, but doesn't run correctly until you complete the next quickstart. If you run the application, you see output similar to the following. The application constructs the Protection profile and Protection engine successfully, but it doesn't fire the authentication module and you don't have an access token until you complete the next quickstart.
C:\MIP Sample Apps\ProtectionQS\Debug\ProtectionQS.exe (process 8252) exited with code 0. To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stops. Press any key to close this window . . .
Next steps
Now that your initialization code is complete, you're ready for the next quickstart, where you start to experience the MIP Protection SDK.
- Explore the MIP Protection SDK C++ sample on GitHub.


