Posts

Showing posts from 2010

C++: Project always out of date when running in Visual Studio

Spanish version / Versión en Español A little while ago, I ran into a weird problem. My application compiled fine in Visual Studio 2010, but when I tried to Debug it, it would ALWAYS say that a certain C++ project (always the same one) was out of date and asked me if I wanted to build it. But if I had just done so! The first thing you'll want to try is to do a full clean and build of your solution. If after that the problem is still there, try this: Enable logging for C++ projects build. Download, unzip and run DebugView from SysInternals. Those people make great tools, check them out! Add a filter to Debug View using the name of your project. If you don't do this, DebugView will drown you in a sea of log messages. Build again. Take a look at DebugView's log messags. In my case, my error was something like this [42216] Project 'YourCrazyProject.vcxproj' not up to date because build input 'YourWackyReference' is missing. Delete or fix th

C++: Proyecto siempre desactualizado al correr en Visual Studio

Versión en inglés / English version Hace poco me pasó que compilaba mi aplicación exitosamente, pero al correrla el Visual Studio 2010 me decía que cierto proyecto estaba desactualizado y que si quería compilarlo. ¡Pero si acabo de compilarlo, macho! Bueno, la solución es arremangarse y activar los mensajes de log del compilador de C++, algo que los de Mocosoft dejaron bastante oculto. Resumiendo: Probar haciendo un Clean Solution y compilando otra vez. Si eso no resuelve el problema, seguir al paso 2. Activar el logging para la compilación de proyectos C++. Bajar, descomprimir y ejecutar DebugView de, cuándo no, SysInternals. Unos capos. Agregarle un filtro al DebugView con el nombre de nuestro proyecto. Si no hacemos esto, nos ahogaremos en un mar de mensajes. Compilar de nuevo. Buscar un mensaje de este estilo: [42216] Project 'TuProyectoLoco.vcxproj' not up to date because build input 'TuDependenciaColgada' is missing . Borrar o corregir esa

Strong naming and error when compiling in VS2010 and Team City

Spanish version / Versión en Español In Visual Studio 2008, when we added a password-protected strong name to an assembly (a .pfx file), and we wanted to build it in another machine, it would prompt us to enter the password when we tried to build it. In the transition to Visual Studio 2010, everything kept working perfectly. But when we added a new assembly and its .pfx, when we tried to build in another machine, it didn't ask for the password, and failed with this message (key file number is anonymized): Cannot import the following key file: fileName.pfx. The key file may be password protected. To correct this, try to import the certificate again or manually install the certificate to the Strong Name CSP with the following key container name: VS_KEY_xxxxxxxxxxxxxxxx First of all, to fix this in our Visual Studio (and our colleagues'), we must go to project's Properties, then to the Signing Tab. There, in the list box where we select the .pfx, click Browse an

Strong naming y error al compilar en VS2010 y Team City

Versión en inglés / English version En el Visual 2008, cuando le agregábamos un strong name a una assembly, cuando queríamos compilar en otra máquina, al compilar nos pedía el password del archivo .pfx y luego seguía compilando. Al pasar a Visual 2010, todo siguió funcionando perfecto. Pero cuando agregamos una nueva assembly y le agregamos su .pfx, al compilar en otra máquina, no nos pidió el password y además falló la compilación, con el siguiente mensaje (suprimo el número de key file): Cannot import the following key file: nombreArchivoPFX.pfx. The key file may be password protected. To correct this, try to import the certificate again or manually install the certificate to the Strong Name CSP with the following key container name: VS_KEY_xxxxxxxxxxxxxxxx En primer lugar, para arreglar esto en nuestro Visual Studio (y los de nuestros colegas), hay que ir a las propiedades del proyecto, a la sección Signing. Donde referenciamos al .pfx, clickear el combo, darle a Brow

C++: Strange Inheritance scenario: public members with same name

Spanish version / Versión en Español Consider this code: #include <iostream> #include <string> using namespace std; class Grandpa{ public: Grandpa() : m_BothersomeField("Grandpa") {} virtual ~Grandpa(){} string m_BothersomeField; }; class Son: public Grandpa{ public: Son() : m_BothersomeField("Son") {} virtual ~Son(){} string m_BothersomeField; }; class Grandson: public Son{ public: Grandson(){} virtual ~Grandson(){} }; int main(){ Grandson n; cout << "Grandson, no disambiguation: " << n.m_BothersomeField << endl; cout << "Grandson, with disambiguation (Son): " << n.Son::m_BothersomeField << endl; cout << "Grandson, with disambiguation (Grandpa): " << n.Grandson::m_BothersomeField << endl; return 0; } Let's ignore for a while the fact that we have public fields (breaking enc

C++: Herencia y miembros públicos con mismo nombre

Versión en inglés / English version Consideren este ejemplo: #include <iostream> #include <string> using namespace std; class Abuelo{ public: Abuelo() : m_AtributoJodido("Abuelo") {} virtual ~Abuelo(){} string m_AtributoJodido; }; class Hijo: public Abuelo{ public: Hijo() : m_AtributoJodido("Hijo") {} virtual ~Hijo(){} string m_AtributoJodido; }; class Nieto: public Hijo{ public: Nieto(){} virtual ~Nieto(){} }; int main(){ Nieto n; cout << "Nieto, sin desambiguar: " << n.m_AtributoJodido << endl; cout << "Nieto, desambiguado a Hijo: " << n.Hijo::m_AtributoJodido << endl; cout << "Nieto, desambiguado a Abuelo: " << n.Abuelo::m_AtributoJodido << endl; return 0; } Ignoremos momentáneamente el hecho de que hay atributos públicos (se viola el encapsulamiento). Supongamos, a efectos p

C++/CLI strong named assemblies in Visual Studio 2010

Spanish version / Versión en Español In a previous post, we saw how to give a C++/CLI assembly a strong name in Visual Studio 2008. On VS 2010, this doesn't work quite the same way; a fix is meant to come in a future service pack. Meanwhile, the new way to do this is as follows: In Solution Explorer, right-click the project, then go to Properties->Linker->Advanced->Key File, and select the .snk file generated with sn.exe. In the same place (Linker->Advanced), set the Delay Sign property to Yes . Add the following Post Build Event to the project: sn -R <dll> <key file> To achieve the previous, some macros sus as $(ProjectDir) are useful. Use as needed. In my case, the post build event ended up being this:: "$(FrameworkSDKRoot)"bin\sn -R $(SolutionDir)Debug\NombreDLL.dll $(ProjectDir)NombreDLL.snk I used the SolutionDir macro because in my particular project, the compiled dll is saved to the solution's Debug folder (for

Strong named assemblies C++/CLI en Visual Studio 2010

Versión en inglés / English version En un post anterior vimos cómo darle un strong name a una assembly C++/CLI en el Visual Studio 2008. En el 2010, esto no funciona del todo bien; se dice que saldrá un fix pertinente en un futuro service pack. Mientras tanto, la nueva forma de hacer esto es la siguiente: En el Solution Explorer, click derecho al proyecto->Propiedades->Linker->Advanced->Key File, y hacer que apunte al archivo .snk que generamos con el programita sn.exe del SDK de Windows. En el mismo lugar (Linker->Advanced), setear la propiedad Delay Sign a Yes . Agregarle al proyecto un Post Build Event de la forma: sn -R <dll> <key file> Para hacer lo anterior, son útiles macros como $(ProjectDir). Usar las necesarias. En mi caso, el post build event quedó así: "$(FrameworkSDKRoot)"bin\sn -R $(SolutionDir)Debug\NombreDLL.dll $(ProjectDir)NombreDLL.snk Usé la macro SolutionDir porque este proyecto en particular guarda la

Strong named assemblies in VB.NET y C++/CLI, C#

Spanish version / Versión en Español What's the use of having "strong named assemblies"? A strong name is unique. Therefore, if an assembly has a unique name, all types defined in it have a unique name as well. Assemblies without strong naming can only be found by the CLR if they are placed in the same directory as the referencing assembly or in special directories (like System32 or any other referenced by the PATH environment variable). A strong named assembly offers more possibilities (more on that in future posts). When an assembly is sought during runtime, its Name, Culture and Public Key Token are compared to see if there is a successful match. The assembly's version number is only taken into account in the comparison when the assembly has a strong name. This eases DLL Hell and encourages using version numbers for dlls. So that FxCop doesn't complain :P At least in Visual Studio 2008 is quite easy to have a VB.NET or C# class library

Strong named assemblies en VB.NET, C# y C++/CLI

Versión en inglés / English version ¿De qué sirve tener "strong named assemblies"? Un "strong name" es único. Así, si una assembly tiene nombre único, todos los tipos definidos en ella tienen nombre único también. Las assemblies con nombre débil sólo pueden ser encontradas si se las coloca en el directorio de la aplicación o en subdirectorios especiales (como System32). Las assemblies con nombre fuerte tienen más posibilidades (más sobre eso en próximos posts). Cuando se busca una dll en tiempo de ejecución, se comparan Nombre, Cultura y Public Key Token. El número de versión sólo se considera cuando la dll buscada es strongly named. Esto busca resolver el DLL Hell y proveer un sistema de versionado más sólido. Si la versión buscada no coincide, la dll no se carga. Para que el FxCop y sus amigos no rompan los quinotos :P Al menos en el Visual Studio 2008 es muy fácil hacer que un proyecto de VB.NET o C# genere una assembly con nombre fuerte

VB.NET: Raise base class events from a derived class

Spanish version / Versión en Español Say we: Have a class we want to divide into subclasses The future base class has events The refactoring leads us to the need of raising an event declared in the base class, from a derived class. When we try to do point 3, we will get a compile error saying that a derived class cannot raise events from a base class. To get around this, we add a protected method in the base class which encapsulates the RaiseEvent call, and call that method from the derived class using MyBase. This way: In the base class (parameters as needed): Protected Overridable Sub OnMessageGenerated(ByVal NewSender As Object, ByVal NewMessage As String) RaiseEvent MessageGenerated(NewSender, New MessageEventArgs(NewMessage)) End Sub And in the derived class: 'Do stuff 'Raise base class event MyBase.OnMessageGenerated( Me, "Message" ) 'Do more stuff... References: Mark Gilbert post

VB.NET: Lanzar eventos de la clase base desde una clase derivada

Versión en inglés / English version Supongamos que: Tenemos una clase que queremos desdoblar en subclases La futura clase base tiene eventos El refactoring nos lleva a la necesidad de que desde una clase derivada haya que hacer un RaiseEvent de un evento de la clase base. Cuando intentemos hacer lo indicado en el punto 3, nos surgirá un error de compilación diciendo que una clase derivada no puede lanzar eventos de la clase base. Para resolver esto, agregamos un método protected en la clase base que encapsule el RaiseEvent de marras, y en la clase derivada lo invocamos usando MyBase. Así: En la clase base (Los parámetros son a gusto nuestro): Protected Overridable Sub OnMessageGenerated(ByVal NewSender As Object, ByVal NewMessage As String) RaiseEvent MessageGenerated(NewSender, New MessageEventArgs(NewMessage)) End Sub Y en la clase derivada 'Hacer cosas... 'Quiero lanzar el evento de la clase base MyBase.OnMessageGenerated( Me, "Message" ) &

VB.NET: DoubleClick event for a Button

Spanish version / Versión en Español It's not everyday that you need to handle a double click event for a Button, but I happened to stumble upon a case. Suppose you have a Grid where the icons are buttons (in my case, those were image thumbnails, and so I intended to have the user double click a thumbnail in order to load the associated image). That led me to the need of handling the double click event for those Buttons. Now, .NET exposes the DoubleClick event for a Button, but it doesn't get fired for some obscure reason (Defined as a no-op?). Therefore, a workaround is to handle the more general MouseDown event instead, and consider the case where two clicks where made: Private Sub Button1_MouseDown(ByVal sender As System.Object, _ ByVal e As System.Windows.Forms.MouseEventArgs) _ Handles Button1.MouseDown If e.Clicks = 2 Then MessageBox.Show("The button was double-clicked.") End If End Sub

VB.NET: Evento DoubleClick para un Button

Versión en inglés / English version No es normal tener que manejar un doble click para un Button, pero yo me topé con un caso donde es necesario. Supongan que tienen una Grid donde los íconos son Buttons (en mi caso, eran thumbnails de Imágenes, y quería hacer que con doble click se seleccionara la Imagen correspondiente al thumbnail). Eso me llevó a la necesidad de manejar el doble click para un Button. Ahora bien, .NET ofrece el evento DoubleClick pero no se dispara. Lo que hacemos entonces es manejar MouseDown y considerar el caso particular en que se hicieron dos clicks: Private Sub Button1_MouseDown(ByVal sender As System.Object, _ ByVal e As System.Windows.Forms.MouseEventArgs) _ Handles Button1.MouseDown If e.Clicks = 2 Then MessageBox.Show("The button was double-clicked.") End If End Sub Referencias: MSDN Forum

.NET: Leak in Windows Forms

Spanish version / Versión en Español Consider this Windows Forms code: int i, j; for (i = 0; i < 150; i++) { for (j = 0; j < 200; j++) { this.Controls.Add(new Button()); } this.Text = String.Format("i={0}", i); this.Controls.Clear(); } You might need to change 150 and 200 to larger values for your system, but this code should eventually crash saying something like "Cannot create window handle". This is because the Clear() call does not instanltly release the Buttons. The GC should eventually do it, but he fails to do it on time. What's the cause for this? First of all, consider that Windows Forms is built on top of the Win32 API, so there is a message pump behind. Second, consider that in Win32, a window handle or any other graphic resource can only be destroyed by the thread who created it. Therefore, when the GC wants to destroy a Button, he must dispatch the call to the GUI thread. And he does it via the messag

.NET: Leak en Windows Forms

Versión en inglés / English version Consideremos este código dentro de un Form: int i, j; for (i = 0; i < 150; i++) { for (j = 0; j < 200; j++) { this.Controls.Add(new Button()); } this.Text = String.Format("i={0}", i); this.Controls.Clear(); } Tal vez haya que cambiar 150 y 200 por algo más grande en tu sistema, pero eventualmente esto explotará diciendo algo del estilo "Cannot create window handle". Esto es porque el Clear() no libera instantáneamente los botones; el GC debería hacerlo eventualmente, pero parece que no llega a tiempo. ¿A qué se debe esto? En primer lugar, debemos considerar que Windows Forms está montado sobre la API de Win32, así que detrás de esto hay un bucle donde se procesan mensajes (message pump). En segundo lugar, debemos considerar que en Win32, una ventana sólo puede ser destruida por el mismo thread que la creó. Por lo tanto, el Garbage Collector, al destruir los controles, debe despachar

C++/CLI: Destructors VS Finalizers

Spanish version / Versión en Español Even though in C# destructor and finalizer are the same thing because C# is garbage collected, in C++/CLI things are quite different. This is because C++/CLI has both deterministic (destructors) and non deterministic destruction (finalizers). Destructors are deterministically invoked when an object created on the managed stack goes out of scope; on the other hand, finalizers are called by .NET's Garbage Collector when its heuristic says so. That is why it's called non-deterministic destruction. La sintaxis: //This generates C4251 public ref class A(){ //Fields public: A(); ~A(); //Destructor !A(); //Finalizer void f(); } The destructor is automatically called when an instance of A created on the managed stack (without using gcnew/new/New) goes out of scope, and also when the Dispose method is called on an instance created on the managed heap (gcnew/New). This is because the C++/CLI compiler maps the destr

C++/CLI: Destructores VS Finalizers

Versión en inglés / English version Aunque en C# estas dos palabras representan lo mismo, dado que C# es un lenguaje con recolección de basura, en C++/CLI la cosa es muy diferente. Esto se debe a que dicho lenguaje tiene tanto destrucción determinística (destructores) como no determinística (finalizers). Los destructores son invocados determinísticamente al irse de scope el objeto; por otro lado, los finalizers son invocados por el recolector de basura de .NET cuando su heurística lo indique. Es por ello que dicha destrucción se denomina "no deterministica." La sintaxis: //Esto genera C4251 public ref class A(){ //Atributos public: A(); ~A(); //Destructor !A(); //Finalizer void f(); } El destructor es invocado cuando una instancia de A creada en el managed stack (o sea, sin usar gcnew/New/new) se va de scope, y cuando se invoca Dispose sobre una instancia creada en managed heap. Esto último es porque el compilador de C++/CLI mapea el dest

C++/CLI: Convert a String to BSTR or some other nasty stuff

Spanish version / Versión en Español This is very usual when replacing a COM interface with a C++/CLI wrapper (Guess who's doing that?). That usually leads to the need to convert a .NET string (System::String^) to a BSTR, or a std::string. Luckily, .NET provides some handy conversion functions for this. They save us the hassle of creating buffers, releasing them and whatnot. Among them are the marshal_as functions and the marshal_context class. Here's the lowdown for when to use which: Overview of Marshalling in C++

C++/CLI: Transformar un String a BSTR u otras cochinadas

Versión en inglés / English version Esto es muy común cuando uno quiere reemplazar una interfaz COM por una C++/CLI. Esto típicamente requiere convertir System::String^ a BSTR, std::string y otras yerbas. Por suerte, .NET nos provee una solución que nos evita andar copiando cosas a buffers y viendo cuándo las liberamos: El método marshal_as y la clase marshal_context. Acá está el detalle de qué usar para cada conversión: Overview of Marshalling in C++

C++: Warning C4251: Templates in exported classes

Spanish version / Versión en Español Say you have a template, be it from the STL or custom, as a field in a class which is __declspec(dllexport)'ed, you'll get this warning. The problem is that we're trying to export the template's declaration without its definition. This can make our program crash in runtime if we combine binaries which use different versions of the STL or our template. This could happen if we used dll's compiled with different versions of Visual Studio. If you can't (or you're lazy) refactor your code in order not to export the class (you should only export interfaces), what you can do is export not the whole class but only the public methods which are used from other assemblies. Generically, if we have... //This generates C4251 class __declspec(dllexport) A(){ public: A(); virtual ~A(); void f(); private: std::vector<int> m_vGeneratesC4251; } ... and this dll's client assembly only needs to access f

C++: Warning C4251: Templates en clases exportadas

Versión en inglés / English version Si uno tiene un template, sea de la STL o propio, como atributo en una clase exportada con __declspec(dllexport), nos salta este warning. El problema reside en que estamos exportando la declaración del template, sin su definición. Esto puede hacer que nuestro programa explote en tiempo de ejecución si combinamos binarios con diferentes versiones de la STL o de nuestro template. Esto puede ocurrir si usamos dll's compiladas con diferentes versiones del Visual Studio. Si no podemos (o nos da fiaca) hacer refactoring para no exponer atributos en una clase exportada (idealmente, sólo deberíamos exportar interfaces), lo que podemos hacer es exportar no toda la clase sino sólo los métodos que se usan afuera. De forma genérica, si tenemos... //Esto genera C4251 class __declspec(dllexport) A(){ public: A(); virtual ~A(); void f(); private: std::vector<int> m_vGeneraC4251; } ... y el cliente de esta dll sólo necesita ac

C++: Parse input skipping whitespace

Spanish version / Versión en Español Still re-reading Stroustrup's book , I found something I'd like to have known some time ago: an elegant way to parse an input stream for words separated by whitespace (1 whitespace = any amount of consecutive space and/or tabs). This can be done using an istream_iterator, like so: #include <fstream> #include <iostream> #include <algorithm> #include <vector> void main(){ using std::cout; using std::endl; // We read from standard input, but it could just as well be a file std::istream_iterator<std::string> ii( std::cin ); cout << "--->Input whitespace-separated words:" << endl; // Suppose we stop reading when we find the word "END" std::vector<string> words; while ( *ii != "END" ){ cout << *ii << endl; words.push_back(*ii); ii++; } // Sort words cout << "Sorted words:"

C++: Parsear entrada separando palabras

Versión en inglés / English version Releyendo el libro de Stroustrup , encontré algo que me habría gustado saber tiempo atrás: una forma piola de parsear un stream de entrada separando palabras con whitespace ( 1 whitespace = cualquier cantidad consecutiva de espacios y/o tabs ). Esto se hace con un istream_iterator, así: #include <fstream> #include <iostream> #include <algorithm> #include <vector> void main(){ using std::cout; using std::endl; // Leemos desde standard input, pero podria ser desde un archivo std::istream_iterator<std::string> ii( std::cin ); cout << "--->Entrada parseada separando por whitespace:" << endl; // Supongamos que dejamos de leer cuando leemos el string "FIN" std::vector<string> palabras; while ( *ii != "FIN" ){ cout << *ii << endl; palabras.push_back(*ii); ii++; } // Ordenamos las palabras cout <

SVN: Tagging and Branching

Spanish version / Versión en Español What are "branches" and "tags" when we're talking about SVN? A tag is simply a specially marked revision: it allows us to give a revision a friendlier name than, say, "revision 901". This is why tags are usually associated to a new release of our product. For this reason, it's common practice to create a tag each time a new version of the software is released, setting the file versions in concordance with the tag name. For instance, a normal name for a tag would be "Version 3.2.0". On the other hand, a branch is a separate line of development, and it can be used in various scenarios. Say we need to do a major refactoring without breaking our colleagues' solution, and we need to commit along the way because work will be long and complex. So we create a branch, as a copy of the "trunk" (the main development line), and work there. When we're done, we merge our changes back int

SVN: Tagging y Branching

Versión en inglés / English version ¿Qué son un Tag y un Branch de SVN? Ambos son creados inicialmente como copias del "trunk" de una carpeta SVN. Un Tag es simplemente una revisión SVN marcada especialmente, lo que nos permite darle un nombre más amigable que "revisión 901". Es por esto que es usual ir crear un tag cada vez que se publica una nueva versión del software, marcando la versión de los archivos en concordancia con el nombre del tag; un nombre esperable para un tag sería "Versión 3.2.0". Por otro lado, un branch es una línea de desarrollo separada, y se usa en varios escenarios. Supongamos que queremos hacer un gran refactoring sin interferir con el trabajo del equipo, y queremos hacer commits a lo largo de nuestro trabajo porque es largo y complejo. Por lo tanto, creamos un branch como una copia del "trunk" (la línea principal de desarrollo) y trabajamos ahí. Cuando terminamos, hacemos un merge de nuestros cambios en el tru

C++/CLI: Trigger Events from native code and handle them in Managed Code, part II

Spanish version / Versión en Español In the previous post, we saw how to trigger an event from a C++ native class which has a C++/CLI wrapper as an interface to .NET. We dealt with the general case in which we wish to pass non trivial information (a class or a struct) along with the event. Today we'll see the more simple case in which we just need to pass a float or some other basic CLR type. As expected, things are quite simpler. In the native class, just for convenience, define a pointer to function type. Both returnType and parameters should be basic CLR types. typedef <returnType> ( __stdcall * PFOnEventCallback )( <parameters> ); In the same class, declare a field of that type: PFOnEventCallback m_fireEvent; Still in the native class, go to where you wish to trigger the event: if (m_fireEvent) m_fireEvent( <parameters> ); (It's good practice to initialize m_fireEvent to 0 or NULL, your cho

C++/CLI: Generar eventos desde C++ y capturarlos en código manejado, parte II

Versión en inglés / English version En la entrada anterior, vimos como generar un evento desde una clase C++ nativa que tiene un wrapper C++/CLI como interfaz hacia .NET en el caso general en que deseamos pasar información extra en el evento, y dicha info no es de un tipo primitivo (o sea, un tipo que no conocen tanto C++ como .NET). Si sólo queremos pasar un float, un int, o cualquier tipo que conozcan tanto C++ como .NET, el método que vimos antes se simplifica un poco. En la clase nativa, definimos, por comodidad, un tipo puntero a función: typedef <retorno> ( __stdcall * PFOnEventoCallback )( <parametros> ); En la misma clase, declaramos un atributo del tipo definido en 1): PFOnEventoCallback m_FireEvento; Dentro de la clase nativa, donde querramos disparar el evento: m_FireEvento( <parametros> ); (Es buena idea inicializar m_FireEvento en NULL y validar que sea distinto de NULL antes de hacer el fir

C++/CLI: Trigger events from C++ native code and handle them in Managed code, Part I

Spanish version / Versión en Español Imagine we want to trigger an event from a native class which has a C++/CLI wrapper as an interface to managed code (C#, VB.NET). And let's deal with the general case in which we desire to pass extra information along with the event, and said information is not inside a CLR basic type, that is one which both native and managed C++ understand (int, float, char, and so on). In the native class, declare, just for convenience, a pointer to function type: typedef <nativeReturnType> ( __stdcall * PFOnEventCallback )( <nativeParameters> ); Still in the native class, declare a field of the type declared in 1): PFOnEventCallback m_fireEvent; In the place in the native class where we want to trigger the event: if( m_fireEvent ) m_fireEvent( <nativeParameters> ); (This suggests you to initialize m_fireEvent to 0, or NULL if you prefer) Now we need a setter for m_

C++/CLI: Generar eventos desde C++ y capturarlos en código manejado, Parte I

Versión en inglés / English version Supongamos que queremos generar un evento desde una clase C++ nativa que tiene un wrapper C++/CLI como interfaz hacia .NET. Supongamos el caso general en que deseamos pasar información extra en el evento, y dicha info no es de un tipo primitivo (o sea, un tipo que no conocen tanto C++ como .NET). En la clase nativa, definimos, por comodidad, un tipo puntero a función: typedef <retornoNativo> ( __stdcall * PFOnEventoCallback )( <parametrosNativos> ); En la misma clase, declaramos un atributo del tipo definido en 1): PFOnEventoCallback m_FireEvento; Dentro de la clase nativa, donde querramos disparar el evento: m_FireEvento( <parametrosNativos> ); (Es buena idea inicializar m_FireEvento en NULL y validar que sea distinto de NULL antes de hacer el fire) Ahora debemos exponer un setter para este atributo, de este estilo: void CClaseNativa::registerOnEvento

C++/CLI: Native types visibility/access

Spanish version / Versión en Español Say we have the following code in a C++/CLI assembly: //Assembly A public ref class ManagedClass{ public: ManagedClass( const NativeClass &a ); } If we wish to invoke this constructor from another C++/CLI assembly, as in this case... //Assembly B ManagedClass^ AnotherManagedClass::Property::get(){ NativeClass temp; return gcnew ManagedClass( temp ); } ... when we try to compile Assembly B, we'll get a compile error saying that the constructor we're trying to call is private. But how is that possible, if we declared it public? The answer is here . To sum it up, the workaround is using the #pragma make_public(NativeClass) directive right below the #include for NativeClass. This makes NativeClass accesible to other C++/CLI assemblies.

C++/CLI: Visibilidad/acceso de tipos nativos

Versión en inglés / English version Supongamos que tenemos lo siguiente en una assembly C++/CLI: //Assembly A public ref class ManagedClass{ public: ManagedClass( const NativeClass & a ); } Si quiero invocar ese constructor desde otra assembly, por ejemplo... //Assembly B ManagedClass^ AnotherManagedClass::Property::get(){ NativeClass temp; return gcnew ManagedClass( temp ); } ...al tratar de compilar Assembly B, nos saltará un error en tiempo de compilación que dirá que el constructor que estamos invocando es privado. ¿Pero cómo puede ser si lo declaramos público? La respuesta está acá . Allí vemos que la solución consiste en usar la directiva #pragma make_public(NativeClass) justo debajo del #include de NativeClass.

C++: Link errors caused by inline functions

Spanish version / Versión en Español When we want a C++ function to be inlined, that is, to have its calls replaced by its code in order to save the calling overhead, one way to achieve is to declare and define it in the .h file, and add the inline keyword. However, that's just a hint to the compiler, he'll decide whether to inline it or not. However, if we are keen on separating declaration and definition, we should declare the function in the .h file, without the inline keyword, and define it in the .cpp with the inline keyword. So far, so good. But there's a catch: If we go for the "cpp inline" approach, and the function is called from another compilation unit (.cpp), we'll get a linking error saying something like the function definition cannot be found. In this case, we have two choices: Place the function definition in the .h file, but outside of the class declaration. This avoids cluttering its interface. This way

C++: Errores de linking generados por el uso de inline

Versión en inglés / English version Cuando queremos que una función C++ sea inline, o sea, que sus llamadas sean reemplazadas en tiempo de compilación por su código a fin de evitar el overhead de la llamada, podemos definir la función dentro de la declaración de la clase y anteponer la palabra reservada inline. De todas formas, eso es sólo un "consejo" para el compilador, quien decidirá si le conviene o no. Si nos molesta tener que definir en el .h, podemos sólo declarar la función ahí sin la palabra reservada inline, y definirla en el .cpp con la palabra reservada inline. Hasta acá, todo bien. Pero puede haber problemas: si usamos inline en el cpp, y queremos usar esa función desde otra unidad de compilación (otro .cpp), nos saltará un error de link diciendo algo como que no logra encontrar la definición de la función. En este caso, si insistimos con usar inline, tenemos dos opciones: Poner la definición en el .h, pero afuera de la dec

VB.NET: Overloading, shadowing and overriding

Spanish version / Versión en Español Overloading : When two methods have the same name, return type and different arguments (in type or quantity), we say they are overloaded. If their arguments are the same, they must be in different classes to avoid a duplicate definition. If those classes are unrelated, it's alright and we're still in the overload case. But if one class inherits from another, either Shadowing or Overriding can ocurr. Shadowing : This is what happens by default in VB.NET. Basically, the definition used when invoking is determined by the reference's type, not by the object's intrinsic type (the one with which it was created). In other word, there is no strict polymorphism/virtual mechanism. For example: Imports System Public Class Base Public Sub ShadowedSub() Console.WriteLine("ShadowedSub:Base") End Sub End Class Public Class Derived : Inherits Base Public Sub ShadowedSub() Console.WriteLine("

VB.NET: Overloading, shadowing y overriding

Versión en inglés / English version Overloading : En general, hay overloading cuando dos o más métodos tienen el mismo nombre y devuelven lo mismo, pero los argumentos que reciben son diferentes en tipo y/o cantidad. Cuando nombre, tipo devuelto y argumentos coinciden, ello sólo puede ocurrir en clases diferentes para que no haya una definición duplicada. Si son clases sin relación, no hay problema. Pero si una hereda de otra, puede ocurrir Shadowing u Overriding. Shadowing : Esto es lo que ocurre por defecto en VB.NET. Básicamente, dado un objeto, no se llama la definición dada por su tipo intrínseco, sino por el aparente. En otras palabras, no hay polimorfismo. Ejemplo: Imports System Public Class Base Public Sub ShadowedSub() Console.WriteLine("ShadowedSub:Base") End Sub End Class Public Class Derived : Inherits Base Public Sub ShadowedSub() Console.WriteLine("ShadowedSub:Derived") End Sub End Class Public Class T

Massive file rename in Windows XP

Spanish version / Versión en Español The Windows XP console (Start->Run...->cmd) is not so bad: With the rename command, it is possible to rename multiple files using wildcards. For example: rename * *.txt #Adds the .txt extension to all files rename *.dat *.rar #Changes all the .dat's extension to .rar

Renombrando archivos masivamente en XP

Versión en inglés / English version La consola de Windows (Inicio->Ejecutar->cmd) no es tan pedorra: Con el comando rename podemos renombrar archivos masivamente usando patrones sencillos. Ejemplos: rename * *.txt #Agrega extensión .txt a todos rename *.dat *.rar #Cambia extensión a todos los .dat

C++: From byte to signed int

Spanish version / Versión en Español If we cast a byte, that is, an unsigned char, to and int, we'll get a value between 0 and 255, since int, even thpugh it's signed, contains that range of values. If our intention is to see that byte as a value between -128 and 127, we must cast to signed char before casting to int. So watch it. unsigned char b = 248; int i = static_cast<int>(b); //248 int j = static_cast<int>( static_cast<char>(b) ); //-8 I prefer using static_cast to the traditional, equivalent casting style because it makes casts easier to find when you suspect there is a problem caused by them. (it's easier to find "static_cast<int>" than "(int)" )

C++: De byte a signed int

Versión en inglés / English version Si casteamos un byte, o sea un unsigned char, a int, obtendremos un valor entre 0 y 255, ya que int, pese a ser signed, contiene ese rango de valores. Si nuestra intención es ver ese byte como un entero entre -128 y 127, lo que debemos hacer es primero castear a signed char. Y recién después de hacer eso, castear a int. unsigned char b = 248; int i = static_cast<int>(b); //248 int j = static_cast<int>( static_cast<char>(b) ); //-8 Prefiero usar static_cast antes que la forma tradicional (y equivalente) de castear, porque facilita encontrar los casteos cuando uno sospecha que generan problemas (es más fácil encontrar "static_cast<int>" que "(int)" ).

C++: How to see a byte's bits

Spanish version / Versión en Español If you ever go down to the dungeons to slay a draconic bug, this little function, adapted from the one written by Bruce Eckel (see Reference), may be a helpful torch. string printBinary(const unsigned char val) { string binaryString=""; for(int i = 7; i >= 0; i--){ if( val & (1 << i) ){ binaryString += "1"; }else{ binaryString += "0"; } } return binaryString; } Reference: Thinking in C++, Vol One, Chapter 3: The C in C++, section: "Shift operators"

C++: Cómo ver los bits de un byte

Versión en inglés / English version Si algún día tenemos necesidad de bajar a las mazmorras para matar un bug dracónico, esta funcioncita, adaptada de la que escribió Bruce Eckel para "Thinking in C++" (ver referencia), puede servir de antorcha: string printBinary(const unsigned char val) { string binaryString=""; for(int i = 7; i >= 0; i--){ if( val & (1 << i) ){ binaryString += "1"; }else{ binaryString += "0"; } } return binaryString; } Referencia: Thinking in C++, Vol One, Chapter 3: The C in C++, section: "Shift operators"

Tracking down exceptions in Visual Studio 2008

Spanish version / Versión en Español If you ever looked at Visual Studio's Output window and saw a "first chance exception" message and a weird error which is not even documented in the MSDN, and you were not patient enough to debug step by step until the line popped up in the Output window again, I have a solution for you. It also applies if you want the Visual Studio debugger to break every time an exception is thrown and/or unhandled by your code. The secret is Visual Studio's Debug->Exceptions dialog. Here we can check which exceptions to track down, including .NET, native C++, ATL and stuff. In the particular case of C++ exceptions, for this mechanism to work, certain conditions must be met: When installing Visual Studio, the C++ runtime was installed In the C++ project's general properties, "Use of MFC" is set to "Use MFC in a static library" or "Use Standard Windows Library". In the project's properti

Rastreando excepciones en Visual Studio 2008

Versión en inglés / English version Si alguna vez miraron el Output del Visual Studio y vieron "first chance exception" y un mensaje raro que no aparecía documentado ni en la MSDN, y no les daba la paciencia para hacer paso a paso con el debugger hasta que apareciera la línea en el Output, ésta es la solución. También si les salta alguna excepción de .NET y el Visual no les pone el breakpoint cuando eso ocurre. El secreto está en el diálogo Debug->Exceptions. Aquí podemos tildar las excepciones que queremos detectar, para que se ponga un breakpoint cuando salten. Pueden ser generadas por .NET, el runtime de C++, ATL y otras yerbas. En el caso particular de las excepciones de C++, para que este mecanismo funcione, debe cumplirse que: Al instalar el Visual, se instaló el runtime de C++ En las propiedades generales del proyecto, "Use of MFC" está seteado en "Use MFC in a static library" o "Use Standard Windows Library". En las

Repair GRUB when installing Windows XP after installing Ubuntu

Spanish version / Versión en Español When we have more than one Operating System in the same machine, it is usual to select which one to boot on startup using GRUB. The problem is that when we install Windows XP, something more frequent than desirable, it wipes out GRUB. It's easy to fix that, see here: Fix GRUB after Windows Install Needless to say, all credit goes to Scott Calonico and the makers of SuperGRUB. But there's a catch! Since version 9.10, Ubuntu uses Grub2, which is quite different from its ancestor. The guys from SuperGRUB claim to have a SuperGRUB version for Grub2, but according to them, it doesn't always work. If that is the case or whe don't even want to bother, we can boot from an Ubuntu Live CD or USB, fire up a terminal and type: sudo update-grub sudo fdisk -l sudo grub-install /dev/sdx In the last line, you should replace the "x" in "sdx" by the letter corresponding to the hard drive where we want to rein

Reparar GRUB al instalar Windows después de Ubuntu

Versión en inglés / English version Cuando tenemos varios sistemas operativos en una misma máquina, típicamente seleccionamos cuál cargar al arrancar usando GRUB. El tema es que instalar Windows, cosa muy frecuente, se lleva puesto el GRUB. Rescatarlo es fácil, pero siempre tengo que buscarlo de nuevo así que voy a poner esta guía acá: Fix GRUB after Windows Install De más está decirlo, pero todo el crédito es para Scott Calonico y los creadores de SuperGRUB ¡Ojo! Desde su versión 9.10, Ubuntu usa Grub2, que es bastante diferente a su antecesor. En todo caso, SuperGRUBDisk tiene una versión para GRUB2, pero según ellos no funciona del todo bien. En ese caso, pelamos el Live CD de Ubuntu, arrancamos desde él, abrimos una terminal y hacemos: sudo update-grub sudo fdisk -l sudo grub-install /dev/sdx Donde reemplazamos la "x" de "sdx" por la letra correspondiente al disco duro en cuyo MBR queremos reinstalar GRUB (para eso usamos el comando fdisk,

Shameless Plug

Spanish version / Versión en Español How's it hanging, software-crazy people? Please check out Juan Alberto Villca's sites. Juan is also a student at UBA, and he's more web oriented than me, so it might interest you. A word of warning to English-olny people : most of these sites are in Spanish. Ubuntu tips and tricks (not just from Juan) Juan Alberto's Web Development Site Lorem Ipsum Juan Alberto's Projects Happy Chanukkah!

Pasando chivo

Versión en inglés / English version ¿Cómo les baila, gente descerebrada por el software? Péguenle una relojeada a los sitios de Juan Alberto Villca, célebre colega de la FIUBA. Él está más orientado al desarrollo Web, así que tal vez les interese. Truquitos para Ubuntu (no sólo de Juan) Desarrollo Web Lorem Ipsum Proyectos varios Feliz día de la GAMBRALBA, sa-sa-sa-migoss

C++: Pointers to member functions

Spanish version / Versión en Español This is quite an advanced C++ topic. In both plain C and C++ there are pointers to functions, which allow us to dynamically select the function to invoke from many which have the same signature. A typical example of this is defining a few comparison functions, all with the same signature, in order to dynamically select how to sort a collection (ascending, descending, alphabetically, etc). C++ brings in a new concept over C: pointers to member functions. Most of the times, plain pointers to function are not very Object Oriented, since they are static and all. The C++ syntax for declaring pointers to member functions is similar to that of pointers to functions, we just have to specify the class: // Generic syntax // functionReturnType (ClassName::*nameOfPointerToMemberFunctionVariable)( functionArguments ); // Concrete example LRESULT (CCoConsola3D::*onMouseWheelHandler) ( UINT, WPARAM, LPARAM, BOOL& ); The concrete example declare

C++: Punteros a funciones miembro

Versión en inglés / English version Éste es uno de los temás más avanzados de C++, casi un arcano. Tanto en C como en C++ tenemos punteros a funciones, que nos permiten seleccionar dinámicamente la función a invocar entre varias que tienen el mismo encabezado. El ejemplo típico de aplicación es hacer una función que ordene una colección de diferentes formas, usando para comparar elementos una función invocado a través de un puntero. Esto puede hacerse en C++, pero a priori sólo con funciones static. Si queremos hacerlo con funciones miembro de una clase, debemos usar este mecanismo exclusivo de C++. La sintaxis para declarar un puntero a función miembro es similar a la de los punteros a función, con el agregado de especificar la clase: // Sintaxis Genérica // retornoFuncion (NombreClase::*nombreVariablePunteroAMiembro)( argumentosFuncion ); // Ejemplo concreto LRESULT (CCoConsola3D::*onMouseWheelHandler) ( UINT, WPARAM, LPARAM, BOOL& ); La línea del ejemplo declara

C++: std::endl versus \n

Spanish version / Versión en Español Recently I started a second, deeper reading of the C++ programmer bible and I noticed something which I had overlooked before. Up next is the Hello World example from the book: int main() { std::cout << "Hello, World!\n"; } Why does Bjarne use \n instead of std::endl? Weren't we taught that the latter is more portable, since it maps to \n in *ix and \r\n in Windows? Stroustrup doesn't say anything about this, but after some googling, it turns out that using std::endl induce a stream flush. What does this mean? As you might know, most commercial programs, operating systems and hardware do I/O buffering, which means that output operations are not directly performed on the physical media. They are done to a buffer, and when it fills up, its contents are "flushed" to the media. This reduces the time spent accessing the media, which is always more time consuming than accessing the buffer. In the He

C++: std::endl versus \n

Versión en inglés / English version Releyendo la biblia del programador C++ , noté algo que en su momento se me pasó por alto. Lo que sigue es el Hola Mundo del libro: int main() { std::cout << "Hello, World!\n"; } ¿Por qué Bjarne usa \n en vez de std::endl? ¿Acaso no nos enseñaron que std::endl es más portable, ya que pone \n en *ix y \r\n en Ventanas? La respuesta es que pese a ser portable, std::endl induce un flush del stream. ¿Qué significa esto? El software de aplicación, el sistema operativo e incluso el hardware hacen buffering, vale decir que no envían los datos al stream inmediatamente: los acumulan en un buffer hasta que el mismo se llene, momento en el que se efectúa el flush. Esto reduce los accesos a disco, lo cual siempre es deseable en términos de eficiencia. En el Hola mundo la diferencia es despreciable, pero si tuviéramos un ciclo que escribiera muchas líneas a un archivo, la diferencia en performance puede manifestarse. Ergo,