twitter

Bonafide Ideas Rss

Featured Posts

Microsoft Visual C++ MVP Award for 2013 G’day Community, Firstly, I’d like to wish you all a happy new year 2013, full of health, blessings & success Secondly, I’m happy to announce that Microsoft has awarded me with an MVP (9th consecutive year) in the Visual C++ category, therefore I’d like to thank God, my daughter, my wife (for all of her patience & understanding),...

Read more

Analysing assemblies and finding out possible leaks... Today’s post is about… A command line utility I wrote a few days back for analysing and finding out possible leaks by not disposing of objects properly. Before we get into the nuts and bolts of the utility, please find attached two files which are: MSIL Instruction Set Specification (Required to do any MSIL manipulation) Utility’s...

Read more

CyberNanny: Remote Access via Distributed Components This article is about an application called CyberNanny, which I recently wrote to allow me to remotely see my baby daughter Miranda at home from anywhere at any time. It’s written in Visual C++ (MFC) and it comprises different technologies such as Kinect and its SDK, Windows Azure, Web services and Office automation via Outlook. The project...

Read more

DDD Sydney - Slide deck Hi community, Please feel free to grab the slides I used at DDD Sydney from here Regards,   Angel

Read more

Developer… Developer… Developer Sydney! Hi Community, I would like to invite you all to “Developer… Developer… Developer Sydney”. This event will be held at UTS on Saturday 30th June 2012. I’ll be presenting “Building Windows 8 applications natively with Visual C++”. I look forward to seeing you there. Best Regards, Angel

Read more

Microsoft Visual C++ MVP Award for 2013

Category : C++, Microsoft, MVP

G’day Community,

Firstly, I’d like to wish you all a happy new year 2013, full of health, blessings & success Smile

Secondly, I’m happy to announce that Microsoft has awarded me with an MVP (9th consecutive year) in the Visual C++ category, therefore I’d like to thank God, my daughter, my wife (for all of her patience & understanding), community & fellow developers,Microsoft and the MVP Program.

I strongly believe in the potential of communities, as well as the opportunity we technical leaders possess  to support people by sharing the knowledge and make them more productive, that’s the main reason why I’m passionate about this program.  I wish this program and MVPs existed when I was 12 years old, and I spent long hours learning to program in GW-BASIC.

My commitment, as usual is to produce material that you community might find relevant and useful.

Once again thank you all!

Best Regards,

Angel

Analysing assemblies and finding out possible leaks by not disposing of objects properly

Category : .NET, Visual C#

Today’s post is about… A command line utility I wrote a few days back for analysing and finding out possible leaks by not disposing of objects properly.

Before we get into the nuts and bolts of the utility, please find attached two files which are:

  1. MSIL Instruction Set Specification (Required to do any MSIL manipulation)
  2. Utility’s Source code

It’s well-known that every single object that implements IDisposable must be disposed by:

  1. Calling the Dispose method explicitly
  2. Enclosing the object that implements IDisposable within an using statement

Said that, let’s have a look at the code snippet shown below

public class LeakyClass {

    public void LeakyMethod() {

        var conn1 = new SqlConnection();

        var conn2 = new SqlConnection();

        conn2.Dispose();

 

        using (var conn3 = new SqlConnection()) {

            // Do something here...

        }

    }

}

This is the generated MSIL from the code snippet

Figure12

 

As you can see, three objects of type SqlConnection are created and two of them are disposed. When enclosing the object within an using statement what really happens is that a try… finally…  block is produced. As you can see the Dispose method is a callvirt which is a “Call to a virtual method” and it’s virtual because it was implemented from the IDisposable interface. MSIL similar to assembler has some Op codes, actually there are 256 (0×100) Op codes being [Dec = 111 | Hex =0x6f] (callvirt) and this is the one we’ll use in our utility.

The way as our utility works is described as follows:

  1. An assembly is loaded for analysis as specified in argument (eg.:  -a "C:\myassembly.dll")
  2. The Inspect method is called which performs the analysis on the modules & types referenced in the assembly
    private static void Inspect(Assembly current) {   

     var flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

     var stats = new Dictionary<string, DisposableStats>();

     current.GetModules().ToList().ForEach(x => x.GetTypes().ToList()

        .ForEach(y => y.GetMethods(flags).ToList().ForEach(z => InspectMethod(x, z))));

    }

  3. The InspectMethod is called only processing the variables (objects) which implement IDisposable
    private static void InspectMethod(Module module, MethodInfo method) { 

      var body = method.GetMethodBody();

     

       if (body != null) {

            var variables = body.LocalVariables;

            var disposable = variables.Where(x => x.LocalType.GetInterfaces()

                             .Where(y => !string.IsNullOrEmpty(y.Name) && 

                                    y.Name.Equals("IDisposable")).FirstOrDefault() != null);

      

            var count = disposable.Count();  

            var key = new MethodDescription(method.ReflectedType.ToString(), method.Name);

     

            if (count > 0 && !stats.ContainsKey(key)) 

                stats.Add(key, IdentifyDisposableObjects(body.GetILAsByteArray(), count, module));    

        }

    }

  4. Then we call IdentifyDisposableObjects method that takes as an argument an array of bytes containing the MSIL of the method. We take into account only callvirt (0x6F) op code.
    private static DisposableStats IdentifyDisposableObjects(byte[] ilasm, int disposable, Module module) { 

        int position = 0, offset = 0, token = 0;

        var retval = new DisposableStats(disposable);

     

        while (position < ilasm.Length) {

            var method = string.Empty;

            var value = ilasm[position++];  

     

            // Is it a callvirt? 

            if (value == 0x6F) {

                offset = position - 1;

                token = ReadInteger(ilasm, ref position);

     

                if ((!string.IsNullOrEmpty(method = module.ResolveMethod(token).Name)) && 

                    method.Equals("Dispose", StringComparison.OrdinalIgnoreCase))

                     retval.DisposedCount++;         

            } 

          }  

      return retval;

    }

  5. We do this for every method in the assembly, and add this information to a dictionary that’s later dumped as a report.

Figure13

If you have a copy of reflector, please feel free to check the results of the report with reflector’s disassembly… You’ll be amazed with the amount of objects that are being left behind and not being disposed.

Regards,

Angel

CyberNanny: Remote Access via Distributed Components

Category : Kinect, Visual C++, Win32

August 2012

This article is about an application called CyberNanny, which I recently wrote to allow me to remotely see my baby daughter Miranda at home from anywhere at any time. It’s written in Visual C++ (MFC) and it comprises different technologies such as Kinect and its SDK, Windows Azure, Web services and Office automation via Outlook. The project is hosted on CodePlex (cybernanny.codeplex.com), where you can check out the code or contribute to it.

Read more

DDD Sydney – Slide deck

Category : Visual C++, Visual Studio, WinRT

Hi community,

Please feel free to grab the slides I used at DDD Sydney from here

Regards,

 

Angel

Developer… Developer… Developer Sydney!

Category : Uncategorized

1581_logo2_63051D71

Hi Community,

I would like to invite you all to “Developer… Developer… Developer Sydney”. This event will be held at UTS on Saturday 30th June 2012. I’ll be presenting “Building Windows 8 applications natively with Visual C++”. I look forward to seeing you there.

Best Regards,

Angel

CyberNanny is on CodePlex

Category : .NET, API, C++, COM, GDI+, Kinect, MFC, Visual C++, Win32

Hi Community,

I would like to share with you all the CyberNanny project that I just published on CodePlex. I’ve submitted an article to MSDN magazine about it but I really don’t know when it’s going to be published, so please feel free to download and/or contribute to the project in the meantime. I will let you know when the article is published. The article describes the bits and pieces of the application in depth as well as the technology aspects of it.The image below depicts CyberNanny’s architecture.

Thanks,

Angel

CyberNanny_Arch

Taking pictures with Kinect & calling GDI+ to reduce the file size

Category : C++, COM, GDI+, Kinect, Visual C++, Win32

Hi Community,

As mentioned in my previous post, I’ve been putting together an application which comprises technologies like Kinect, Windows Azure & Visual C++. The application name is “CyberNanny” and I wrote it for my beautiful newborn daughter Smile. Actually, I’ve submitted today an article to MSDN magazine about the aforementioned solution.

Today’s post is about how we can take pictures with the Kinect sensor and reduce the size of the resulting image file (for emailing purposes).

Let’s assume that we have a smart pointer of type INuiSensor. INuiSensor is the COM representation of the physical sensor. We also have another smart pointer that holds a reference to a custom class called DrawDevice that performs the drawing via Direct2D and  ID2D1Factory

CComPtr<INuiSensor> m_pSensor;

 

std::shared_ptr<DrawDevice> m_pDrawColor;

 


 

void  Nui_Core::TakePicture(std::shared_ptr<BYTE>& imageBytes, int& bytesCount) {

 

    byte *bytes;

 

    NUI_IMAGE_FRAME imageFrame;

 

    NUI_LOCKED_RECT LockedRect;

 


 

    if (SUCCEEDED(m_pSensor->NuiImageStreamGetNextFrame(m_hVideoStream, m_millisecondsToWait, &imageFrame))) {

 

        auto pTexture = imageFrame.pFrameTexture;

 

        pTexture->LockRect(0, &LockedRect, NULL, 0);

 


 

        if (LockedRect.Pitch != 0) {

 

            bytes = static_cast<BYTE *>(LockedRect.pBits);

 

            m_pDrawColor->Draw(bytes, LockedRect.size);

 

        }

 


 

        pTexture->UnlockRect(0);

 

        imageBytes.reset(new BYTE[LockedRect.size]);

 

        memcpy(imageBytes.get(), bytes, LockedRect.size);

 

        bytesCount = LockedRect.size;

 

        m_pSensor->NuiImageStreamReleaseFrame(m_hVideoStream, &imageFrame );

 

    }

 

}

 

Please note that we deal with a pointer to byte (array of bytes) and it’s not a safe practice to return a pointer because the memory address might change and our pointer might point to something else, therefore we pass a smart pointer by reference to store the bytes in it.

The code to handcraft our image (picture)  which is a BMP is shown below

std::wstring ImageFile::SerializeImage(std::shared_ptr<BYTE>& bytes, int byteCount) {

 

    RPC_WSTR guidAsStr;

 

    WCHAR tempPath[MAX_PATH];

 

    std::wstring retval, tempFile;

 

    std::unique_ptr<GUID> guid(new GUID);

 

    CoCreateGuid(guid.get());

 

    UuidToString(guid.get(), &guidAsStr);

 

    auto str = std::wstring((LPTSTR) guidAsStr);

 

    GetTempPath(MAX_PATH, tempPath);

 

    tempFile = std::wstring(tempPath).append(L"photo_").append(str).append(L".bmp");

 

    auto infoHeader = GetBitmapInfoHeader();

 

    auto fileHeader = GetBitmapFileHeader(infoHeader);

 


 

    if (SerializeImageHelper(infoHeader, fileHeader, tempFile, bytes, byteCount)) {

 

        if (RotateImage(tempFile, retval))

 

            m_savedImagePath = retval;

 

    } else retval = L"";

 


 

    return retval;

 

}

 


 

BITMAPINFOHEADER ImageFile::GetBitmapInfoHeader() {

 

    BITMAPINFOHEADER retval = {0};

 


 

    retval.biSize = sizeof(BITMAPINFOHEADER);

 

    retval.biBitCount = 32;

 

    retval.biPlanes = 1;

 

    retval.biCompression = BI_RGB;

 

    retval.biWidth = 640;

 

    retval.biHeight = 480;

 

    retval.biSizeImage = ((((retval.biWidth * retval.biBitCount) + 31) & ~31) >> 3) * retval.biHeight;

 


 

    return retval;

 

}

 


 

BITMAPFILEHEADER ImageFile::GetBitmapFileHeader(const BITMAPINFOHEADER& infoHeader) {

 

    BITMAPFILEHEADER retval = {0};

 


 

    auto nBitsOffset = sizeof(BITMAPFILEHEADER) + infoHeader.biSize;

 

    auto lImageSize = infoHeader.biSizeImage;

 

    auto lFileSize = nBitsOffset + lImageSize;

 

    retval.bfType = 'B'+('M'<<8);

 

    retval.bfOffBits = nBitsOffset;

 

    retval.bfSize = lFileSize;

 


 

    return retval;

 

}

 


 

bool ImageFile::SerializeImageHelper(const BITMAPINFOHEADER& infoHeader, const BITMAPFILEHEADER& fileHeader,

 

                                     std::wstring& filePath, std::shared_ptr<BYTE>& bytes, int byteCount) {

 

    auto retval = false;

 

    auto hFile = CreateFile(filePath.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

 


 

    if (hFile !=  INVALID_HANDLE_VALUE) {

 

        auto newFile = CFile(hFile);

 

        newFile.Write(&fileHeader, sizeof(BITMAPFILEHEADER));

 

        newFile.Write(&infoHeader, sizeof(BITMAPINFOHEADER));

 

        newFile.Write(bytes.get(), byteCount);

 

        newFile.Close();

 

        retval = true;

 

    }

 


 

    return retval;

 

}

 

In order to save our BMP, we must specify two things before serializing the bytes:

Another detail to take into account is, the resulting bitmap is approximately 1.7 MB in size and it’s upside down – This is not very convenient for emailing purposes, so we have to rotate the image 180 degrees and save it with a different format (Encode it), the snippet below shows how we can do this

bool ImageFile::RotateImage(const std::wstring& filePath, std::wstring& newFile) {

 

    CLSID jpgClsid;

 

    newFile = filePath;

 

    auto retval = false;

 

    ULONG_PTR gdiplusToken;

 

    GdiplusStartupInput gdiplusStartupInput;

 

    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

 


 

    if ((retval = GetEncoderClsid(L"image/jpeg", &jpgClsid))) {

 

        auto fileToRotate = new Image(filePath.c_str(), FALSE);

 

        newFile.replace(newFile.find(L"bmp"), 3, L"jpg");

 

        fileToRotate->RotateFlip(Rotate180FlipNone);

 

        fileToRotate->Save(newFile.c_str(), &jpgClsid, NULL);

 

        delete fileToRotate;

 

    }

 


 

    ::DeleteFile(filePath.c_str());

 


 

    GdiplusShutdown(gdiplusToken);

 


 

    return retval;

 

}

 


 

bool ImageFile::GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {

 

    UINT  num = 0;

 

    UINT  size = 0;

 

    auto retval = false;

 


 

    ImageCodecInfo* pImageCodecInfo = NULL;

 


 

    if ((GetImageEncodersSize(&num, &size)) == Status::Ok && (pImageCodecInfo = (ImageCodecInfo*)(malloc(size))) != NULL) {

 

        if (GetImageEncoders(num, size, pImageCodecInfo) == Status::Ok) {

 

            for(auto index = 0; index < num; ++index)  {

 

                if(wcscmp(pImageCodecInfo[index].MimeType, format) == 0 ) {

 

                    *pClsid = pImageCodecInfo[index].Clsid;

 

                    free(pImageCodecInfo);

 

                    pImageCodecInfo = NULL;

 

                    retval = true;

 

                    break;

 

                }

 

            }

 

        }

 

    }

 


 


 

    if (!pImageCodecInfo)

 

        free(pImageCodecInfo);

 


 

    return retval;

 

}

 

 

As you can see, we reduce the file size by saving the image as a JPEG by calling the Save method of the Image class (from 1.7 MB the file size was reduced to 32 KB) and we rotate the image by calling the RotateFlip method of the same class. This functionality is provided by GDI+. It’s important to note that GDI+ needs to be initialized and then shutdown once we’ve finished using it.

Best Regards,

Angel

Tip of the day–An easy & convenient way to create tabs in an MFC application

Category : C++, MFC, Visual C++

Hi Community,

Today I started to write an MFC application that comprises the Kinect sensor and its SDK, and the idea is to have a single UI with different views, this functionality is provided by the CTabCtrl class (Tab control) – I could’ve accomplish this by creating tabs and setting its properties individually but it’s repetitive code that might grow in the future when a new tab is required, so I came up with a convenient way to do this as shown in the snippet below

void MyKinectAppDlg::CreateTabControl() {

 

    auto nIndex = 0;

 

    auto tabs = std::map<std::wstring, TCITEM>();

 

    tabs.insert(std::pair<std::wstring, TCITEM>(L"Color View", TCITEM()));

 

    tabs.insert(std::pair<std::wstring, TCITEM>(L"Depth View", TCITEM()));

 

    tabs.insert(std::pair<std::wstring, TCITEM>(L"Skeletal View", TCITEM()));

 


 

    std::for_each(tabs.begin(), tabs.end(), [&] (std::pair<std::wstring, TCITEM> tab) {

 

        tab.second.mask = TCIF_TEXT;

 

        tab.second.pszText =  (LPWSTR) tab.first.c_str();

 

        m_streamTabs.InsertItem(nIndex++, &tab.second);

 

    });

 

}

 

 

and the tab control created is

image

Happy coding & happy weekend!

Angel

Implementing Office 365 into our WinRT application with Visual C++ (Part I)

Category : C++, Microsoft, Office 365, Visual C++, Windows 8 Developer Preview, WinRT

Hi Community,

The following post is about how we can leverage Office 365 (SharePoint in our case) from our WinRT application. WWSAPI will provide the infrastructure required to interact with the Web Services. There’s a blog post I wrote a couple of years ago on WWSAPI that can be found here. The very first thing we have to be aware of is that SharePoint Online relies on Claims-Based authentication which uses FedAuth cookies that are written with an HTTPOnly flag, said that now you must be wondering, how can we retrieve these cookies then?

Before we start delving into the code, I’d like to mention that most of this functionality is encapsulated in a Win32 DLL that’s consumed from our WinRT application. The main reason for this is that WinRT supports only a subset of Win32 and I’d like this functionality to be available to different clients.

Ok… Back to the task of retrieving the FedAuth cookies, we can accomplish this by calling the InternetGetCookieEx function  as shown in the ReadSharePointCookies method below, please note two things:

  1. The InternetGetCookieEx function accepts as an argument the type of cookie to retrieve
  2. Our function is an exported function which returns an HRESULT (for success/failure) and it returns a map with all of the HTTPOnly cookies.
 1: SPCLIENT_API HRESULT ReadSharePointCookies(map<basic_string<wchar_t>, basic_string<wchar_t>>& cookies) {

 

 2:     auto retval = S_FALSE;

 

 3:     DWORD size = CookieBufferLength;

 

 4:     unique_ptr<wchar_t> buffer(new wchar_t[size]);

 

 5:

 

 6:     if (!InternetGetCookieEx(MicrosoftOnlineUrl, NULL, buffer.get(), &size, INTERNET_COOKIE_HTTPONLY, NULL))  {

 

 7:         if (size > 0) {

 

 8:             buffer.reset();

 

 9:             buffer = unique_ptr<wchar_t>(new wchar_t[size]);

 

 10:             if (InternetGetCookieEx(MicrosoftOnlineUrl, NULL, buffer.get(), &size, INTERNET_COOKIE_HTTPONLY, NULL))  {

 

 11:                 auto cookieStr = basic_string<wchar_t>(buffer.get());

 

 12:                 int next = cookieStr.find_first_of(';');

 

 13:

 

 14:                 while(next != string::npos) {

 

 15:                     auto cookie = cookieStr.substr(0, next);

 

 16:                     cookieStr = cookieStr.erase(0, cookie.length() + 1);

 

 17:                     auto name = cookie.substr(0, cookie.find('='));

 

 18:                     std::remove(name.begin(), name.end(), ' ');

 

 19:                     cookies[name] = cookie;

 

 20:                     next = cookieStr.find_first_of(';');

 

 21:                 }

 

 22:

 

 23:                 retval = S_OK;

 

 24:             }

 

 25:         }

 

 26:     }

 

 27:

 

 28:     return retval;

 

 29: }

 

 

The exported function declaration looks like this

 1: extern "C"

 

 2: {

 

 3:     SPCLIENT_API HRESULT ReadSharePointCookies(map<basic_string<wchar_t>, basic_string<wchar_t>>& cookies);

 

 4: }

 

 

And we do it to prevent name mangling and preserve compatibility with C.  Remember that this is a Win32 DLL consumed from our WinRT application.

For the login process then we leverage/re-use what Office 365 provides us with – A login page

 

image

 

We’re not responsible for the authentication process, but how can we get the cookies after signing in to the site? Well, if you’ve ever used the WebBrowser control (whether it’s WinForms or WPF) then fear not because WinRT provides us with the WebView control, so it’s a pretty straightforward thing to do as shown in the XAML/Code below

 1: <UserControl x:Class="MyMetroSync.Login"

 

 2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

 

 3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

 

 4:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

 

 5:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

 

 6:     mc:Ignorable="d"

 

 7:              d:DesignHeight="768" d:DesignWidth="1366">

 

 8:

 

 9:     <Grid x:Name="LayoutRoot" Background="#FF0C0C0C">

 

 10:         <WebView x:Name="webContent" Margin="27,31,24,36"  LoadCompleted="webContent_LoadCompleted"  />

 

 11:

 

 12:

 

 13:     </Grid>

 

 14: </UserControl>

 

 

 1: void MyMetroSync::Login::webContent_LoadCompleted(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e)

 

 2: {

 

 3:     if (e->Uri->Path->Equals(LandingPage)) {

 

 4:         App::Properties->Insert(CookieName, ReadSharePointCookie());

 

 5:

 

 6:         //Let's call getwebid

 

 7:         auto spHelper = ref new Core();

 

 8:         auto result = spHelper->GetWebId(((IMap<String^, String^>^) App::Properties->Lookup(CookieName)), L"http://bonafideideas.sharepoint.com/_vti_bin/webs.asmx");

 

 9:         App::ShowSplit(nullptr);

 

 10:     }

 

 11: }

 

 

As you can see we got a property bag called Properties to store our cookies and it’s not the same property found in WPF

 1: namespace MyMetroSync

 

 2: {

 

 3:     ref class App

 

 4:     {

 

 5:     private:

 

 6:         static Map<String^, Object^>^ properties;

 

 7:

 

 8:     public:

 

 9:         virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ pArgs);

 

 10:         static void ShowSplit(Expression::Blend::SampleData::SampleDataSource::SampleDataCollection^ collection);

 

 11:         static void ShowLoginPage();

 

 12:

 

 13:         static property Map<String^, Object^>^ Properties {

 

 14:             Map<String^, Object^>^ get();

 

 15:         }

 

 16:     };

 

 17: }

 

But hang on… Where do you retrieve the cookies in your application?

 1: typedef HRESULT (*ptrFun) (map<basic_string<wchar_t>, basic_string<wchar_t>>& cookies);

 

 2:

 

 3: IMap<String^, String^>^ Core::ReadSharePointCookie() {

 

 4:     HRESULT result;

 

 5:     HINSTANCE hInstance;

 

 6:     auto retval = ref new Map<String^, String^>();

 

 7:     auto cookies = map<basic_string<wchar_t>, basic_string<wchar_t>>();

 

 8:

 

 9:     if ((hInstance = LoadPackagedLibrary(SP_HELPER_LIBRARY, 0)) != NULL) {

 

 10:         auto functor = (ptrFun) GetProcAddress(hInstance, "ReadSharePointCookies");

 

 11:

 

 12:         if (functor != nullptr && (functor(cookies)) == S_OK) {

 

 13:             for_each(cookies.begin(), cookies.end(), [&] (pair<basic_string<wchar_t>, basic_string<wchar_t>> cookie) {

 

 14:                 retval->Insert(ref new String(cookie.first.c_str()), ref new String(cookie.second.c_str()));

 

 15:             });

 

 16:         }

 

 17:

 

 18:         FreeLibrary(hInstance);

 

 19:     }

 

 20:

 

 21:     return retval;

 

 22: }

 

Our Win32 DLL must’ve been added to the solution and since every Metro Style application is “packaged” then the application is able to find it without any issues. Another interesting point is the function LoadPackagedLibrary that’s responsible for loading the specified module and its dependencies into the address space of the calling process, then similarly to how it’s done natively, once we have a HINSTANCE to the loaded module, we call GetProcAddress and its return value is cast into a callback to call the desired function (in this case, ReadSharePointCookies).

 

See you soon!

 

Angel

C++ AMP Specification

Category : AMP, C++, Microsoft, Visual C++

Hi Community,

Microsoft just published the “C++ AMP Specification”, please feel free to download it from here.

Cheers,

Angel