Friday, February 9, 2007

Passing Structs from COM to .NET

The easiest way of passing structs built out of primative data types from COM to .NET is to define the struct in your COM IDL file and use that struct in your COM code. Then expose a COM interface method to retrieve that struct and return it using standard COM rules. For example:

In your IDL define a struct like this:

typedef struct tagTeamInfo
{
long TeamId;
BSTR TeamName;
} TEAMINFO;
...
[id(6), helpstring("method GetTeamInfo")] HRESULT GetTeamInfo([in] LONG index, [out,retval] TEAMINFO* pTeamInfo);


Then, in your COM code, use the TEAMINFO struct as normal.

TEAMINFO ti;
ti.TeamId = gd->mObject;
ti.TeamName = StringToBSTR(gd->mName); //NOTE: See BSTR and .NET FAQ entry

In your implementation of the GetTeamInfo interface:

STDMETHODIMP CCollector::GetTeamInfo(LONG index, TEAMINFO* pTeamInfo)
{
const TEAMINFO& ti = mCurrentSession.GetTeamInfo(index);
pTeamInfo->TeamId = ti.TeamId;
pTeamInfo->TeamName = SysAllocString( ti.TeamName );
return S_OK;
}

Note that we allocate a new BSTR to place in the out TEAMINFO that was passed in. The caller is responsible for freeing that BSTR.

The cool part about all of this is that you can now pass a struct from COM to .NET and all of the memory allocations and such are taken care of for you (even the freeing of the BSTR!)

Thursday, February 8, 2007

System.IO.FileNotFoundException occurring with XmlSerializer

Recently I discovered that when loading the a C# app in the debugger and have exception trapping enabled, you will receive an exception "System.IO.FileNotFoundException" with a message similar to: "Could not load file or assembly 'mscorlib.XmlSerializers,..."

Looking around on the Microsoft bug database I found this explination: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=93647

"XmlSerializer attempts to load pre-generated serializers to avoid compilation of the serialization code on the fly. There is no easy way to check for "will assembly be found by the Assembly.Load() call", it would be duplicating Fusion path search and loader logic in XmlSerializer."

Basically, this is not really an error since the exception is caught and the assembly is then generated in order to run the XmlSerializer correctly. There is no way to avoid this exception and it will always be caught by the Exception manager in the debugger when you have CLR Exceptions set to be thrown. It is perfectly safe to just ignore this exception.


Wednesday, January 31, 2007

Exporting native C++ in a C++/CLI Project using dllexport

Normally, when compiling C++ code with the /clr compiler flag, you generate a managed assembly that exports all the C++ code through a managed wrapper. Under the hood, this generates a native and a managed wrapper around each function. When an external assembly attempts to call the native function, it will always choose the managed wrapper call, even if the originator was a native function. This leads to a double thunk, where you transition from native to managed, then from managed to native, and back. Ideally, you would want to use the native entry point to the function when calling from a native function.

For example, say we have a C++/CLI project called MyExportProject that contains the class defintion:

ExportClass.h

#ifdef MAKING_DLL
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllimport)
#endif
namespace MyExportProject
{
// this is a native class
class DLLEXPORT NativeClass
{
public:
int GetValue();
};
}

ExportClass.cpp

namespace MyExportProject
{
int NativeClass::GetValue()
{
return 42;
}
}

If you compile this file with the /clr option and then run DUMPBIN /exports on the resulting MyExportProject.dll, you will see that there are in fact exported methods. There will also be a MyExportProject.lib that is a DLL stub library that you must use in order to use the NativeClass that was exported. You can then use the exported class in another project (also compiled with /clr):

UseExportedClass.cpp

#include "ExportedClass.h"
void main()
{
MyExportProject::NativeClass c;
printf("The Meaning of Life is %d\n", c.GetValue() );
}

Although this appears to do what you want (ie, calling a native exported function from a native function), it really adds the double thunk since .NET tries to remain in managed code as long as possible. Since there is a managed wrapper around the exported native function, it will prefer to use the managed wrapper.

The way to avoid this is to force the compiler not to create the managed wrapper. This is done by using #pragma unmanaged around the code that you do not want the wrapper for. So, to make the above code work we would change the ExportedClass.cpp file to look like the following:

ExportClass.cpp

namespace MyExportProject
{
#pragma unmanaged
int NativeClass::GetValue()
{
return 42;
}
#pragma managed
}

This will solve the double-thunk problem. However, you will no longer be able to access this function from managed code directly since the is no managed wrapper. Since the point of this was to only call this code from native code, it is a fair tradeoff.

For more information on this issue, see: http://www.heege.net/blog/PermaLink,guid,d5e2c3da-ff4d-40bc-bea9-9da8ec9e091e.aspx

Monday, January 29, 2007

Introduction to Microsoft XNA Game Studio Express

Here is the article I wrote for the G2Expo I mentioned in my last post. If you are interested in getting started with XNA then read this to learn how to install XNA Game Studio Express and gain a basic understanding of what is contained in an XNA project. Enjoy.


Introduction to Microsoft XNA Game Studio Express

If you've ever played a video game then you have probably felt the urge to sit down and make your own. After all, there is always a little change here or there that would make the last game you played even better. Or maybe you have the best idea ever and you want to share it with the world. You sit down in front of your computer and stare blankly at the screen wondering where to start. You fire up your compiler, excited to get to work, but end up spending half the day just trying to draw a triangle. Worse yet, you have to read pages and pages of documentation and write hundreds of lines of code just to get anything interesting to happen. As a final insult, you can't even have the fancy triangle you spent so much time on display on your Xbox 360. You just want to write a game, not spend all your time writing all the code that just makes it possible to start working on a game. Before long you give up and decide those guys who write games must be some kind of geniuses and you go back to playing one more match of Ghost Recon on Live.

Thankfully, Microsoft has heard the pleas of the would-be game designers and have come to the rescue with the first release of XNA Game Studio Express. Game Studio Express takes a lot of the drudgery out of writing a game, handling the grunt work while leaving you free to focus on implementing your great ideas. Based in C#, even a novice programmer can pick up the basics of coding without the headaches usually found in other languages such as C or C++. Best yet, with a membership to the XNA Creators Club, you can share your masterpiece with your friend on Xbox Live. Finally, although writing a game for your Xbox 360 is one of the major features of XNA Game Studio Express, an Xbox 360 is not required to use it. There is no reason you can't use Game Studio Express to develop your own PC games as well.

In this article I will explain where to get XNA Game Studio Express, how to install it, and take a quick tour of what you'll find an a XNA game project. I assume you have some programming experience and at least some familiarity with C# (For a quick introduction to C#, see http://www.codeproject.com/csharp/quickcsharp.asp)

Installation
In order to use XNA Game Studio Express (GSE) you must have a PC running Windows XP SP2 as well as being capable of running Microsoft Visual Studio C# Express. A complete list of requirements can be found on the XNA Game Studio Express download page (http://msdn.microsoft.com/directx/xna/gse). Go there and follow the instructions for downloading XNA Game Studio Express 1.0, as well as Visual C# Express. You will also need a copy of the latest DirectX 9.0c SDK. Although GSE runs fine without it, you need some of the tools that come with the DirectX SDK in order to take full advantage of XNA GSE.

Before you can install XNA Game Studio you must install Visual Studio C# Express (http://msdn.microsoft.com/vstudio/express/visualcsharp/download). This is the environment that you will use when writing your XNA games. Just follow the default installation. After installation, find the Start menu item "Microsoft Visual Studio C# 2005 Express Edition" and run that to ensure that your installation was successful. Exit Visual Studio.

Next, install the DirectX 9.0c SDK (the latest version can be found at http://www.microsoft.com/downloads/Browse.aspx?displaylang=en&categoryid=2). Once you are done you should be able to find "Microsoft DirectX SDK (December 2006)" in your Start menu.

Once Visual Studio C# Express and the DirectX SDK are installed you can begin to install XNA Game Studio Express 1.0. Run the XNA Game Studio Express setup program that you downloaded. When it is complete, you will find a new item in your Start menu, "Microsoft XNA Game Studio Express" and inside that item will be a shortcut to "XNA Game Studio Express". You can use either this shortcut or the original Visual Studio C# Express shortcut to launch Game Studio Express. Use either shortcut and you should see Visual Studio C# Express load and show you a blank Solution and a Start page. Now you are ready to start working.

First Steps
Launch XNA Game Studio Express (either using the Visual Studio C# shortcut or the XNA Game Studio Express shortcut). You should see the Start Page and have an empty workspace. The first thing you'll want to do is create a new XNA Game project. To do this select the File->New Project menu. A window named "New Project" will appear. Under "Templates" you will see all of the different types of C# projects you can create. There are six different XNA project types. For now we want to create a simple project so that we can explore what XNA provides us. Select the "Windows Game" template, entering "MyFirstGame" for the name and setting "Location" to a directory on your computer where you want to store your project. When you hit OK a new XNA Windows project will be created called "MyFirstGame" and a new file called "Game1.cs" is open in your editor. If you build and run this program now you will see a window titled "MyFirstGame" appear with a blue background. If no window appears or there was an error, check that you followed all the installation instructions correctly.

There are two .cs (C#) files in the project, Game1.cs and Program.cs. If you open Program.cs you will see that all it does is create a new instance of your Game1 class and call the Run() method on it. Game1.cs is where the main program is located. Here we see the class Game1 that is derived from Microsoft.Xna.Framework.Game. This base class provides us with a framework for our game's logic and rendering code. All XNA games must have a Game class.

Inside class Game1 we see two members: graphics and content, of types GraphicsDeviceManager and ContentManager, respectively. The GraphicsDeviceManager, as you have probably guessed, handles the configuration and management of the graphics device. The ContentManager is how you access all of the graphics and sound files that your project will use.

The next thing you will see is the constructor for the Game1 class. In it the graphics and content devices are created for you. Following the constructor is an Initialize() method. This is where you would initialize your own game data and set up your game before the main loop starts. For example, this is where you would create any graphics objects like sprites.

Next are two methods, LoadGraphicsContent() and UnloadGraphicsContent(). The first, LoadGraphicsContent(), is called whenever you need to load graphics content, such as when you switch monitors or resolutions. It is important to remember to load all our content here or you may end up with missing data and possible crashes in your game. The next method, UnloadGraphicsContent() called whenever you need to dispose of any non-managed graphics content you may have loaded in LoadGraphicsContent().

The Update() function is where you will update the simulation part of your game. For instance, you would move all your sprites, perform collision detection, do AI, play sounds, and do everything that you need to actually make your game work. The GameTime parameter that is passed to this method allows you to determine how much time your game as been running as well as how much time has elapsed since the last time Update() was called. When writing your own games you should base all of your calculations off of this GameTime.

Finally is the Render() function. Here is where you draw each frame of your game. Depending on your game this can be as simple as drawing 2D sprites or as complex as rendering a full 3D scene with pixel and vertex shaders. Again you are supplied with a GameTime parameter that tells you just how long your game has been running so that you can adjust your rendering to match.

Where to Go From Here
Now that you are familiar with XNA Game Studio Express you can begin experimenting on your own. The XNA documentation is a great source of information as well as the main XNA Game Studio Express web site (msdn.microsoft.com/xna) I've also written a sample 2D XNA game that you can try out and experiment with. You can find it at www.bruceshankle.com/cstoy/TanksOfDeath.zip.

Microsoft has done a great job in developing XNA Game Studio Express and opening up Xbox and PC game development to everyone looking to create the next great game.








Sunday, January 28, 2007

G2 Expo

Yesterday I was lucky enough to attend the Goldsboro Gaming Expo (G2Expo), "a hybrid festival of industry speakers, video game tournaments, product promotions, exhibition booths, student recruitment and full blown family fun!" It was great to go out and meet all of the enthusiastic gamers and talk to them. The day was filled with various gaming tournaments and game industry experts giving presentations on everything from being a game designer to how to get a job in the games industry. I was asked to speak on the North Carolina Game Developers Q&A Panel at the end of the day. There was a great turnout for the panel, especially considering we didn't go on until nearly 9:30pm. It was a long day, but was a lot of fun and I'm looking forward to next years expo.

I wrote an article for the G2Expo program giving a quick introduction to Microsoft's XNA Game Studio Express. I really like XNA, not just because it allows anyone to develop a game for the Xbox 360, but also since it is free and easy to use. Microsoft has done a really good job on it and I recommend anyone interested in getting started writing their own game.