Posts

Showing posts from 2011

Translating a Windows Forms custom control from VB.NET to C#

Spanish version / Versión en Español It's not as easy as tossing the code into some translator , copying and pasting. There are some gotchas: After creating the C# project, instead of creating the .cs and .Designer.cs files manually, it's more practical to right-click the project in Visual Studio's Solution Explorer and selecting Add->User Control. This way, the .cs and .Designer.cs are automatically associated. Before editing these two files, open the newly created control in Design view. Open the Toolbox window, and drag and drop any control (a Label, for instance). This will make Visual Studio create a .resx file which will be associated to the control. Once that is done, you can safely delete the control you added in the design view. If the original project has resources, that is, there is also a .resx file at the project level, we need to generate one for our C# project as well. This can be done by going to the project's properties, Resources sect

Traduciendo un custom control de Windows Forms de VB.NET a C#

Versión en inglés / English version No es tan fácil como tirar el código en un traductor , copiar y pegar. Hay ciertos detalles a tener en cuenta, a saber: Una vez creado el nuevo proyecto C#, en vez de crear el .cs y el .Designer.cs a mano, es mejor hacer click derecho al proyecto->Add->User Control. De esta forma, el .cs y el .Designer.cs ya quedan vinculados. Antes de largarse a editar el .cs y el .Designer.cs, abrir el control en vista diseño. Abrir la ventana de Toolbox, agregar un control cualquiera (un Label, por ejemplo) y salvar. Esto generará el .resx del control. Hecho eso, se puede eliminar el control que habíamos agregado. Si el proyecto original usa recursos, o sea que también hay un .resx a nivel proyecto, hay que generar uno. Esto se hace yendo a las propiedades del proyecto, sección Resources. Lo único que veremos será un link que dirá "This project does not contain a default resources file. Click here to create one.". Click allí y listo.

C#: Dispose Pattern

Spanish version / Versión en Español In .NET, the Dispose Pattern... MUST be implemented if our class has references to unmanaged resources. For instance, references to C++/CLI objects which wrap native objects, native memory, etc. MUST be implemented if our class accesses limited resources, even if accessed through managed objects. For example, database connections. MUST be implemented if you wish to use RAII semantics for your class. SHOULD be implemented if your class contains big objects (a Dictionary with lots of keys, for example), and instances are created dynamically and relatively frequently. In this case, the objective is reclaiming memory as soon as possible, to avoid Out of Memory Scenarios due to memory fragmentation. Once we decide to apply the pattern to a class, there are two possibilites. First, if the class is sealed AND it doesn't reference unmanaged resources , we can just override the Dispose Method:: public sealed class A :

Patrón Dispose en C#

Versión en inglés / English version En .NET, el patrón Dispose... DEBE implementarse si nuestra clase manejada mantiene referencias a recursos no manejados. Por ejemplo, clases C++/CLI que funcionan como wrappers de objetos C++ nativos, memoria nativa, etc. DEBE implementarse si nuestra clase debe liberar recursos limitados, incluso si son accedidos a través de objetos manejados. Por ejemplo, conexiones a Bases de Datos. DEBE implementarse si se quiere implementar RAII PUEDE, y DEBERÍA ser implementado si la clase contiene objetos manejados grandes (un Dictionary con muchas claves, por ejemplo), y sus instancias son creadas dinámicamente. En ese caso, implementar IDisposable nos permite usar la instrucción using de C# para acceder con semántica RAII. De esta forma, no sólo se libera la memoria lo antes posible, sino que si ocurre una excepción, la memoria es liberada en el acto. Una vez que decidimos aplicar el pat

MFC: CString and error LNK2019

Spanish version / Versión en Español This error is of the "unresolved external symbol" kind, which can lead us to believe that we misdeclared or forgot to define some function, or we are not linking correctly to some dll. In my particular case, I was using the MFC CString class, which is actually a template class. I was not aware of that. Moreover, its definition changes according to some project options: ATL usage, Character Set, and there might be more. More concretely, I was calling a function from another dll, which had Multi-Byte (ANSI) as its character set, and the calling dll was configured to use Unicode. Therefore, the CString definitions did not match and the error ensued. So the solution consisted of going to the called dll's project Properties, General section, Project Defaults subsection, Character Set combo box, and setting it to Unicode.

MFC: CString y el error LNK2019

Versión en inglés / English version Este error se manifiesta como "unresolved external symbol", lo cual nos puede llevar a pensar que nos falta definir una función, o que no linkeamos correctamente. Lo que ocurría en mi caso era que estaba usando la clase CString, que es un template, cosa que no sabía. Aún más: su definición depende de si se usa ATL o no, o si el proyecto está configurado para usar caracteres Unicode o ANSI. En mi caso particular, estaba llamando a un método de otra dll, configurada con ANSI, desde una configurada con Unicode. Por ende, las definiciones de CString no coincidían, para el compilador eran dos tipos diferentes. Por lo tanto, la solución fue ir a mi proyecto desde el Solution Explorer del Visual Studio, click derecho->Properties->General->Project Defaults->Character Set, y en ese combo box, setear Unicode.

C++: Capture Windows Messages from an MFC app without using MFC

Spanish version / Versión en Español Let's say you need your C++ dll to communicate with a third party dll which uses MFC and Windows Messages to send data and notifications. The easiest way out would be to write an MFC application with a dialog which handled those messages. But let's say your C++ dll is at a very low layer and you don't want GUI code there. At least not openly. Well, there is no avoiding the Windows Messages, so we'll be using, at least, the Win32 unmanaged API. So how do we capture Windows Messages without showing a window? Some basic things you should know first: To capture Windows Messages, you must create a window (associated with a HWND) and use its message loop There is one message loop per thread. This implies that the message-handling window must live in the same thread as the message-generating code A window can be created as a Message-Only window , in MSDN jargon. And that's what we'll do Once I learned all of

C++: Capturar Windows Messages de una aplicación MFC sin usar MFC

Versión en inglés / English version Supongamos que necesitamos que nuestra dll C++ se comunique con una biblioteca externa que use MFC y Windows Messages para enviar datos y notificaciones. La forma más sencilla de establecer esa comunicación sería escribiendo una aplicación MFC con un diálogo (una clase que herede de CDialog) que maneje los mensajes generados por la biblioteca externa. Pero supongamos que nuestra dll C++ está en una capa de bajo nivel y no queremos meter una interfaz de usuario ahí. Al menos, no abiertamente. No hay forma de evitar los Windows Messages, así que tendremos que usar, mínimamente, la API Win32 nativa. Entonces, ¿Cómo capturamos Windows Messages sin mostrar una ventana? Antes de seguir, debemos saber lo siguiente: Para capturar Windows Messages, hay que crear una ventana (asociada a un HWND) y usar su message loop Hay uno y sólo un message loop por thread. Esto implica que la ventana que atrape los mensajes y su message loop deben vivir

RAII in C++

Spanish version / Versión en Español RAII is an acronym which means "Resource Acquisition Is Initialization". And what's it about? It'a low level design pattern, what some call "idiom". Its aim is to ease and ensure resource deallocation. Resources include file handles, bitmaps, data base connections, heap memory, etc. RAII was created by Bjarne Stroustrup, the face of the team which created C++. Even though RAII was born in C++, it's so general that it can be used in any object oriented language with an exception handling mechanism. It can even be implemented in languages which do not meet these requirements, but it is not so trivial and might not be worth the hassle. The idea is quite simple: allocate the resource ONLY in the constructor and deallocate it ONLY in the destructor. Hence the name RAII: When we initialize the object (call the constructor), we acquire the resource. Initialization is acquisition. Acquisition is Initialization. T

RAII en C++

Versión en inglés / English version RAII es un acrónimo que significa "Resource Acquisition Is Initialization". ¿Y de qué se trata? Es un patrón de diseño de bajo nivel, lo que algunos teóricos llaman "idiom". El problema que busca resolver es facilitar y asegurar la liberación de recursos (archivos, bitmaps, conexiones a base de datos, memoria del heap, etc). La creación de RAII corresponde a Bjarne Stroustrup, líder del equipo creador de C++. Pese a haber nacido en ese lenguaje, RAII es tan general que puede usarse fácilmente en cualquier lenguaje orientado a objetos con manejo de excepciones. Incluso puede implementarse en otros lenguajes, pero no es tan trivial y por ende puede no valer la pena. La idea es muy simple: adquirir el recurso SÓLO en el constructor y liberarlo SÓLO en el destructor. De ahí el nombre RAII: al inicializar (construir) el objeto, adquirimos el recurso. Esto ata el uso del recurso a la vida del objeto, y nos evita andar pensa

SQL: Export a SQL Server 2008 DB to SQL Server 2005

Spanish version / Versión en Español Since the 2008 version uses a different format for .bak files, a backup done in 2008 cannot be restored from 2005. A possible workaround is is creating, in 2008, a Script targeted at 2005, and run that scrit in 2005. The steps: Open Managment Studio 2008 and connect to the instance in which the DB we wanna export is. Right click the database, and hit Tasks->Generate Scripts. Hit Next in the initial Dialog. Check "Script all objects in the selected database" before hitting Next. This guarantees that not only the schema is exported, but the contents too. In the next dialog, we have lots of options. The ones we have to set before hitting Next are the following: Script for Server Version : SQL Server 2005. Script Data : True. If the DB to export wasn't created in the 2005 server, which is usually the case, set 'Script Database Create' to 'True'. Select 'Script to File&

SQL: Exportar una Base de Datos de SQL Server 2008 a SQL Server 2005

Versión en inglés / English version Dado que la versión 2008 usa un formato diferente para los .bak, un backup hecho en la versión 2008 no puede ser restaurado desde la 2005. La solución es crear, desde 2008, un Script cuyo target sea la versión 2005 y ejecutar ese script en la instancia del 2005. Para hacerlo: Abrir el Management Studio 2008 donde está la BD que queremos exportar. Darle click derecho a la BD y seleccionar Tasks->Generate Scripts. Darle Next al diálogo inicial. Marcar la checkbox que dice "Script all objects in the selected database" antes de darle Next al diálogo siguiente. Esto garantiza que no sólo se exporte el esquema de tablas sino también su contenido. En el próximo diálogo, hay varias opciones. Las que nos interesa setear antes de darle Next son las siguientes: Script for Server Version : SQL Server 2005. Script Data : True. Si la base de datos a importar aún no existe en el server 2005, hay que poner '

MSBuild: How to develop a Custom Build Task

Spanish version / Versión en Español My problem: When compiling a VB.NET project, I wanted to read a key from a .config file. According to the value of that key, decide which native dll's to copy to the target directory. My solution: First of all, remember that every C#, VB.NET or C++ Visual studio project is an MSBuild script (I guess F# projects too), which is somewhat similar to a Nant build script. It's an XML file with a special schema defined by Microsoft. The XML tags of interest are Target, which are made up mainly of Task tags. In other words, a Target can call Tasks. The .NET framework offers a bunch of predefined MSBuild Tasks, which are documented in the MSDN. However, if those are not enough, we can quite easily write and use our own tasks. An MSBuild custom task must be defined in a dll, which must be referenced from the MSBuidl script which calls it. We'll see how soon. So, the first step is creating a C# project (I guess VB.NET or any other p

MSBuild: Cómo hacer una Custom Build Task

Versión en inglés / English version Mi problema: Al compilar, quería ver el valor de una key de un archivo .config (o sea, con la estructura de los app.config que genera el Visual Studio). En base a ese valor, decidir si copiar o no ciertas dlls. Mi solución: Ante todo, recordemos que todo proyecto C#, VB.NET o C++ del Visual Studio es un script de MSBuild, o sea muy parecido a un .build de NAnt. Está compuesto, entre otras cosas, de Targets, que a su vez consisten en invocaciones de Tasks. En .NET, hay varias Tasks predefinidas, pero si uno quiere escribir una propia, el framework provee un mecanismo para hacerlo. Eso es lo que veremos. Una custom task debe ser definida en una dll, la cual debe ser referenciada desde un script de MSBuild (recordemos que todo archivo de proyecto C#, VB.NET o C++ es un script de MSBuild). Entonces, el primer paso es crear un proyecto de C#, de tipo Class Library. En dicho proyecto, debemos crear una clase que herede de Task y que tenga s

Visual Studio 2010: Find and Replace using Regular Expressions

Image
Spanish version / Versión en Español This is not something introduced by Visual Studio 2010, but I'm a late bloomer. I'm quite sure that at least 2008 and 2005 also have it. Let's say we have a test class which opens a bunch of files, and that it has a lot of hardcoded relative paths like this: class FactoryImage{ public static IEnumerable ImageTestCases{ get{ //9 bits, Signed, Monochrome1 yield return new TestCaseData(new ImageParameters { FileName = ".\\ImagesTest\\DavidClunie\\MONOCHROME1\\Signed\\9SignedMonochrome1_512x512_LE.pix", //Rawdata, example image FileNameWhite = ".\\ImagesTest\\DavidClunie\\MONOCHROME1\\Signed\\9SignedMonochrome1_512x512_LEWhiteImage.pix", //Rawdata, white example image //More fields... }); //9 bits, Unsigned, Monochrome1 yield return new TestCaseData(new ImageParameters{ FileName = ".\\ImagesTest\\Da

Visual Studio 2010: Find and Replace con Expresiones Regulares

Image
Versión en inglés / English version Esto lo tienen versiones anteriores al Visual 2010, pero uso la referencia del 2010, así que aclaro por si las moscas. Supongamos que tenemos una clase de test que abre un conjunto de archivos, y que tiene un montón de paths relativos hardcodeados de esta forma: class FactoryImage{ public static IEnumerable ImageTestCases{ get{ //9 bits, Signed, Monochrome1 yield return new TestCaseData(new ImageParameters { FileName = ".\\ImagesTest\\DavidClunie\\MONOCHROME1\\Signed\\9SignedMonochrome1_512x512_LE.pix", //Rawdata, example image FileNameWhite = ".\\ImagesTest\\DavidClunie\\MONOCHROME1\\Signed\\9SignedMonochrome1_512x512_LEWhiteImage.pix", //Rawdata, white example image //Otros atributos... }); //9 bits, Unsigned, Monochrome1 yield return new TestCaseData(new ImageParameters{ FileName = ".\\ImagesTest\\DavidCluni