Hi community,

I would like to inform you that my new blog is "Bonafide Ideas", so please update your bookmarks. I'm going to keep this one, but everything new will be posted on the new one.

Thanks,

Angel


Hola comunidad,

Me gustaría informarles que my nuevo blog es "Bonafide Ideas", para que por favor actualicen sus favoritos. Seguiré manteniendo este, pero todo lo nuevo será posteado en el nuevo blog.

Gracias,

Angel

Hi community,

I would like to share the following links containing information about the new C++0X standard.

Regards,

Angel


Hola comunidad,

Me gustaría compartir los siguientes enlaces que contienen información acerca del nuevo C++0X estándar.

Saludos,

Angel

Hi community,

I'm happy to announce that Microsoft has awarded me with an MVP (7th consecutive year), in this opportunity in the Visual C++ category, this is something that I’ve been waiting for sometime and got it now.  I would like to thank, God and all of you for your patience and support.  I look forward to deliver  heaps of articles and cool stuff for this new year 2011.

Thanks again,

Angel


Hola comunidad,

Me alegra anunciar que Microsoft me ha concedido nuevamente el reconocimiento de MVP (Séptimo año consecutivo).  En esta oportunidad en la categoría de Visual C++, esto es algo que he estado esperando por algo de tiempo pero que finalmente llegó. Me gustaría agradecer a Dios y a todos ustedes por su apoyo y paciencia. Espero entregar este año montón de artículos y cosas interesantes para este año nuevo 2011.

Gracias nuevamente,

Angel

Hola Comunidad,

Me gustaría invitarlos a que revisen el siguiente enlace:

Este contiene información valiosa para ayudarlos a comenzar a escribir aplicaciones para Windows con C++. Algunos de los tópicos tratados son:

  • Administración de Ventanas (Creación, mensajes, gráficos y más)
  • Entrada de datos
  • COM
  • Desktop Window Manager
  • Direct2D

Saludos,

Angel

Hi Community,

I would like to invite you to check the following link:

It contains valuable information to get you started writing applications in C++ for Windows. Some of the topics covered are:

  • Windows’ Management (Creation, messages, graphics and more)
  • User Input
  • COM
  • Desktop Window Manager
  • Direct2D

Regards,

Angel

alt

Hi Community,

I would like to invite you all to the following Webcast:

I look forward to seeing you there

Regards,

Angel

alt

Hola Comunidad,

Me gustaría invitarlos al siguiente Webcast:

Espero verlos allí

Saludos,

Angel

Hi Community,

I’m still in chilly Melbourne for work commitments, as a matter of fact, I’ve been considering the idea about applying for the “Victorian Citizenship”  (just joking!!!). Even when I’ve been flat out lately, I’ve been spending some time reading every night when I’m back to the hotel, so this post is about some of the books that I’m currently reading and that I would highly recommend you to have on your bookshelves.

Regards,

Angel


Hola Comunidad,

Aún me encuentro en la fría ciudad de Melbourne por compromisos laborales, de hecho, he estado considerando la idea de aplicar por la “Ciudadanía de Victoria”  (Solo estoy bromeando!!!). Sin embargo, a pesar de estar cargado de trabajo y cosas por hacer, he estado leyendo bastante todas las noches cuando regreso al hotel, así que este post es acerca de los libros que leo actualmente y que me gustaría recomendar para sus bibliotecas.

Saludos,

Angel

Hi Community,

This is the first post for  August 2010 and I must say that “This year has flown by” and I’ve been pretty busy in  Melbourne lately. A few days ago my mate and peer Simon Waight flicked me an email about  this very interesting Unit Test Framework for C++ called Isolator++ which in my humble opinion has a lot to offer, a basic code snippet using this framework is shown below

   1: int Product::GetPrice(PricingManager* manager)
   2: {
   3:       if (manager->isOnSale())
   4:             return 5;
   5:       else
   6:             return 10;
   7: }
   8:  
   9:  
  10: bool PricingManager::isOnSale()
  11: {
  12:      return false;
  13: }
  14:  
  15:  
  16: TEST_F(IsolatorTests, GetPrice_OnSaleIsFalse_ExpectHighPrice)
  17: {
  18:      Product product;
  19:      PricingManager* manager =  new PricingManager();
  20:      ASSERT_EQ(10, product.GetPrice(manager));
  21: }
  22:  
  23:  
  24: TEST_F(IsolatorTests, GetPrice_OnSaleIsTrue_ExpectLowPrice)
  25: {
  26:       Product product;
  27:       PricingManager* fakeManager = FAKE(PricingManager);
  28:       WHEN_CALLED(fakeManager->isOnSale()).Return(true);
  29:       ASSERT_EQ(5, product.GetPrice(fakeManager));
  30: }

At the same time, I found this table containing information about some unit testing frameworks currently available for C++.

Regards,

Angel

Hola Comunidad,

Este es el primer post del mes de Agosto 2010 y debo decir “Este año se ha ido volando”, he estado bastante ocupado en la ciudad de Melbourne. Hace unos días atrás mi amigo y colega Simon Waight me envío un correo sobre un marco de trabajo para pruebas unitarias llamado Isolator++ el cual me pareció muy interesante, a continuación un fragmento de código que muestra como usarlo

   1: int Product::GetPrice(PricingManager* manager)
   2: {
   3:       if (manager->isOnSale())
   4:             return 5;
   5:       else
   6:             return 10;
   7: }
   8:  
   9:  
  10: bool PricingManager::isOnSale()
  11: {
  12:      return false;
  13: }
  14:  
  15:  
  16: TEST_F(IsolatorTests, GetPrice_OnSaleIsFalse_ExpectHighPrice)
  17: {
  18:      Product product;
  19:      PricingManager* manager =  new PricingManager();
  20:      ASSERT_EQ(10, product.GetPrice(manager));
  21: }
  22:  
  23:  
  24: TEST_F(IsolatorTests, GetPrice_OnSaleIsTrue_ExpectLowPrice)
  25: {
  26:       Product product;
  27:       PricingManager* fakeManager = FAKE(PricingManager);
  28:       WHEN_CALLED(fakeManager->isOnSale()).Return(true);
  29:       ASSERT_EQ(5, product.GetPrice(fakeManager));
  30: }

Al mismo tiempo conseguí esta tabla que contiene información de algunos marcos de trabajo disponibles para pruebas unitarias con C++

Saludos,

Angel

Hi Community,

In last December, I began working on a framework for creating extensible and dynamic code, without being dependant on the DLR, I called this personal project “Simplicity”, as a matter of fact is mentioned on this post. However, I’m currently engaged on a new project, and I need to implement some mechanism to provide that extensibility. So after searching on the Internet plus some guidance provided by a fellow peer, Nathan Fernandez, I was able to find MEF, which it was precisely what I was looking for. Below you can find some links related to MEF:

Regards,

Angel

Hola Comunidad,

En diciembre del año pasado, comencé a trabajar en un marco de trabajo para crear código extensible, dinámico y sin dependencia del DLR, a este proyecto personal lo llamé “Simplicity”, de hecho lo menciono en este post. Sin embargo, actualmente estoy en un proyecto y necesito utilizar algún marco de trabajo que permita ser extensible. Haciendo algo de investigación en la Internet además de la información provista por mi colega Nathan Fernandez, conseguí a MEF lo cual era lo que necesitaba. A continuación unos enlaces sobre MEF:

Saludos,

Angel

Hi community,

I came back from Melbourne a couple of days ago, to attend and present at DDD Sydney, however, the previous night it was raining heavily and I had to stay at the hotel; so I began to write another demo for my presso and I wrote the  UIInspector, a class that allows to extract information from the children elements within a window  (for instance, a textbox or label). The code snippet is shown below 

   1: public static List<UIElement> GetUIElements(string pidOrImageName) {
   2:             int testPid = 0;
   3:             bool hasData = false;
   4:             string xmlAsString = string.Empty;
   5:             List<UIElement> retval = new List<UIElement>();
   6:             IntPtr uiXml = Marshal.AllocHGlobal(XML_ALLOCATED_BYTES);
   7:             GCHandle pinnedPtr = GCHandle.Alloc(uiXml, GCHandleType.Pinned);
   8:             EnumChildProc enumCallback = new EnumChildProc(EnumChildWindowProcedure);
   9:             GCHandle safeFunctor = GCHandle.Alloc(enumCallback);
  10:             WriteMemory(XML_START, uiXml);
  11:  
  12:             if (int.TryParse(pidOrImageName, out testPid) &&
  13:                 Process.GetProcesses().AsQueryable().Where(x => x.Id.Equals(testPid)).Count() > 0) {
  14:                 using (Process targetProcess = Process.GetProcessById(testPid))
  15:                     EnumChildWindows(targetProcess.MainWindowHandle, (EnumChildProc)safeFunctor.Target, uiXml.ToInt32());
  16:                 hasData = true;
  17:             } else {
  18:                 if (!string.IsNullOrEmpty(pidOrImageName)) {
  19:                     var targetProcess = Process.GetProcessesByName(pidOrImageName).DefaultIfEmpty();
  20:  
  21:                     if (targetProcess.Any()) {
  22:                         EnumChildWindows(targetProcess.First().MainWindowHandle, (EnumChildProc)safeFunctor.Target, uiXml.ToInt32());
  23:                         hasData = true;
  24:                     }
  25:                 }
  26:             }
  27:  
  28:             xmlAsString = Marshal.PtrToStringAnsi(uiXml);
  29:             pinnedPtr.Free();
  30:             safeFunctor.Free();
  31:             Marshal.FreeHGlobal(uiXml);
  32:  
  33:             if (!string.IsNullOrEmpty(xmlAsString) && hasData)
  34:                 retval = ConvertToList(xmlAsString);
  35:  
  36:             return retval;
  37:         }

The aforementioned method, expects to receive a string with a numerical representation (Process Identifier) as well as the name of the process to be inspected. The method returns a List<UIElement> (Struct containing information about the child elements found) which can be filtered through a LINQ query.

The first point of interest in this method is Marshal.AllocHGlobal, which at the same time invokes the VirtualAlloc function, in order to dynamically allocate “these many bytes” in memory (buffer). This is required to avoid  incurring in a potential “C0000005 Exception – Access Violation”, then we have to make use of the GCHandle struct to prevent the GC from moving that memory address, and we do the same with the delegate responsible for enumerating the children elements.

It is well-known that a pointer is just a memory address therefore it’s a number; so it’s not hard to manipulate this memory through pointer arithmetic as shown below:

  • (a_pointer + (a_offset * sizeof(*apointer)))

That formula allows us to write in the following memory address (block) given by a pointer, in “theory” we don’t have pointers in C#, however, there are times where a direct memory mainpulation is required as depicted below

   1: private static void WriteMemory(string stringToWrite, IntPtr memoryAddress) {
   2:     int offset = 0;
   3:  
   4:     if (!string.IsNullOrEmpty(stringToWrite)) {
   5:         stringToWrite.AsEnumerable().ToList().ForEach(x => {
   6:             Marshal.WriteByte(new IntPtr(memoryAddress.ToInt64() + (offset * Marshal.SizeOf(typeof(byte)))), (byte)x);
   7:             offset += 1;
   8:         });
   9:     }
  10: }

The method responsible for extracting information from the children elements is shown below, where a WM_GETTEXT message is sent to the child element based on its hWnd, and its contents is then copied into a buffer that is translated into an Unicode through the Marshal.PtrToStringUni method

   1: private static string GetControlOrWindowText(IntPtr hWnd) {
   2:     string retval = string.Empty;
   3:     IntPtr buffer = Marshal.AllocHGlobal(MAX_TEXT_SIZE);
   4:     SendMessage(hWnd, WM_GETTEXT, new IntPtr(MAX_TEXT_SIZE), buffer);
   5:     retval = Marshal.PtrToStringUni(buffer);
   6:     Marshal.FreeHGlobal(buffer);
   7:  
   8:     return retval;
   9: }

The source code can be fully downloaded from here

Regards,

Angel

Hola comunidad,

Hace un par de días regresé de Melbourne para presentar en DDD Sydney, sin embargo, una noche que me quedé en el hotel porque estaba lloviendo, me pusé a escribir un demo para mi charla y escribí el UIInspector, una clase que permite extraer información de los elementos hijos  de una ventana   (por ejemplo, un cuadro de texto o una etiqueta). A continuación les muestro como funciona

   1: public static List<UIElement> GetUIElements(string pidOrImageName) {
   2:             int testPid = 0;
   3:             bool hasData = false;
   4:             string xmlAsString = string.Empty;
   5:             List<UIElement> retval = new List<UIElement>();
   6:             IntPtr uiXml = Marshal.AllocHGlobal(XML_ALLOCATED_BYTES);
   7:             GCHandle pinnedPtr = GCHandle.Alloc(uiXml, GCHandleType.Pinned);
   8:             EnumChildProc enumCallback = new EnumChildProc(EnumChildWindowProcedure);
   9:             GCHandle safeFunctor = GCHandle.Alloc(enumCallback);
  10:             WriteMemory(XML_START, uiXml);
  11:  
  12:             if (int.TryParse(pidOrImageName, out testPid) &&
  13:                 Process.GetProcesses().AsQueryable().Where(x => x.Id.Equals(testPid)).Count() > 0) {
  14:                 using (Process targetProcess = Process.GetProcessById(testPid))
  15:                     EnumChildWindows(targetProcess.MainWindowHandle, (EnumChildProc)safeFunctor.Target, uiXml.ToInt32());
  16:                 hasData = true;
  17:             } else {
  18:                 if (!string.IsNullOrEmpty(pidOrImageName)) {
  19:                     var targetProcess = Process.GetProcessesByName(pidOrImageName).DefaultIfEmpty();
  20:  
  21:                     if (targetProcess.Any()) {
  22:                         EnumChildWindows(targetProcess.First().MainWindowHandle, (EnumChildProc)safeFunctor.Target, uiXml.ToInt32());
  23:                         hasData = true;
  24:                     }
  25:                 }
  26:             }
  27:  
  28:             xmlAsString = Marshal.PtrToStringAnsi(uiXml);
  29:             pinnedPtr.Free();
  30:             safeFunctor.Free();
  31:             Marshal.FreeHGlobal(uiXml);
  32:  
  33:             if (!string.IsNullOrEmpty(xmlAsString) && hasData)
  34:                 retval = ConvertToList(xmlAsString);
  35:  
  36:             return retval;
  37:         }

El método antes mostrado, espera recibir una cadena con una representación númerica (Identificador del proceso) o el nombre del proceso a inspeccionar, dicho método después retorna una lista de UIElement (Estructura con información del elemento hijo encontrado) la cuál puede filtrarse con una consulta de LINQ.

El primer punto de intéres en dicho método es que usamos el método Marshal.AllocHGlobal que al mismo tiempo llama a la función VirtualAlloc, para así reservar dinámicamente “tantos bytes” de memoria (búfer) para así no incurrir en una posible “excepción C0000005 - Violación de Acceso”, lo siguiente es utilizar la estructura GCHandle para evitar que el GC mueva esa dirección de memoria previamente reservada y haga lo mismo con el delegado que apunta al método responsable por enumerar los elementos (ventanas) hijas.

Como es sabido por todos, un puntero es una dirección en memoria y esta corresponde a un valor númerico; por lo que es válido manipular esa memoria a través de la aritmética de punteros, como mostramos con la siguiente fórmula:

  • (a_pointer + (a_offset * sizeof(*apointer)))

La cual permite escribir en la próxima ubicación de memoria que es dada por un puntero, en C# en “teoría” no se tienen punteros, sin embargo en muchas ocasiones es necesario la manipulación directa de la memoria, como se muestra a continuación

   1: private static void WriteMemory(string stringToWrite, IntPtr memoryAddress) {
   2:     int offset = 0;
   3:  
   4:     if (!string.IsNullOrEmpty(stringToWrite)) {
   5:         stringToWrite.AsEnumerable().ToList().ForEach(x => {
   6:             Marshal.WriteByte(new IntPtr(memoryAddress.ToInt64() + (offset * Marshal.SizeOf(typeof(byte)))), (byte)x);
   7:             offset += 1;
   8:         });
   9:     }
  10: }

El método responsable de extraer el texto de los elementos hijos es el siguiente, en donde se envía un mensaje WM_GETTEXT, y el contenido de dicho elemento es copiado en un  búfer para después convertirla en una cadena Unicode mediante la función Marshal.PtrToStringUni

   1: private static string GetControlOrWindowText(IntPtr hWnd) {
   2:     string retval = string.Empty;
   3:     IntPtr buffer = Marshal.AllocHGlobal(MAX_TEXT_SIZE);
   4:     SendMessage(hWnd, WM_GETTEXT, new IntPtr(MAX_TEXT_SIZE), buffer);
   5:     retval = Marshal.PtrToStringUni(buffer);
   6:     Marshal.FreeHGlobal(buffer);
   7:  
   8:     return retval;
   9: }

El código mostrado se puede descargar completo desde acá

Saludos,

Angel

DDD Sydney

Hi community,

As promised, please find below the slide deck and demos for yesterday’s session

Best regards,

Angel

 


Hola comunidad,

Lo prometido es deuda, por favor siéntanse libres en descargar la presentación y demos de la sesión de ayer

Saludos,

Angel

Hi community,

This post is about a feature that’s available in C++, which sometimes tends to confuse developers. I’m referring to casting operators. These operators complement the old C-style casting operator (provided for backwards compatibility), the C++ standard defines the following operators:

  • static_cast: It’s the most useful cast. It can be used to perform any implicit cast. When an implicit conversion loses some information, some compilers will produce warnings, and static_cast will eliminate these warnings. Making implicit conversion through static_cast is also useful to resolve ambiguity or to clarify the conversion presence. It also can be used to call a unary constructor, declared as explicit. It also can be used to cast up and down a class hierarchy, like dynamic_cast, except that no runtime checking is performed.
  • dynamic_cast: It’s used on polymorphic pointers or references to move up or down a class hierarchy. Note that dynamic_cast performs runtime-checks: if the object's type is not the one expected, it will return NULL during a pointer-cast and throw a std::bad_cast exception during a reference-cast.
  • const_cast: It’s used to apply or remove const or volatile qualifier from a variable.
  • reinterpret_cast: It’s used to perform conversions between unrelated types, like conversion between unrelated pointers (like char* to void*) and references or conversion between an integer and a pointer.

Regards,

Angel

 

Hola comunidad,

El siguiente post es acerca de una característica disponible en  C++, la cual tiende a confundir a muchos desarrolladores. Me refiero a los operadores para realizar conversiones forzadas de tipo (casting). Estos operadores complementan al operador ofrecido y tomado de C (el cuál se mantiene por compatibilidad) sin embargo el C++ standard  define los siguientes operadores:

  • static_cast: Éste es el más útil de los operadores. Puede utilizarse para realizar cualquier conversión forzada de tipo implícita. Cuando una conversión implícita pierde información, algunos compiladores generan advertencias, y static_cast elimina estas advertencias. La conversión implícita a través de dicho operador también es útil para resolver la ambigüedad o hacer evidente la presencia de una conversión forzada de tipo. Se puede utilizar también para invocar un constructor unario que se haya declarado como explicit. Así mismo puede ser utilizado para convertir forzosamente el tipo hacia arriba o abajo de la jerarquí de clases, cómo dynamic_cast, excepto que no hay chequeo en el tiempo de ejecución.
  • dynamic_cast: Es utilizado con punteros polimórficos o refeencias que pueden moverse hacia arriba o abajo en la jerarquía de clases. Éste operador realiza chequeos en tiempo de ejecución: Sí el tipo del objeto no es el esperado, entonces retornará NULL durante una conversión forzada de tipo de punteros y arrojará una excepción de tipo std::bad_cast cuando se aplique a una referencia.
  • const_cast: Es utilizado para eliminar los calificadores const y/o volatile de una variable.
  • reinterpret_cast: Es utilizado para realizar conversiones forzadas de tipo entre tipo de datos que no están relacionados, por ejemplo, conversión de tipo entre punteros no relacionados (como char* a void*) o conversiones entre un entero y un puntero.

Saludos,

Angel

 

logo[2]

Hi community,

I would like to invite you to “Developer… Developer… Developer Sydney”. This event will be held at Microsoft in North Ryde on Saturday, June 17th. I’ll be presenting “Some survival tips & tricks for developers”. I look forward to seeing you there!!!

Regards,

Angel

 


Hola comunidad,

Me gustaría invitarlos al evento “Developer… Developer… Developer Sydney”. El cual se llevará a cabo en las oficinas de Microsoft en North Ryde, el Sábado 17 de Junio. Estaré presentando “Some survival tips & tricks for developers”. Espero verlos allá!!!

Saludos,

 

Angel

Hi Community,

 

Please feel free to download the recording and demos from yesterday's webcast -  "What's new in VS 2010 for C++ developers" . It's in Spanish though [:)] 

 

Regards,

Angel

 


Hola Comunidad,

 

Por favor siéntanse libres de descargar la grabación y demos del webcast de ayer  "Lo nuevo en VS2010 para desarrolladores de C++"

 

 

Saludos,

Angel

 

Hi community,

Today is a public holiday here in Australia because of the ANZAC day celebration, and since I was going to spend my day at home, I decided to write about something that has been through my head for the last week or so. LINQ is a really useful feature that can be used in our applications but it’s “available” to C# and VB.NET only, even when considering to have it in  C++ shouldn’t be “impossible”. At the end of the day, LINQ is supported by Lambda expressions and delegates enabling the creation of expression trees, said that the latest release of C++ supports lambdas and callbacks (delegates), so LINQ support should be in theory possible.

The image shown below has been taken from .NET Reflector and you can see how a LINQ query uses delegates in conjunction with  extension methods

ExecuteLinqQuery

The compiler also generates the required delegates for LINQ support, see the CompilerGenerated attribute

Compiler_Generated_Delegate

Nevertheless, this post is about executing a LINQ query in a .NET assembly from Visual C++. This is accomplished by hosting the CLR in native code and  an  memory mapped file is used as an IPC mechanism, so we can exchange/pass information from managed to native code. Hosting the CLR is not a new thing, but there are some subtle changes for .NET Framework 4.0, many existing functions  (for instance, CorBindToRuntimeEx and CorBindToCurrentRuntime) have been deprecated and now there are some interfaces such as ICLRMetaHost, ICLRRuntimeInfo, ICLRRuntimeHost among others.  Now, the CLRCreateInstance function is required to get an ICLRMetaHost instance which is the starting point for hosting the CLR.

The following  C++ code is responsible for hosting the CLR, creating the memory mapped file, invoking the method which in turns executes the LINQ query and displays the results.

   1: #include "stdafx.h"
   2: #include <metahost.h>
   3: #include <stdio.h>
   4: #include <Windows.h>
   5: #include <stdlib.h>
   6: #include <conio.h>
   7: #include <iostream>
   8: #include <ObjBase.h>
   9: #include <strsafe.h>
  10:  
  11: using namespace std;
  12:  
  13: // Structs
  14: typedef struct _ExecuteArgs {
  15:     LPCWSTR pwzAssemblyPath;
  16:     LPCWSTR pwzTypeName;
  17:     LPCWSTR pwzMethodName;
  18:     LPCWSTR pwzArgument;
  19:     DWORD pReturnValue;
  20: } ExecuteArgs, *PExecuteArgs;
  21:  
  22: // Function prototypes
  23: void LoadAssembly(wchar_t* searchString);
  24: void ReadData(LPVOID lpViewAddress, int cbBytesWritten);
  25: void ExecuteMethod(ICLRRuntimeHost* clrHost, PExecuteArgs args);
  26: BOOL CreateFileMapped(HANDLE& hFileMap, LPVOID& lpViewAddress, wchar_t* fileName);
  27:  
  28: int _tmain(int argc, _TCHAR* argv[])
  29: {
  30:     wchar_t buffer[30];
  31:     wcout << "Enter search string: ";
  32:     wcin.getline(buffer, 30);
  33:     LoadAssembly(buffer);
  34:     wcout << "\n\nPress any key to continue...";
  35:     _getch();
  36:  
  37:     return 0;
  38: }
  39:  
  40: // Method responsible for loading the .NET assembly
  41: void LoadAssembly(wchar_t* searchString) {
  42:     GUID fileNameGuid;
  43:     ExecuteArgs args;
  44:     HANDLE hFileMap = 0;
  45:     LPVOID lpViewAddress = NULL;
  46:     const int fileSize = 0x00100000; 
  47:     LPOLESTR szGUID = new WCHAR [39];
  48:     ICLRMetaHost       *pMetaHost       = NULL;
  49:     ICLRRuntimeInfo       *pRuntimeInfo    = NULL;
  50:     ICLRRuntimeHost    *pRuntimeHost    = NULL;
  51:     wchar_t concatStr[50], parsedStr[100], mappedFileName[60];
  52:     size_t concatStrCb = 0, parsedStrCb = 0, mappedFileStrCb = 0;
  53:  
  54:     CoCreateGuid(&fileNameGuid);
  55:     StringFromGUID2(fileNameGuid, szGUID, 39);
  56:     concatStrCb = sizeof(concatStr) / sizeof(wchar_t);
  57:     parsedStrCb = sizeof(parsedStr) / sizeof(wchar_t);
  58:     mappedFileStrCb = sizeof(mappedFileName) / sizeof(wchar_t);
  59:     StringCchPrintf(mappedFileName, mappedFileStrCb, L"Global\\LinqData%s", &szGUID[1]);
  60:     StringCchCopyN(parsedStr, parsedStrCb, mappedFileName, mappedFileStrCb - 37);
  61:     StringCchPrintf(concatStr, concatStrCb,  L"%s;%s;%u", searchString, parsedStr, fileSize); 
  62:  
  63:     args.pwzAssemblyPath=L"Managed.dll";
  64:     args.pwzTypeName=L"Managed.DataOperations";
  65:     args.pwzMethodName=L"SearchCustomer";
  66:     args.pwzArgument = concatStr;
  67:     args.pReturnValue = 0;
  68:  
  69:     if (CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost) == S_OK) {
  70:         if (pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo) == S_OK) {
  71:             if (pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost) == S_OK) {
  72:                 if (CreateFileMapped(hFileMap, lpViewAddress, parsedStr)) {
  73:                     pRuntimeHost->Start();
  74:                     ExecuteMethod(pRuntimeHost, &args);
  75:                     // Found any data?
  76:                     if (args.pReturnValue > 0) ReadData(lpViewAddress, args.pReturnValue);
  77:                     pRuntimeHost->Stop();
  78:                     UnmapViewOfFile(lpViewAddress);
  79:                 }
  80:                 CloseHandle(hFileMap);
  81:             }
  82:         }
  83:     }
  84:     delete[] szGUID;
  85: }
  86:  
  87: // Method responsible for creating a file mapped into memory
  88: BOOL CreateFileMapped(HANDLE& hFileMap, LPVOID& lpViewAddress, wchar_t* fileName) {
  89:     BOOL retval = FALSE;
  90:  
  91:     hFileMap = CreateFileMapping(NULL, NULL, PAGE_EXECUTE_READWRITE | SEC_COMMIT, 0x00000000, 0x00100000, fileName);
  92:  
  93:     if (GetLastError() == NULL) {
  94:         lpViewAddress = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, NULL, NULL, 0x00100000); 
  95:         retval = GetLastError() == NULL;
  96:     }
  97:     return retval;
  98: }
  99:  
 100: // Method responsible for reading from the mapped file
 101: void ReadData(LPVOID lpViewAddress, int cbBytesWritten) {
 102:     wchar_t* buffer = new wchar_t[cbBytesWritten + 1];
 103:     char* pData = (char*) lpViewAddress;
 104:     buffer[cbBytesWritten] = '\0';
 105:  
 106:     for(int nByte = 0; nByte < cbBytesWritten; nByte++)
 107:         buffer[nByte] = pData[nByte];
 108:  
 109:     wcout << "\n\nThe value returned from .NET is \n\n" << buffer << endl;
 110:  
 111:     delete[] buffer;
 112: }
 113:  
 114: // Method responsible for executing method in hosted assembly
 115: void ExecuteMethod(ICLRRuntimeHost* clrHost, PExecuteArgs args) {
 116:     HRESULT result= clrHost->ExecuteInDefaultAppDomain(args->pwzAssemblyPath, args->pwzTypeName,
 117:         args->pwzMethodName, args->pwzArgument, &args->pReturnValue);
 118: }

 

The following C# code is responsible for executing the LINQ query, opening the memory mapped file that was previously created through the new MemoryMappedFile class which is a wrapper around the CreateFileMapping function. This reminds me of a presentation I had in October last year for DNRTV where I demonstrated how to do it via  Interop with Win32. A point of interest is, that no matter how the memory mapped file was created, it’s possible to access it from native or managed code.

   1: using System;
   2: using System.IO;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Collections.Generic;
   6: using System.IO.MemoryMappedFiles;
   7: using System.Runtime.InteropServices;
   8:  
   9: namespace Managed {
  10:     /// <summary>
  11:     /// 
  12:     /// </summary>
  13:     public class DataOperations {
  14:         #region Methods
  15:  
  16:         /// <summary>
  17:         /// Searches the customer.
  18:         /// </summary>
  19:         /// <param name="value">The value.</param>
  20:         /// <returns></returns>
  21:         public static int SearchCustomer(string value) {
  22:             int retval = 0;
  23:             List<string> args = null;
  24:  
  25:             if (!string.IsNullOrWhiteSpace(value)) {
  26:                 args = value.Split(';').ToList();
  27:                 retval = ExecuteLinqQuery(args[0], args[1], int.Parse(args[2]));
  28:             }
  29:             return retval;
  30:         }
  31:  
  32:         /// <summary>
  33:         /// Executes the linq query.
  34:         /// </summary>
  35:         /// <param name="search">The search.</param>
  36:         /// <param name="mappedFileName">Name of the mapped file.</param>
  37:         /// <param name="fileSize">Size of the file.</param>
  38:         /// <returns></returns>
  39:         private static int ExecuteLinqQuery(string search, string mappedFileName, int fileSize) {
  40:             int nIndex = 0;
  41:             List<Customer> results;
  42:             StringBuilder xmlData = new StringBuilder();
  43:  
  44:             var customerQry = from data in Customer.Customers
  45:                               .Where(match => match.Name.Equals(search, StringComparison.InvariantCultureIgnoreCase))
  46:                               select data;
  47:  
  48:             if ((results = customerQry.ToList()).Count > 0) {
  49:                 xmlData.AppendLine("<?xml version='1.0' encoding='utf-16' ?>");
  50:                 xmlData.AppendLine("<Customers>");
  51:                 results.ForEach(item => xmlData.AppendLine(string.Format("<Customer id='{0}' Name='{1}' Surname='{2}' DateOfBirth='{3}' />",
  52:                                                            new object[] { ++nIndex, item.Name, item.Surname, item.DateOfBirth.ToShortDateString() })));
  53:                 xmlData.AppendLine("</Customers>");
  54:             }
  55:             return WriteToPageFile(xmlData.ToString(), mappedFileName, fileSize);
  56:         }
  57:  
  58:         /// <summary>
  59:         /// Writes to page file.
  60:         /// </summary>
  61:         /// <param name="content">The content.</param>
  62:         /// <param name="mappedFileName">Name of the mapped file.</param>
  63:         /// <param name="fileSize">Size of the file.</param>
  64:         /// <returns></returns>
  65:         private static int WriteToPageFile(string content, string mappedFileName, int fileSize) {
  66:             int retval = content.Length;
  67:  
  68:             using (MemoryMappedFile mappedFile = MemoryMappedFile.OpenExisting(mappedFileName, MemoryMappedFileRights.ReadWrite)) {
  69:                 using (MemoryMappedViewAccessor view = mappedFile.CreateViewAccessor(0, 1048576, MemoryMappedFileAccess.ReadWrite)) {
  70:                     for (int nByte = 0; nByte < retval; nByte++)
  71:                         view.Write(nByte, content[nByte]);
  72:                 }
  73:             }
  74:             return retval;
  75:         }
  76:  
  77:         #endregion
  78:     }
  79:  
  80:     /// <summary>
  81:     /// 
  82:     /// </summary>
  83:     public class Customer {
  84:         #region Properties
  85:  
  86:         /// <summary>
  87:         /// Gets or sets the name.
  88:         /// </summary>
  89:         /// <value>The name.</value>
  90:         public string Name {
  91:             get;
  92:             set;
  93:         }
  94:  
  95:         /// <summary>
  96:         /// Gets or sets the surname.
  97:         /// </summary>
  98:         /// <value>The surname.</value>
  99:         public string Surname {
 100:             get;
 101:             set;
 102:         }
 103:  
 104:         /// <summary>
 105:         /// Gets or sets the date of birth.
 106:         /// </summary>
 107:         /// <value>The date of birth.</value>
 108:         public DateTime DateOfBirth {
 109:             get;
 110:             set;
 111:         }
 112:  
 113:         /// <summary>
 114:         /// Gets the customers.
 115:         /// </summary>
 116:         /// <value>The customers.</value>
 117:         public static IList<Customer> Customers {
 118:             get {
 119:                 return new List<Customer>() {
 120:                     new Customer() { DateOfBirth = new DateTime(1976, 11, 19), Name="Angel", Surname="Hernandez"},
 121:                     new Customer() { DateOfBirth = new DateTime(1980, 5, 20), Name="Jose", Surname="Lopez"},
 122:                     new Customer() { DateOfBirth = new DateTime(1985, 10, 15), Name="Angel", Surname="Martinez"},
 123:                     new Customer() { DateOfBirth = new DateTime(1988, 1, 23), Name="Jesus", Surname="Ramirez"},
 124:                     new Customer() { DateOfBirth = new DateTime(2000, 8, 11), Name="Maria", Surname="Romero"}
 125:                 };
 126:             }
 127:         }
 128:  
 129:         #endregion
 130:     }
 131: }

The image depicted below illustrates a typical implementation of a memory mapped file for exchanging information between processes or as in this post, information between managed and native code.

memory_mapped

 

The image show below corresponds to our running application

Running

 

Regards,

Angel

More Posts Next page »