Saturday, February 19, 2011

down casting unknown types

In C++ you have classes. Classes are objects that can be based off of other classes. Casting between class types is usually done by.

Foo* f = new Foo()
Bar *b = (Bar*)f;

The problem with this is its not safe. If Bar is not a base class of Foo then b is invalid and will do who knows what. There is a second possible problem too. If Foo has multiple base classes, say Bar and Baz, the cast might not work either. This depends on how the class was declared

class Foo : public Bar, public Baz

or

class Foo : public Baz, public Bar

If it was the first one, the code would have been okay. If it was the second then we just tried to cast a pointer to Baz into a pointer to Bar, which isn't okay. Casting to a base type is called down casting. How do you safely cast into Bar?

Welcome our good friend dynamic_cast. dynamic_cast knows how the classes were declared and will correct cast for you. It'll shift pointers around and return the right thing. And in case you tried to cast to something that is impossible, it returns a null. The one thing dynamic_cast wont do is cast from a void*. This is known as up casting, or casting from a base class to a derived class.

void* v = new Foo();
Bar* b = (Bar*)new Foo();
Foo* x = dynamic_cast(v); // returns null
Foo* y = dynamic_cast(b); // returns Foo*

There is no path to Bar from void, so dynamic_cast wont work here. Using void* as a generic pointer is pretty common, but unfortunately you can't dynamic_cast from it. What you need to do is create a common base class for everything to share. Lets call it Object

class Object{};

class Bar : public Object
{ };
class Baz : public Object
{ };
class Foo : public Bar, public Baz
{};

Now everything shares a common base class called Object. The problem is Foo has 2 Object base classes, one for Bar and one for Baz. If you drew out the memory, it might look something like this.

Foo
+-----
|Object
|Bar
+-----
+-----
| Object
| Baz
+-----

Now, if you tried to cast Foo to Object, which Object should it point to, the one in Bar or the one in Baz. Using a normal (Object*)new Foo() would get you the Object from bar. Using dynamic_cast would result in a compile warning of C4540 (dynamic_cast used to convert to inaccessible or ambiguous base) and it would return null. You can fix this by using a virtual base class.


class Object{};

class Bar : virtual public Object
{ };
class Baz : virtual public Object
{ };
class Foo : public Bar, public Baz
{};

Notice the "virtual public Object". This tells the compiler to only make one Object for Foo, and have Bar and Baz share it. Now dynamic_cast will be able to cast from Object to Foo and vise-versa. Now you can use Object* instead of void* as your generic pointer. This will allow you to dynamic_cast up and down all you want. The one thing you can't use this for is for primitives like int, char, float. But you can't derive anything from that anyway so it shouldn't matter.

One idea, you can use these for a Service Registry. Just make all your services have a virtual base class of IService.

class ServiceRegistry
{
public:
void Add(char* name, IService *i);
IService Find(char* name);
}

// cast to IService to add
reg->Add("my_service", dynamic_cast(my_service) );
// cast from IService to get
MyService* find = dynamic_cast( reg->Find("my_service") );


Thursday, February 3, 2011

Zombies from Microsoft

Apparently there is a bug in windows that causes Zombie Console windows.


Whats a zombie window? Its a window with no process. Every window should have a process associated with it. When that process closes, so should its window. But if the process closes some how without ever closing the window, it turns into a Zombie window.

Zombie windows are bad because they can't be closed and they prevent you from shutting down, and logging out of windows. Windows gets stuck trying to close them.

I have never seen a solution on how to get rid of them, so I came up with my own. I call it Zombie Killer.

What it does is list all your windows and lets you select one to close. You just need to double click the window in the list and it will be handled.


Wednesday, September 15, 2010

HDR in DirectX

HDR in DirectX isn't as simple as they make it out to be. What is HDR? HDR or high dynamic range is images with more than 256 colors (8bits) per channel (red.green,blue). Formats with 16, or 32 bits per channel are common. DirectX will even support a floating point number per channel, for a very large range of values.

So the obvious thing when working with HDR is that you cant render directly to your screen. Your screen only has 8bits per channel. DirectX allows you to render to an off screen buffer called a render target. Using a render target you can render in any format your gpu supports.

After you tell the GPU to use a render target you should be able to what ever you want in HDR right? Unfortunately this is not the experience I had. I set up my render target and drew a image and what I got back out was only an 8bit image. It didn't matter what format the render target was in, or what I drew for an image, it was always rendering to 8bits.

Turns out you need to also use a pixel shader. You need nothing more than:

texld r1, t0, s0
mov oC0, r1

All this does it get the value of the pixel in the texture and return it. This should be exactly what is happening by default without a pixel shader, but it doesn't seem to be. Using these 2 lines of pixel shader suddenly I was getting more than 8bits out.

Not sure why it works this way, maybe someone knows more than I do?

Monday, May 31, 2010

C++ gotchas

I was testing the timing of some code the other day. To make test easy to exit I used _kbhit(). This way hitting any key would exit the test. The problem is _kbhit() takes a LONG time.

while(!_kbhit())
{
do_something()
}

The problem here is that do_something was the method I needed to test, but _kbhit was adding a lot of extra time to each call and I was not meeting my timing. Spent a few hours trying to improve the do_something code just to find out all I had to do was call _kbhit less often.


Another gotcha is .LIB files. .LIB are like DLLs except they are compiled into the EXE file. That way you don't need to have lots of dlls with the program. The problem with lib files is they need to be build the exact same way your program is built. DLLs run in their own little memory space, while LIB share the memory space with your EXE. If you program uses Foo-v2.dll while the LIB file was compiled to use Foo-v1.dll you'll have a conflict. This shows up when the LIB file is compiled for RELEASE, and your EXE is compiled for debug. If the lib tries to allocate memory, it will use the release version of the C-library and allocate on its heap. You're program will use the debug version of the C-library and allocate on its heap. Now you have memory allocated on two different heaps. When the program closes, C will check all the memory to ensure their wasn't any memory leaks or what not. This is a great feature if you are in debug mode. When its checking the memory, it is expecting everything to be on the 'debug heap'. It will find memory allocated from the LIB file on the 'release heap' and throw a big warning about a possible memory leak because it found memory outside of where it should have been. Moral of the story is build your LIB files with the same memory model and linked libraries as you will build your EXE. If you are giving the LIB to someone else give them a debug and release version and make sure all the other linked libraries are the same.

Saturday, March 27, 2010

NFS in windows over putty

Setting up a NFS share in windows is simple. First you need a NFS client. Windows 7 ultimate comes with a client. Programs and Features -> Turn Windows features on or off -> Services for NFS (install all of it). Other versions of windows can use Window Services for UNIX. The nfs share needs to be setup for "insecure" ports. This means ports above 1024. To do this add 'insecure' to the list of options in /etc/exports. Once you have a NFS setup on the linux box you can mount it in windows using

mount server:/path/to/share x:

This works if you do not have a firewall between you and the server. If you do you need to tunnel some ports. You need to tunnel portmapper, mountd, and nfs. On the linux server run

rpcinfo -p | grep tcp

you should see something like

100000 4 tcp 111 portmapper
100000 3 tcp 111 portmapper
100000 2 tcp 111 portmapper
100011 1 tcp 875 rquotad
100011 2 tcp 875 rquotad
100003 2 tcp 2049 nfs
100003 3 tcp 2049 nfs
100003 4 tcp 2049 nfs
100021 1 tcp 1047 nlockmgr
100021 3 tcp 1047 nlockmgr
100021 4 tcp 1047 nlockmgr
100005 1 tcp 21050 mountd
100005 2 tcp 21050 mountd
100005 3 tcp 21050 mountd


This shows portmapper running on port 111, nfs on port 2049, and mountd on port 21050. Mountd runs on a random port so you may see a different number. If you want to tell mountd to run on a specific port, in fedora edit /etc/sysconfig/nfs. Restart NFS after editing the file.

In putty you want to tunnel ports 111, 2049, and 21050 (or whatever you set mountd up with). To do this goto settings -> Connection -> Tunnels

Source port: 2049, Desitnation: 127.0.0.1:2049 click Add. Repeat this for ports 111 and 21050.

Now when you mount the server used 127.0.0.1 for the server address. For example

mount 127.0.0.1/path/to/share x:

One thing you might notice is you connect as uid -2. This is the default value for an unknown user. You can change this in the registry.

HKLM\software\microsoft\clientfornfs\currentversion\default

add a DWORD called AnonymousGid, and AnonymousUid. Set it to any uid you like. Reboot and when you connect it will be as that user.

Saturday, February 27, 2010

MoinMoin 1.9.1 desktop edition

Here is a patch file to build MoinMoin 1.9.1 for windows as a desktop edition You'll need python , docutils, and PyXml installed. This will build everything into the dist directory. You should be able to copy this directory where you want and run wikiserver.exe. No language files have been install. You will have to install them first to have a working wiki.

  • download moinmoin 1.9.1
  • unzip the patch file into the directory.
  • Run the patch file
  • run python setup_py2exe py2exe
  • look in the dist folder for output
For those looking for a prebuilt archive, you can find it here

Friday, February 26, 2010

The number that wasn't

Signed numbers on computers are handled in a special way. Computers deal with bits (1s and 0s). Numbers are represented using a number of bits, usually 8, 16, 32. To represent a signed number one of the bits is used to tell if its positive or negative, usually the 1st bit. Usually this all works and everything goes well. Sometimes you want a number using a different number of bits, like 3, 4, or 5. Some languages allow you to do this automatically. In C this would look like

struct {
int foo : 5
int bar : 1
} my_number

This makes foo 5 bits and bar 1 bit. Both of these are defined as signed numbers. foo can represent a number from -16 to 15. The question now is what values can bar hold? Because it is signed, the 1st bit will be used to tell if its negative or positive. There are no bits left to tell what the value will be. So what values can it hold? If you were wondering it is possible to define a number in your program like this.