Unit testing our Visual C++ code with Microsoft Unit Testing Framework

One of the things I love about unit testing (besides all of the well-known benefits) is the ability to test code without writing a tester or test harness application, but I can pretty much leverage what Microsoft have already built for us. Image below depicts an unit test I’ve written for this JNI .NET bridge or adapter to piggy back on existing libraries (adapters) provided by  Mulesoft 

image

More information here

Beware of where you call _CrtDumpMemoryLeaks

The Visual C++ compiler has a myriad of great features to build robust and high-quality software. A good example of this could be _CrtDumpMemoryLeaks function that allows to detect any memory leaks  that has occurred in the debug heap.  There is an entire section on debugging native code here.  The results produced by the function in question here (_CrtDumpMemoryLeaks) can be easily misinterpreted if the call to the function is not made in the right place, but let’s illustrate this with an example

1 #include "stdafx.h" 2 #include <iostream> 3 #include <string> 4 #include <memory> 5 #include <stdlib.h> 6 #include <crtdbg.h> 7 #define _CRTDBG_MAP_ALLOC 8 9 int _tmain(int argc, _TCHAR* argv[]) { 10 11 auto dodgyPtr = new int[5]; // Fail (delete is missing) 12 auto mySmartPtr = std::make_unique<int[]>(512); // Ok in "theory" 13 auto myString = std::string("This my test string"); // Ok in "theory" 14 15 _CrtDumpMemoryLeaks(); 16 17 return 0; 18 } 19

The produced output is and you’ll be like Disappointed smile why? if I’m using smart pointers and handling strings with std:: string class… Yes, I must admit it that I haven’t call delete operator but I knew I was leaking one pointer only but in modern C++ this should not happen!!!

1 Detected memory leaks! 2 Dumping objects -> 3 {202} normal block at 0x01046E08, 32 bytes long. 4 Data: <This my test str> 54 68 69 73 20 6D 79 20 74 65 73 74 20 73 74 72 5 {201} normal block at 0x01037748, 8 bytes long. 6 Data: <0 > 30 FB D8 00 00 00 00 00 7 {200} normal block at 0x010465C8, 2048 bytes long. 8 Data: < > 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 9 {199} normal block at 0x010411A8, 20 bytes long. 10 Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 11 Object dump complete. 12 The thread 0x29a4 has exited with code 0 (0x0). 13 The program '[11056] Temp.exe' has exited with code 0 (0x0). 14

Well, reason being is that the string and smart pointers are still “alive” when the call to _CrtDumpMemoryLeaks was made, therefore that memory allocation has not been freed because the destructor of the objects has not been invoked as yet. One of the nicest features in C++ is that the destruction of objects is deterministic, hence objects are destroyed once they go outside of scope. If we make minors changes to the code shown above we would then get a different result which is the correct one.

1 void AllocateMyObjectsInMemory() { 2 auto itemsInArray = 5; 3 auto dodgyPtr = new int[itemsInArray]; // Fail (remember to delete it) 4 auto mySmartPtr = std::make_unique<int[]>(512); // Ok 5 auto myString = std::string("This my test string"); // Ok 6 7 std::cout << "How many bytes am I leaking? " << 8 sizeof(int) * itemsInArray << std::endl; 9 } 10 11 int _tmain(int argc, _TCHAR* argv[]) { 12 13 AllocateMyObjectsInMemory(); 14 15 _CrtDumpMemoryLeaks(); 16 17 return 0; 18 } 19

And the newly produced output is accurate

1 Detected memory leaks! 2 Dumping objects -> 3 {199} normal block at 0x006311A8, 20 bytes long. 4 Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 5 Object dump complete. 6 The thread 0x1540 has exited with code 0 (0x0). 7 The program '[4632] Temp.exe' has exited with code 0 (0x0).

Why am I leaking 20 bytes? Well, an integer is 4 bytes * 5 (number of items in array)

image

Visual Studio also provides us with memory windows that allow us to view into the application’s memory space and it’s very useful when debugging

image

Easy and convenient way to convert Wide Characters to Multibyte with modern C++

One  of the most common tasks we developers have to do comes in the form of data conversion. A good example would be converting  void* (equivalent of Object in .NET) to a specific pointer of a different class through reinterpret_cast, this is however one example. Today’s post is about converting strings as Wide Characters to Multibyte using modern C++.

By modern C++, I mean using smart pointers instead of naked or raw pointers, string class and since it’s a functionality that will be used in different sections of code, it could be in the form of a function template or lambda, in this case, I’ll use a lambda as shown below

1 auto ConvertWstringToChar = [=](std::wstring& original) -> std::string { 2 std::string retval; 3 size_t cntConverted; 4 5 if (!original.empty()) { 6 wcstombs_s(&cntConverted, nullptr, NULL, original.c_str(), 7 original.size()); 8 9 auto buffer = std::make_unique<char[]>(cntConverted); 10 11 memset(buffer.get(), ' ', original.size()); 12 13 wcstombs_s(&cntConverted, buffer.get(), strlen(buffer.get()) + 1, 14 original.c_str(), original.size()); 15 16 retval.append(buffer.get()); 17 } 18 19 return retval; 20 }; 21 22 std::wstring test(L"This is my very funky string!!!!"); 23 auto converted = ConvertWstringToChar(test); 24 }

Some tools that every Visual C++ / .NET developer should have in their toolbox

Hi Community,

This post is about some of the tools I use when building stuff or diagnosing misbehaving applications, so I thought it’d come handy to have them, or learn about them [in case you don’t know them]

Regards,

Angel

Native Windows Service Example

Hi Community,

This blog post describes and explains the steps required to build a native Windows Service. One of the projects I’m currently working on is about a metadata filesystem for Windows (Similar to what WinFS was supposed to be but different in many aspects, mainly because users will have a greater level of customization and it will be template driven). One of the artefacts required (besides Minifilter driver and managed .NET assemblies it’s in the form of a Windows Service).

Building Windows Service in .NET is pretty straightforward, mainly because the project template in Visual Studio does pretty much all of the scaffolding for developers, however, in native code using Visual C++ that template is completely missing and it’s up to developers to do it by themselves.

In my use scenario, the rationale for having a Windows Service is to interact with Minifilter driver. Please bear in mind, most of the stuff we developers build run in User mode and drivers and such do it in Kernel mode, thus the need of having a Windows Service. User and Kernel mode are isolated one from the other, but there are ways to exchange information between the two (if required).

image

The source code for Windows Service is below (please disregard InitializeClr method).

1 #include "stdafx.h" 2 3 // Global variables 4 SERVICE_STATUS g_SvcStatus = {0}; 5 SERVICE_STATUS_HANDLE g_svcHandle = NULL; 6 HANDLE g_filterEventHandle = INVALID_HANDLE_VALUE; 7 HANDLE g_svcStopNotification = INVALID_HANDLE_VALUE; 8 9 10 11 12 /// <summary> 13 /// _tmains the specified argc. 14 /// </summary> 15 /// <param name="argc">The argc.</param> 16 /// <param name="argv">The argv.</param> 17 /// <returns>int.</returns> 18 int _tmain(int argc, _TCHAR* argv[]) { 19 auto retval = 0; 20 21 InitializeClr(); 22 23 SERVICE_TABLE_ENTRY ServiceTable[] = {{SERVICE_NAME, ServiceMain}}; 24 25 if (!StartServiceCtrlDispatcher(ServiceTable)) { 26 WriteEvent(EventInformation(EventType::ERROR_TYPE, L"Unable to start MetaFSAgent Service.")); 27 retval = GetLastError(); 28 } 29 30 return retval; 31 } 32 33 34 /// <summary> 35 /// Services the controller. 36 /// </summary> 37 /// <param name="ctlCode">The control code.</param> 38 VOID WINAPI ServiceController(DWORD ctlCode) { 39 switch (ctlCode) { 40 case SERVICE_CONTROL_STOP: 41 if (g_SvcStatus.dwCurrentState == SERVICE_RUNNING) { 42 ConfigureService(ConfigOption::STOP_SERVICE); 43 if (SetServiceStatus(g_svcHandle, &g_SvcStatus)) { 44 SetEvent(g_filterEventHandle); 45 SetEvent(g_svcStopNotification); 46 WriteEvent(EventInformation(EventType::INFORMATION_TYPE, L"MetaFS Agent Service stopped.\nVersion 1.0.0.0.\n\nChanges made to metadata on existing filesystem objects will not be monitored")); 47 } else WriteEvent(EventInformation(EventType::ERROR_TYPE, L"Unable to change status of MetaFSAgent Service (Stop Pending).")); 48 } 49 break; 50 } 51 } 52 53 /// <summary> 54 /// Services the main. 55 /// </summary> 56 /// <param name="argc">The argc.</param> 57 /// <param name="argv">The argv.</param> 58 VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv) { 59 HANDLE hThread; 60 61 if ((g_svcHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceController)) != NULL) { 62 ConfigureService(ConfigOption::START_SERVICE); 63 if (SetServiceStatus(g_svcHandle, &g_SvcStatus)) { 64 if ((g_svcStopNotification = CreateEvent(NULL, TRUE, FALSE, NULL)) != NULL) { 65 ConfigureService(ConfigOption::RUNNING_SERVICE); 66 if (SetServiceStatus(g_svcHandle, &g_SvcStatus)) { 67 InitializeCommunicationWithDriver(); 68 WriteEvent(EventInformation(EventType::INFORMATION_TYPE, L"MetaFS Agent Service started.\nVersion 1.0.0.0")); 69 hThread = CreateThread(NULL, NULL, AsyncFilterWorker, NULL, NULL, NULL); 70 WaitForSingleObject(hThread, INFINITE); 71 CloseHandle(g_svcStopNotification); 72 ConfigureService(ConfigOption::STOPPED_SERVICE); 73 SetServiceStatus(g_svcHandle, &g_SvcStatus); 74 CloseHandle(hThread); 75 } else WriteEvent(EventInformation(EventType::ERROR_TYPE, L"Unable to change status of MetaFSAgent Service (Running).")); 76 } else { 77 WriteEvent(EventInformation(EventType::ERROR_TYPE, L"Unable to CreateEvent(g_ServiceStopEvent) for MetaFSAgent Service.")); 78 ConfigureService(ConfigOption::STOP_SERVICE); 79 SetServiceStatus(g_svcHandle, &g_SvcStatus); 80 } 81 } else WriteEvent(EventInformation(EventType::ERROR_TYPE, L"Unable to change status of MetaFSAgent Service (Started).")); 82 } else WriteEvent(EventInformation(EventType::ERROR_TYPE, L"Unable to start MetaFSAgent Service.")); 83 } 84 85 /// <summary> 86 /// Asynchronouses the filter worker. 87 /// </summary> 88 /// <param name="lpParam">The lp parameter.</param> 89 /// <returns>DWORD.</returns> 90 DWORD WINAPI AsyncFilterWorker(LPVOID lpParam) { 91 while (WaitForSingleObject(g_svcStopNotification, INFINITE) != WAIT_OBJECT_0) { 92 // Has there been changes to the filesystem? 93 if (WaitForSingleObject(g_filterEventHandle, INFINITE) != WAIT_OBJECT_0) { 94 WriteEvent(EventInformation(EventType::INFORMATION_TYPE, L"Notification from driver...")); 95 SetEvent(g_filterEventHandle); 96 } 97 } 98 return ERROR_SUCCESS; 99 } 100 101 /// <summary> 102 /// Configures the service. 103 /// </summary> 104 /// <param name="option">The option.</param> 105 VOID ConfigureService(ConfigOption option) { 106 switch (option) { 107 case ConfigOption::START_SERVICE: 108 ZeroMemory(&g_SvcStatus, sizeof(g_SvcStatus)); 109 g_SvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 110 g_SvcStatus.dwControlsAccepted = 0; 111 g_SvcStatus.dwCurrentState = SERVICE_START_PENDING; 112 g_SvcStatus.dwWin32ExitCode = 0; 113 g_SvcStatus.dwServiceSpecificExitCode = 0; 114 g_SvcStatus.dwCheckPoint = 0; 115 break; 116 117 case ConfigOption::STOP_SERVICE: 118 g_SvcStatus.dwControlsAccepted = 0; 119 g_SvcStatus.dwCurrentState = SERVICE_STOPPED; 120 g_SvcStatus.dwWin32ExitCode = GetLastError(); 121 g_SvcStatus.dwCheckPoint = 1; 122 break; 123 124 case ConfigOption::RUNNING_SERVICE: 125 g_SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; 126 g_SvcStatus.dwCurrentState = SERVICE_RUNNING; 127 g_SvcStatus.dwWin32ExitCode = 0; 128 g_SvcStatus.dwCheckPoint = 0; 129 break; 130 131 case ConfigOption::STOPPED_SERVICE: 132 g_SvcStatus.dwControlsAccepted = 0; 133 g_SvcStatus.dwCurrentState = SERVICE_STOPPED; 134 g_SvcStatus.dwWin32ExitCode = 0; 135 g_SvcStatus.dwCheckPoint = 3; 136 } 137 } 138 139 /// <summary> 140 /// Initializes the CLR. 141 /// </summary> 142 VOID InitializeClr() { 143 HINSTANCE hInstance; 144 145 SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); 146 147 if ((hInstance = LoadLibraryEx(INTEROP_LIBRARY, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) != NULL) { 148 ptrInitializeClr funcPtr = (ptrInitializeClr)GetProcAddress(hInstance, "InitializeClr"); 149 funcPtr(); 150 } 151 152 SetErrorMode(NULL); 153 154 FreeLibrary(hInstance); 155 } 156 157 /// <summary> 158 /// Initializes communication with driver 159 /// </summary> 160 VOID InitializeCommunicationWithDriver() { 161 HANDLE hFile; 162 DWORD cbSize; 163 164 if ((hFile = CreateFile(TARGET_DRIVER, GENERIC_READ | GENERIC_WRITE, 165 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) { 166 if ((g_filterEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL)) != NULL) { 167 if (DeviceIoControl(hFile, IOCTL_REGISTER_EVENT, &g_filterEventHandle, sizeof(g_filterEventHandle), NULL, NULL, &cbSize, NULL)) 168 WriteEvent(EventInformation(EventType::INFORMATION_TYPE, L"Event successfully created....")); 169 } 170 CloseHandle(hFile); 171 } 172 } 173 174 /// <summary> 175 /// Writes the event. 176 /// </summary> 177 /// <param name="ei">The ei.</param> 178 VOID WriteEvent(const EventInformation& ei) { 179 HANDLE hEventLog; 180 LPWSTR messages[1] = {(WCHAR*)ei.Message.c_str()}; 181 182 if ((hEventLog = OpenEventLog(NULL, L"Application")) != NULL) { 183 ReportEvent(hEventLog, ei.Type, 0x1, 0x1, NULL, 1, NULL, (LPCWSTR*)messages, NULL); 184 CloseEventLog(hEventLog); 185 } 186 }

Regards,

Angel

Interoperability between Java World and Microsoft World by implementing a MSMQ Bridge in Visual C++

 

Hi Community,

As Developers, consultants or architects we always have to face challenges when it comes to integrating to existing systems. This is a bit harder when technologies aren’t from the same vendor. This blog post describes an IPC mechanism I had to implement for an integration project that comprised Microsoft technologies and Java.

The beauty of C++ is that one can virtually build anything with it, and almost every technology or platform provides means to be extended through the use of C++. Java is not exception because it provides JNI that allows running native code from the JVM. This would be the equivalent of the DllImportAttribute in .NET.

MSMQ provides reliable delivery of messages and it also provides a SDK that enables developers to implement queues in their applications, below code snippet to delete a queue

1 2 QueueOpResult CMSMQBridge::DeleteQueue(int nQueueId) { 3 HRESULT ret; 4 QueueOpResult retval; 5 retval.isSuccess = false; 6 wchar_t szFormatName[MAX_PATH]; 7 DWORD cbFormatLength = MAX_PATH; 8 hash_map<int, QueueInformation>::const_iterator found = Queues.find(nQueueId); 9 10 if (Queues.size() > 0 || found != Queues.end()) { 11 auto pathName = found->second.Queuepath.c_str(); 12 auto result = MQPathNameToFormatName(pathName, &szFormatName[0], &cbFormatLength); 13 if (SUCCEEDED((ret = MQDeleteQueue(szFormatName)))) { 14 retval.hr = S_OK; 15 retval.isSuccess = true; 16 Queues.erase(found); 17 } else { 18 CreateFailedQueueOpResult(retval, ret); 19 } 20 } else { 21 retval.isSuccess = false; 22 retval.errMessage = L"Queue is empty or Queue Id wasn't found"; 23 } 24 25 return retval; 26 }

Once we run “DeleteQueue” unit test and set a breakpoint inside the method, we can clearly see that our library is interacting with MSMQ effectively

image

So the way all pieces hang together is as follows:

  • Native Visual C++ Library provides an interface which is consumed from Java through JNI (source code here)
  • Java sends messages to Microsoft application using a queue.
  • .NET application provides classes to interact and use MSMQ (e.g.: MessageQueue class).

And once again, Visual C++ has saved the day Smile

Angel

Building a Visual Studio Add-In To Leverage WinDBG and SOS

 

Hi Community,

I am currently building an Visual Studio add-in to leverage SOS and make it more user friendly, thus I have called it Visual SOS. On this blog post I will describe the main debugging interfaces that are required as well as an artefact called SOS Wrapper which encapsulates the functionality as a native DLL that is invoked from the add-in which is written in C# effectively.

Windows has a built-in debugger engine, and like with every other feature in the  operating system, it also provides means for the developers to build code around it. The debugger engine API is COM based, so every interface required has IUnknown as the base interface.

In Visual SOS, we require to use the following interfaces:

  • IDebugOutputCallbacks:  This interface is called by the engine and it allows to send output from the client to the IDebugOutputCallbacks object that is registered with the client.
  • IDebugEventCallbacks: This interface is called by the engine and it allows to subscribe to events fired by the debugging engine.

The way Visual SOS works is as follows:

  • The entire core functionality is encapsulated in C++ library that exposes a few functions as “extern
  • The add-in code is written in its entirety in C#/.NET but it makes calls to the native library, this is the same approach I took when building Memory Inspector a few years back.
  • Notifications are done using a message sink in the form of a callback or delegate that is passed from managed code to native code, similar to the technique I used and described here

The native functionality lives in SOSWrapper, below its Initialize method

1 void SOSWrapper::Initialize() { 2 if (!m_bIsInitialized) { 3 CoInitialize(NULL); 4 5 if (SUCCEEDED(DebugCreate(__uuidof(IDebugClient), (void**)&m_pDbgClient))) { 6 if (SUCCEEDED(m_pDbgClient->QueryInterface(__uuidof(IDebugControl), (void**)&m_pDbgControl))) { 7 8 // Load extensions 9 std::for_each(m_configReader.Extensions_get().begin(), 10 m_configReader.Extensions_get().end(), 11 [&, this](ExtInformation& item) { m_pDbgControl->AddExtension(item.Path.data(), NULL, &item.pHandle); }); 12 13 m_pDbgClient->SetOutputCallbacks(&m_pOutputCallback); 14 m_pDbgClient->SetEventCallbacks(&m_pEventCallback); 15 16 if (SUCCEEDED(LoadSos())) 17 m_bIsInitialized = TRUE; 18 } 19 } 20 CoUninitialize(); 21 } 22 }

Initialize method

 

Visual SOS  implements a XML-based config file which allows to specify what debugger extensions to load. The way it parses this config file is described here. The implementation of the required debugger engine interfaces are:

1 #include "../../dbghelp/inc/dbgeng.h" 2 3 class EventCallback : public IDebugEventCallbacks { 4 5 private: 6 long m_ref; 7 8 public: 9 EventCallback(); 10 11 ~EventCallback(); 12 13 // IUnknown 14 STDMETHOD_(ULONG, AddRef)(); 15 STDMETHOD_(ULONG, Release)(); 16 STDMETHOD(QueryInterface)(__in REFIID InterfaceId, __out PVOID* Interface); 17 18 // IDebugEventCallbacks 19 STDMETHOD(ExitThread)(__in ULONG ExitCode); 20 STDMETHOD(SessionStatus)(__in ULONG Status); 21 STDMETHOD(ExitProcess)(__in ULONG ExitCode); 22 STDMETHOD(GetInterestMask)(__out PULONG Mask); 23 STDMETHOD(Breakpoint)(__in PDEBUG_BREAKPOINT Bp); 24 STDMETHOD(SystemError)(__in ULONG Error, __in ULONG Level); 25 STDMETHOD(ChangeEngineState)(__in ULONG Flags, __in ULONG64 Argument); 26 STDMETHOD(ChangeSymbolState)(__in ULONG Flags, __in ULONG64 Argument); 27 STDMETHOD(ChangeDebuggeeState)(__in ULONG Flags, __in ULONG64 Argument); 28 STDMETHOD(UnloadModule)(__in_opt PCSTR ImageBaseName, __in ULONG64 BaseOffset); 29 STDMETHOD(Exception)(__in PEXCEPTION_RECORD64 Exception, __in ULONG FirstChance); 30 STDMETHOD(CreateThread)(__in ULONG64 Handle, __in ULONG64 DataOffset, __in ULONG64 StartOffset); 31 STDMETHOD(LoadModule)(__in ULONG64 ImageFileHandle, __in ULONG64 BaseOffset, __in ULONG ModuleSize, 32 __in_opt PCSTR ModuleName, __in_opt PCSTR ImageName, __in ULONG CheckSum, __in ULONG TimeDateStamp); 33 STDMETHOD(CreateProcess)(__in ULONG64 ImageFileHandle, __in ULONG64 Handle, __in ULONG64 BaseOffset, 34 __in ULONG ModuleSize, __in_opt PCSTR ModuleName, __in_opt PCSTR ImageName, __in ULONG CheckSum, 35 __in ULONG TimeDateStamp, __in ULONG64 InitialThreadHandle, __in ULONG64 ThreadDataOffset, 36 __in ULONG64 StartOffset); 37 };

EventCallback.h

1 #include "stdafx.h" 2 #include "EventCallback.h" 3 4 EventCallback::EventCallback() { 5 m_ref = 1; 6 7 } 8 9 EventCallback::~EventCallback() { 10 11 } 12 13 STDMETHODIMP EventCallback::QueryInterface(__in REFIID InterfaceId, __out PVOID* Interface) { 14 *Interface = NULL; 15 if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) || IsEqualIID(InterfaceId, __uuidof(IDebugEventCallbacks))) { 16 *Interface = (IDebugEventCallbacks *)this; 17 InterlockedIncrement(&m_ref); 18 return S_OK; 19 } else { 20 return E_NOINTERFACE; 21 } 22 } 23 24 STDMETHODIMP_(ULONG) EventCallback::AddRef() { 25 return InterlockedIncrement(&m_ref); 26 } 27 28 STDMETHODIMP_(ULONG) EventCallback::Release() { 29 if (InterlockedDecrement(&m_ref) == 0) { 30 delete this; 31 return 0; 32 } 33 return m_ref; 34 } 35 36 37 38 STDMETHODIMP EventCallback::ExitThread(__in ULONG ExitCode) { 39 return S_OK; 40 } 41 42 STDMETHODIMP EventCallback::SessionStatus(__in ULONG Status) { 43 return S_OK; 44 } 45 46 STDMETHODIMP EventCallback::ExitProcess(__in ULONG ExitCode) { 47 return S_OK; 48 } 49 50 STDMETHODIMP EventCallback::GetInterestMask(__out PULONG Mask) { 51 auto retval = S_OK; 52 53 if (Mask != nullptr) 54 *Mask = DEBUG_EVENT_BREAKPOINT; 55 56 return retval; 57 } 58 59 60 STDMETHODIMP EventCallback::Breakpoint(__in PDEBUG_BREAKPOINT Bp) { 61 return DEBUG_STATUS_BREAK; 62 } 63 64 STDMETHODIMP EventCallback::SystemError(__in ULONG Error, __in ULONG Level) { 65 return S_OK; 66 } 67 68 69 STDMETHODIMP EventCallback::ChangeEngineState(__in ULONG Flags, __in ULONG64 Argument) { 70 return S_OK; 71 } 72 73 STDMETHODIMP EventCallback::ChangeSymbolState(__in ULONG Flags, __in ULONG64 Argument) { 74 return S_OK; 75 } 76 77 STDMETHODIMP EventCallback::ChangeDebuggeeState(__in ULONG Flags, __in ULONG64 Argument) { 78 return S_OK; 79 } 80 81 STDMETHODIMP EventCallback::UnloadModule(__in_opt PCSTR ImageBaseName, __in ULONG64 BaseOffset) { 82 return S_OK; 83 } 84 85 STDMETHODIMP EventCallback::Exception(__in PEXCEPTION_RECORD64 Exception, __in ULONG FirstChance) { 86 return S_OK; 87 } 88 89 90 STDMETHODIMP EventCallback::CreateThread(__in ULONG64 Handle, __in ULONG64 DataOffset, __in ULONG64 StartOffset) { 91 return S_OK; 92 } 93 94 STDMETHODIMP EventCallback::LoadModule(__in ULONG64 ImageFileHandle, __in ULONG64 BaseOffset, __in ULONG ModuleSize, 95 __in_opt PCSTR ModuleName, __in_opt PCSTR ImageName, __in ULONG CheckSum, 96 __in ULONG TimeDateStamp) { 97 98 return S_OK; 99 } 100 101 102 STDMETHODIMP EventCallback::CreateProcess(__in ULONG64 ImageFileHandle, __in ULONG64 Handle, __in ULONG64 BaseOffset, 103 __in ULONG ModuleSize, __in_opt PCSTR ModuleName, __in_opt PCSTR ImageName, __in ULONG CheckSum, 104 __in ULONG TimeDateStamp, __in ULONG64 InitialThreadHandle, __in ULONG64 ThreadDataOffset, 105 __in ULONG64 StartOffset) { 106 107 return S_OK; 108 }

EventCallback.cpp

 

In summary, the debugger engine is available and it allows building cool stuff around it. I’ll keep you posted on the development/progress of this add-in, so stay tuned Smile

Angel

Microsoft Visual C++ MVP Award for 2015

Hi community,

It gives me great pleasure to announce that Microsoft has awarded me with an MVP recognition once again in the Visual C++ category. This is my tenth consecutive time as an MVP award recipient. Wow!!! Who woulda have imagined, MVP award recipient for a decade :-) I am thrilled and excited about this, because it is hard to be awarded for the first time even harder to continue being awarded the following years. Before, I continue writing this blog post I would like to thank God and his son Jesus in the first place, Microsoft for valuing and appreciating my time, effort and contributions, Developer community because you are the reason for the MVP program to exist, and by helping you I help myself , hence the insatiable appetite for knowledge and ideas sharing is always there, and last but not least, to my family, my wife and two daughters, thanks for your understanding and patience with me whenever I can’t go out to finish writing or presenting something… Thank-you all!!!

Image (13)

In this opportunity, I will not say or mention how awesome or powerful C++ is because you must know it already, what I would love to do though is to reflect on the past 10 years as an MVP, how the program has helped lots of people (including me) and what lies ahead with native code and C++.

The first time I ever gave a talk was back in 2002 for the Visual FoxPro community in Venezuela, then I started to present for the MUG communities all along Venezuela and South America. To me, communities represented my playground, a place where I could talk in “Geek” language, share experiences with peers and learn, at the same time it helped me to get rid of my introvert-self… Yes, I was an introvert but the need to present helped me overcome it and I became an extrovert.

I was awarded the first time back in January 2006 and I have been an MVP recipient since then. I came to Australia in February 2008 because a consultancy firm based in Sydney CBD found my blog, and they were keen enough to sponsor me, seven years later I can proudly say that I’m Venezuelan-Australian and my children our Australian. Why made me any special back then for this Australian company sponsor me here? My status as an MVP.

To me being an MVP is more important than any recognition, because it is about my contributions towards society as an individual, a good example of this is how my inputs and comments are taken into consideration by the evolution working group of the ISO committee (C++ Language). Some people ask me about whether I get paid by Microsoft or why haven’t I joined Microsoft and similar questions. My answer pretty much is the same… I rather be an independent vendor and/or consultant who enjoys doing research, learning and sharing my experiences. It is more fun, trust me.

I used to spend a lot of time in forums and newsgroups (long before Stackoverflow even existed) and NNTP was the only channel available to seek and provide help. In recent years, I have been the kind of “blogging” dude instead of being in forums, reason being is that like everything in life, it was one stage I had to go through, learn from it and move on. I find blogging more interesting… Heaps more.

I must have been 16 when MIcrosoft released Microsoft C/C++ 7.0 (and it introduced MFC 1.0) and I learned every book available about C and C++. In those days, I also experienced a bit of assembler, even when it was a great learning experience it could have been much better if someone like an MVP was available, but the MVP program was introduced a year later in 1993 and CompuServe was not available in Venezuela either.

20 something years have passed, and I am still passionate about C++ and programming in general like I was back in 1992 (to those wondering about my age, I am 38 years old as I type this – 1976 model, and I have dedicated my life to computers since age 12).

Moving on… What lies ahead for native code and C++… Interesting question, and I will try to be nonbiased on this one. C++ has been evolving since its conception and the language has become better and better, but not only the language itself but the tools. Native code has not gone anywhere, it has always been there (if you have a PC, Mac, Mobile device, etc. whatever the OS is running, it is native). Managed languages are great for RAD and common development tasks, but if you want to have full access to hardware, bare metal and be in control of your program and how it behaves, then native code and C++ is the way to go.

C and C++ were one of the first portable languages (long before any VM, CLR or similar) and they will always be in demand. Mobility is considered by many the new computing wave, and as a developer if you want to make the most of your device battery, well, C++ is the right choice which by the way, in Visual Studio 2015 will allow cross-platform development, so as you can all see. C++ and native code are here to stay.

Once again thank-you all and I look forward to contributing to community this year 2015.

Angel

Handy PowerShell script to crawl file shares and collect information on their structure

 

Hi Community,

I’ve been a bit busy lately (work and family related with the arrival of my second children) but it’s always great to share information with you. A couple of weeks ago, I was working on this engagement to decide whether to move to the cloud or not (It wasn’t a brainer for me taking into consideration the existing technology stack my customer has, but more importantly I needed to collect evidence or facts in order to help them make a decision).

My customer has quite some file shares spread across Windows and multiple NAS. I had to write a PowerShell script (see below) for this task. Personally, I don’t like any scripting language mainly because I expect my code to be compiled, linked besides being able to tweak my code to perform as I want it too, but like I said it’s my personal opinion.

I hope you’ll find it useful.

param([String]$targetServer=“Win2012R2″)

CLS

$shareCount = 0
$startAnalysis = (Get-Date)
$loggedOnUser = Get-WMIObject -class Win32_ComputerSystem | select username

Write-Host “**************************************************************************”
Write-Host “**        File Share Report – Shares on: $targetServer              “
Write-Host “**        Currently logged on as: $loggedOnUser                     ”
Write-Host “**        Analysis start: $startAnalysis”
Write-Host “**************************************************************************”

If (-Not [string]::IsNullOrEmpty($targetServer)) {
 
$existingShares = Get-WmiObject -class Win32_Share -computername $targetServer `
    
-filter “Type=0 And Name Like ‘%[^$]’ And Name <> ‘NETLOGON’ And Name <> ‘SYSVOL'”
    
    
foreach($share in $existingShares) {
       
$results = $null
       
$uncPath = “\\$targetServer\\”+$share.Name
       
       
# Let‘s display information on fileshares on target server (Summary)
        $stats = dir $uncPath -recurse -errorAction “SilentlyContinue” | `
            where {-Not $_.PSIsContainer}| Measure-Object -Property length -Sum
        $results = New-Object -TypeName PSObject -Property @{
                        Computername=$targetServer
                        LocalPath=$share.Path
                        UNCPath=$uncPath
                        SizeKB=[math]::Round(($stats.sum/1KB),2)
                        NumberFiles=$stats.count
            }
       
         $results | Format-Table ComputerName, LocalPath, UNCPath, SizeKB, NumberFiles
        
         # Let’
s display a breakdown on file types and their sizes
        
Get-ChildItem -Path $uncPath -Recurse |
           
Where-Object { !$_.PSIsContainer } |
               
Group-Object Extension |

         Select-Object @{n=“Extension”;e={$_.Name -replace ‘^\.’}}, `
                       
@{n=“Size(MB)”;e={[math]::Round((($_.Group | Measure-Object Length -Sum).Sum / 1MB), 2)}}, 
                      
@{n=“Average Size(MB)”;e={[math]::Round((($_.Group | Measure-Object Length -Average).Average / 1MB), 2)}},
                      
@{n=“Maximum Size (MB)”;e={[math]::Round((($_.Group | Measure-Object Length -Maximum).Maximum / 1MB), 2)}},  #, 
                      
Count | Format-Table
        
        
        
# Let‘s display a breakdown on files in shares by age bucket
         $files=dir $uncPath -recurse |
         Select Fullname, CreationTime, LastWriteTime, Length,
            @{Name=”Age”;Expression={(Get-Date)-$_.LastWriteTime}},
            @{Name=”Days”;Expression={[int]((Get-Date)-$_.LastWriteTime).TotalDays}}
       
         $summary=@{
                Path=$uncPath
                OverAYear = ($files | Where {$_.Days -gt 365} | Measure-Object).Count
                ‘
_365Days‘ = ($files | Where {$_.Days -gt 180 -AND $_.Days -le 365} | Measure-Object).Count
                ‘
_180Days‘ = ($files | Where {$_.Days -gt 90 -AND $_.Days -le 180} | Measure-Object).Count
                ‘
_90Days‘ =  ($files | Where {$_.Days -gt 30 -AND $_.Days -le 90} | Measure-Object).Count
                ‘
_30Days‘ =  ($files | Where {$_.Days -gt 7 -AND $_.Days -le 30} | Measure-Object).Count
                ‘
_7Days‘ =   ($files | Where {$_.Days -gt 0 -AND $_.Days -le 7} | Measure-Object).Count
         }
       
        $ageBucket =  New-Object -TypeName PSObject -Property $summary | Select Path, OverAYear, _365Days, _180Days, _90Days, _30Days, _7Days
       
        [Console]::Write(“`n`r*****************************`nFiles grouped by age (Count)`n*****************************`n`rPath: {0}`nOver a year: {1}`n365 days: {2}`n”, $ageBucket.Path, $ageBucket.OverAYear,  $ageBucket._365Days)
        [Console]::Write(“180 days: {0}`n90 days: {1}`n30 days: {2}`n”, $ageBucket._180Days, $ageBucket._90Days,  $ageBucket._30Days)
        [Console]::Write(“7 days: {0}`n”, $ageBucket._7Days)
       
        $shareCount += 1
       
        Write-Host “——————————————————————————“
     }
    
     $endAnalysis = (Get-Date) – $startAnalysis
     Write-Host “Total Shares: $shareCount”
     Write-Host “Analysis Execution Time: $endAnalysis”
} Else {
   Write-Host “**  targetServer needs to be specified.    **” -ForegroundColor Red

}

 

.NET Crash Dump and live process analysis via clrmd

m4s0n501

Application debugging and analysis can be a daunting task, even more when source code neither symbols are not available. Visual Studio provides developers with powerful debugging capabilities, but the problem many times faced by developers is that Visual Studio is not installed on the target computer Sad smile which is fair enough if it is a production environment.

There are a few tools available, being WinDbg the most powerful and one of my favorite ones. WinDbg allows developers to debug native (in kernel and user mode) and managed code through SOS (Debugging Extension). The options available are more powerful than the ones provided by Visual Studio debugger, however it might not be very user friendly, for the following reasons:

  • Load SOS via CLR or mscorwks (depending on the version of the framework)
  • Type in commands in WinDbg to perform our analysis. These commands are powerful if the developer knows them besides having a good understanding of how the CLR works, the only thing is that many of these commands’ names are very user friendly, as shown below
.load C:WINDOWSMicrosoft.NETFrameworkv2.0.50727sos.dll


!dumpheap -type MyBusinessObject

PDB symbol for mscorwks.dll not loaded

 Address       MT     Size

027437e4 01d6683c       12

02743830 01d6683c       12

0274387c 01d6683c       12

...

02747d6c 01d6683c       12

02747db8 01d6683c       12

02747e04 01d6683c       12

02747e50 01d6683c       12

02747e9c 01d6683c       12

02747ee8 01d6683c       12

total 30 objects

Statistics:

      MT    Count    TotalSize Class Name

01d6683c       30          360 FinalizerProblem.MyBusinessObject

Total 30 objects


!gcroot 02747d6c

Note: Roots found on stacks may be false positives. Run "!help gcroot" for

more info.

Error during command: warning! Extension is using a feature which Visual Studio does not implement.


Scan Thread 7092 OSTHread 1bb4

Scan Thread 6864 OSTHread 1ad0

Finalizer queue:Root:02747d6c(FinalizerProblem.MyBusinessObject)


!finalizequeue

SyncBlocks to be cleaned up: 0

MTA Interfaces to be released: 0

STA Interfaces to be released: 0

----------------------------------

generation 0 has 0 finalizable objects (002906d0->002906d0)

generation 1 has 36 finalizable objects (00290640->002906d0)

generation 2 has 0 finalizable objects (00290640->00290640)

Ready for finalization 69 objects (002906d0->002907e4)

Statistics:

      MT    Count    TotalSize Class Name

7b47f8f8        1           20 System.Windows.Forms.ApplicationContext

...

7910b694       10          160 System.WeakReference

7b47ff4c        4          224 System.Windows.Forms.Control+ControlNativeWindow

01d6683c       22          264 FinalizerProblem.MyBusinessObject

01d65a54        1          332 FinalizerProblem.Form1

7b4827e8        2          336 System.Windows.Forms.Button

7ae78e7c        8          352 System.Drawing.BufferedGraphics

...

Total 105 objects

There is a great article on MSDN on this subject – Debugging Managed Code using the Windows Debugger.

So, WinDbg is very powerful but some developers might not find it user friendly, what options do we have then? Well, good news is that Microsoft has produced and released a library to diagnose and analyze CLR applications, it is called CLrMD (CLR Memory Diagnostics). It is currently in beta and available to download from nuget.

image

Image 1 – Install nuget package

Therefore, I have just built an utility to showcase some of the features in the library. The utility is a WPF C# application which implements the ClrMD library as well as the MVVM pattern. The whole idea is to make developers life easier, by providing an easy to use UI and encapsulate some of the commands in SOS as operations that can be selected on the user interface.

image

Image 2 – Options available in the utility

The utility as of now, provides 3 operations only which are:

  • Dump Heap
  • Heap Stats
  • Threads and StackTrace

These options can be expanded by making changes to the DebuggerOption ViewModel to add a new option, and by implementing the required code in CorDbg.Operations class (Depicted below code for collecting information threads and stack trace information of the attached process.

public ObservableCollection<Thread> GeThreadsAndStackTrace() {

            var retval = new ObservableCollection<Thread>();


            if (Session != null) {

                Session.Runtime.Threads.ToList().ForEach(x => {

                    var newItem = new Thread() {

                        ThreadId = string.Format("{0:X}", x.OSThreadId).Trim(),

                        ThreadExecutionBlock = string.Format("{0:X}", x.Teb).Trim()

                    };


                    x.StackTrace.ToList().ForEach(z => newItem.StackTrace.Add(new StackTrace() {

                        InstructionPtr = string.Format("{0,12:X}", z.InstructionPointer),

                        StackPtr = string.Format("{0,12:X}", z.StackPointer),

                        Method =  (z.Method != null ?  z.Method.GetFullSignature() : string.Empty)

                    }));


                    retval.Add(newItem);

                });

            }


            return retval;


        }

The operation workflow is as follows:

  • Refresh process list – if required (This is if the target application was launched after the utility was running)
  • Select the mode to attach to the target process.
  • Select operation and click on the Go button… That simple!

In this example, the target application was another instance of Visual Studio.

image

Image 3 – Managed Heap Stats

image

Image 4 – Running threads and their stack traces

I hope you’ll find this utility useful, please feel free to download it and extend it.
[office src=”https://onedrive.live.com/embed?cid=2FE1291768841ACE&resid=2FE1291768841ACE!5826&authkey=!ADRH2VtXOaWWuRU” width=”98″ height=”120″”]