Greg Dolley’s Weblog

A Blog about Graphics Programming, Game Programming, Tips and Tricks

  • Archives

  • June 2023
    M T W T F S S
     1234
    567891011
    12131415161718
    19202122232425
    2627282930  
  • Blog Stats

    • 1,071,665 hits
  • Subscribers

  • Twitter

Archive for the ‘Tips and Tricks’ Category

Can I Use Typedef’s in C#?

Posted by gregd1024 on February 15, 2008

When moving from C++ to C#, the following question often arises: does C# support typedef’s? Unfortunately, no. However, you can get pretty close. Consider this code:

using GLenum = System.UInt32;

The “using GLenum” statement makes the symbol “GLenum” equivalent to a “System.UInt32” name. Now you can use “GLenum” to declare identifiers instead of “UInt32.” In this way, it’s acting exactly like a C or C++ typedef. What’s actually happening is that you’re creating a C# alias – a mechanism which allows the renaming of a class, struct, or namespace. While this may seem pretty flexible, consider what happens when you try the following:

using GLfloat = float; // ERROR!

This line results in a compile error because “float” is a keyword. Why weren’t C# aliases built to support this as well? When you consider the original purpose of aliases it kind of makes sense. They were meant to save the programmer from lots of typing by providing a mechanism to shorten long qualifiers. We all know some namespaces and classes in C# are much longer than what you would typically see in a C++ program, so providing renaming support was practically a necessity. But do you really think a lot of programmers are going to shorten “float” or “int”? So when I said you can “get pretty close” to a C++ typedef, I was specifically referring to limitations such as this.

Another big limitation is that aliases are limited in scope. Only the namespace in which they’re declared can see them and their scope cannot cross multiple source files. The last part is severely limiting – it forces you to include the same declaration in every file. At least it’s better than nothing.

-Greg Dolley

*Get new posts automatically! Grab the RSS feed here. Want email updates instead? Click here.

Advertisement

Posted in C# Programming, Tips and Tricks | 8 Comments »

How to Make a C# Application Without the Wizard

Posted by gregd1024 on February 14, 2008

Most C++ programmers know how to start coding from an empty project without the wizard’s assistance. But how many tutorials show a way to do this in C#? Questions arise like what references you need, what should the default project settings be, etc.

In this post I’m going to create a Windows Form application starting from scratch (just an empty project). It’s actually quite easy if you’re making a DLL, Console application, or Forms application. Plus, you can be certain that your application doesn’t contain any useless references or dependencies.

Note: this tutorial is applicable to Visual Studio 2008.

Step 1 – Create an Empty Project

Start Visual Studio and select “File->New Project.” When the “New Project” dialog appears, select the “Empty Project” template and name it whatever you like. Click OK.

c_sharp_app_from_scratch_new_project_dialog

Step 2 – Modify Project Settings

At this point you’ll have an empty project loaded in Solution Explorer without any source files or references listed. Now, go to the “Project” menu and select “Properties.” Under the “Application” tab, click the “Output type” combo box and change it from “Console Application” to “Windows Application.” This makes the project into a regular Windows Form app.

c_sharp_app_from_scratch_project_settings

Save this configuration (hit CTRL-S or click “File->Save”) and close the “Project Settings” window.

Step 3 – Add References

Now right click on the “References” folder in Solution Explorer and click “Add Reference” (you can also select the same option from the “Project” menu). Which references you’ll need will depend on what kind of project you’re building, but in our case we need “System,” “System.Windows.Forms,” and “System.Drawing.” They are located in the .NET tab of the “Add Reference” dialog:

c_sharp_app_from_scratch_system_reference

After you’ve selected all three references, click OK. Now your project should look like this in Solution Explorer:

 c_sharp_app_from_scratch_solution_explorer_references

FYI: for almost any project you’ll at least need the “System” reference, so I add this one right away no matter what kind of project I’m creating. If your project was extremely simple, had no dependencies, and you didn’t care about fully qualifying your types, then you could get away with not adding this reference.

Step 4 – Add a Source File

You’ll notice from the last screenshot that we don’t have any source files in our project. Well that’s easy to fix – click on “Add New Item” located under the “Project” menu. When the “Add New Item” dialog appears, select “Code File.” Name it whatever you like and click OK.

c_sharp_app_from_scratch_add_code_file

Step 5 – Add Code

We didn’t want to select the “Class” template because that would cause Visual Studio to create a class skeleton and add useless references to the project.  Selecting “Code File” ensures that nothing is done which isn’t completely necessary. It also gives us an entirely blank source file. Here is the minimum amount of code you’ll have to add for some meaningful output:

  1. Type the “using” directives for “System,” “System.Windows.Forms,” and “System.Drawing.”
  2. Type a namespace declaration.
  3. In that namespace type a class declaration deriving from “Form”.
  4. Type a “static void Main()” function into the class.
  5. Inside the Main() function type this line: “Application.Run(new MyClass());”

After following the steps above, your code should look similar to this:

using System;
using System.Windows.Forms;

using System.Drawing;

 

namespace MyProject
{
   class MyClass:Form
   {
      static void Main()
      {
         Application.Run(new MyClass());
      }
   }
}

You can actually compile and run the project in this state, but it will just produce a blank form and you won’t be able to add controls in the Designer. We’ll take care of this problem in the next step.

Step 6 – Add Controls to Form

You may be wondering how to associate your hand-written code with Visual Studio’s Designer. Believe it or not, there’s no need to do this. In fact, Visual Studio automatically detects whenever you derive a class from “System.Windows.Forms.Form” and links the associated source file to the Designer.

Now, right click on your source file in Solution Explorer and select “View Designer.” When the Designer comes up you’ll see an empty form. Drag a button control on it and switch back to code-view. You’ll notice that Visual Studio has added this function to your class:

private void InitializeComponent()
{
   this.button1 = new System.Windows.Forms.Button();
   this.SuspendLayout();
   //
   // button1
   //
   this.button1.Location = new System.Drawing.Point(104, 93);
   this.button1.Name = “button1”;
   this.button1.Size = new System.Drawing.Size(75, 23);
   this.button1.TabIndex = 0;
   this.button1.Text = “button1”;
   this.button1.UseVisualStyleBackColor = true;
   //
   // MyClass
   //
   this.ClientSize = new System.Drawing.Size(284, 264);
   this.Controls.Add(this.button1);
   this.Name = “MyClass”;
   this.ResumeLayout(false);

}

Visual Studio automatically keeps InitializeComponent() up-to-date. It contains all the code for creating and positioning the form’s controls. However, we still have to call the function. For this, we turn to the class’s constructor. Since we haven’t defined a constructor yet, we’ll do it now and add the call to InitializeComponent():

MyClass()
{
   InitializeComponent();
}

By now, your source code should look like this:

using System;
using System.Windows.Forms;
using System.Drawing;

 

namespace MyProject
{
   class MyClass:Form
   {
      private Button button1;
     

      MyClass()
      {
         InitializeComponent();
      }
     

      static void Main()
      {
         Application.Run(new MyClass());
      }

     

      private void InitializeComponent()
      {
         this.button1 = new System.Windows.Forms.Button();
         this.SuspendLayout();
         //
         // button1
         //
         this.button1.Location = new System.Drawing.Point(104, 93);
         this.button1.Name = “button1”;
         this.button1.Size = new System.Drawing.Size(75, 23);
         this.button1.TabIndex = 0;
         this.button1.Text = “button1”;
         this.button1.UseVisualStyleBackColor = true;
         //
         // MyClass
         //
         this.ClientSize = new System.Drawing.Size(284, 264);
         this.Controls.Add(this.button1);
         this.Name = “MyClass”;
         this.ResumeLayout(false);

      }
   }
}

Step 7 – Compiled and Run

Now try running the project! Hopefully you see something similar to my output:

c_sharp_app_from_scratch_output_form

Congratulations! You just created a Windows Forms application from scratch!

Optional Things

You may be thinking, “but what about the extra code the wizard adds in forms like Dispose() and the “components” member? Don’t I need that stuff too?” The short answer: it depends.

In certain situations you’ll need the “components” member, but it’s not necessary to define it. The Designer will add the declaration when it’s needed. Try placing a Notify Icon or Timer control and you’ll see what I mean. The “components” member is used for most of the non-visual controls available in the Designer. If you drag a control on a form and it gets added to the container bar (on the bottom of the design window) instead of making some visual appearance on the form itself, then there’s a good chance it’ll use this variable.

You’ll need the Dispose() function only if you must explicitly free resources that can’t otherwise be managed by the Garbage Collector. These resources might be unmanaged memory, file handles, database connections, or similar objects who’s destruction is non-deterministic. Given that our example program allocated objects only from the managed heap, having a Dispose() would be pointless.

If you find that your class will eventually need the “components” member and a Dispose() method, here’s the minimum amount of code you’ll need to get started:

// Special Designer variable
private System.ComponentModel.IContainer components = null;

 

// Used to explicitly free any resources not
// managed by the Garbage Collector
protected override void Dispose(bool disposing)
{
   if (disposing && (components != null))
   {
      components.Dispose();
   }
   base.Dispose(disposing);
}

Also, you may have noticed that when using the wizard to generate a project, it creates a separate form class instead of using the application’s main class as the container. This results in two extra source files being added to the solution. You can do this yourself by creating one source file giving it a “.cs” extension (such as “Form.cs”) and creating another file with the same name but giving it a “.Designer.cs” extension (such as “Form.Designer.cs”). Visual Studio will automatically associate these two files together and you’ll see “Form.Designer.cs” underneath “Form.cs” in Solution Explorer’s tree view:

c_sharp_app_from_scratch_manual_form_files

Conclusion

I hope that this post has given you insight into rolling your own Windows Forms project from scratch. While it will always be faster to use the wizard, at least now you don’t have to rely on it. You also know what parts of the wizard’s code can be deleted if your program doesn’t require it.

-Greg Dolley

*Get new posts automatically! Grab the RSS feed here. Want email updates instead? Click here.

Posted in C# Programming, General Programming, Tips and Tricks | 6 Comments »

Tip: How to Delete MRU Items from Visual Studio 2008

Posted by gregd1024 on February 11, 2008

How many times have you had a project (or solution) in Visual Studio’s MRU list that you didn’t want? Maybe it was a project you opened by mistake, or maybe it was something you only needed in rare circumstances. Whatever the reason, did you also try looking for an option in Visual Studio that would allow you to delete those MRU entries? I’ve been in the same situation and, unfortunately, I had no luck finding a way to delete a specific entry in the list. At least, not directly through Visual Studio.

In this post I’ll show you a hack that will allow specific entries to be deleted. It requires a few registry modifications and isn’t the cleanest solution, but at least it gets the job done. If you know of another way to do this directly through Visual Studio then, by all means, please leave a comment.

The first thing you’ll need to do is open one of the following registry keys:

  • Visual Studio Express for C++: HKEY_CURRENT_USER\Software\Microsoft\VCExpress\9.0\ProjectMRUList
  • Visual Studio Express for C#: HKEY_CURRENT_USER\Software\Microsoft\VCSExpress\9.0\ProjectMRUList
  • Visual Studio Professional: HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\ProjectMRUList

It will look something similar to this:

registry_MRU_list

Here you’ll see paths to each of your MRU projects. The entry which appears first in Visual Studio’s list is labeled “File1,” the second is “File2,” etc. Simply delete whichever entry holds the path to the project you don’t want. If you’re deleting the last entry, you can stop here. Otherwise, you’ll have to rename all successive entries such that the numbering is consecutive.

Once you’ve deleted the entry or entries representing your project(s), open a new instance of Visual Studio – notice how the MRU list just got shorter! 😉

-Greg Dolley

*Get new posts automatically! Grab the RSS feed here. Want email updates instead? Click here.

Posted in Miscellaneous, Tips and Tricks | Leave a Comment »

How to Convert a Console App into a Windows App in C# – Part Two

Posted by gregd1024 on February 9, 2008

As I promised in yesterday’s post, I’m now going to show you an even easier way to convert a C# console application into a regular Windows application. Since the steps are nearly identical, I’m just going to focus on the key points instead of writing the same thing as before.

First, perform the following steps:

  • Create a regular C# console application or open one of your own.
  • Add the following two references to your project and the corresponding “using” statements on top of the main source file:

using System.Drawing

using System.Windows.Forms

  • Remove the “args” string array parameter from the Main() function.
  • Add “Application.EnableVisualStyles();” as the first call in the Main() function.
  • Change the “Output type” of your project from “Console Application” to “Windows Application.”

Now for the fun part (the part that’s different from my last post). Do the following:

  • Change the “Program” class to derive from “System.Windows.Forms.Form.”
  • Add “Application.Run(new Program());” as the last call in the Main() function.

At this point your “Program” class should look like this:

class Program:System.Windows.Forms.Form

{

   static void Main()

   {

      Application.EnableVisualStyles();

      Application.Run(new Program());

   }

}

We’re almost done. In fact, you can run the program now and you’ll see a blank form. But you won’t be able to place any controls on it. Well, actually that’s not true – you can place controls, but the form will still be blank at runtime. The last step is:

  • Add a constructor to the “Program” class and call “InitializeComponent()” inside it:

class Program:System.Windows.Forms.Form

{

   Program() // ADD THIS CONSTRUCTOR

   {

      InitializeComponent();

   }

 

   static void Main()

   {

      Application.EnableVisualStyles();

      Application.Run(new Program());

   }

}

“InitializeComponent()” will not be defined yet. However, the Form Designer will create this function as soon as any control is placed on the form or its layout is modified. You may have noticed that the icon next to “Program.cs” (in Solution Explorer) has changed to a form instead of the one representing a code file:

console_convert_2_icon_change 

This means you can double-click on it and Visual Studio will open the Form Designer instead of going to the source. Try this:

  1. Double click on Program.cs.
  2. Change the form’s size in the Designer.
  3. Go back to the source window of Program.cs.

Now you should see the “InitializeComponent()” function defined underneath “Main().” Your “Program” class will now look like this:

class Program:System.Windows.Forms.Form
{
   Program()
   {
      InitializeComponent();
   }
     
   static void Main()
   {
      Application.EnableVisualStyles();
      Application.Run(new Program());
   }

 

   private void InitializeComponent() // DESIGNER WILL ADD THIS FUNCTION
   {
      this.SuspendLayout();
      //
      // Program
      //
      this.ClientSize = new System.Drawing.Size(367, 188);
      this.Name = “Program”;
      this.ResumeLayout(false);

 

   }
}

You’re done! 🙂 Everything is contained in this one source file. The designer will keep on modifying “InitializeComponent()” whenever something changes in the form itself. It will also add the necessary member variables to the “Program” class whenever controls are placed on the form.

-Greg Dolley

*Get new posts automatically! Grab the RSS feed here. Want email updates instead? Click here.

Posted in C# Programming, General Programming, Tips and Tricks | 22 Comments »

How to Convert a Console App into a Windows App in C#

Posted by gregd1024 on February 8, 2008

In this post I’m going to demonstrate how you can easily take a simple C# console application and convert it into a regular Windows application. It will involve just a few code changes and one project settings change. There are actually two methods to do it – a method in which you end up with almost the same code the wizard normally generates, and a method in which your application class becomes the main form. I’m only going to demonstrate the first method in this post; I’ll cover the second method in my next post.

The instructions presented in this post are for Visual Studio 2008, but most should work in a similar way with previous versions. I’m also going to use Express for the programmers who don’t have full blown Visual Studio.

Step 1: Create a C# Console Application

For demonstration purposes I’m creating a C# console application from the wizard. Of course, if you already have a console app you want to convert, open your project instead.

console_app_conversion_new_project

Step #2: Add References

Add the following references to the project:

  1. “System.Drawing”
  2. “System.Windows.Forms”

console_convert_add_references

These references are not added by the console app generator wizard, so we must add them manually. Also, add the corresponding “using” statements to your application’s main source file (the file that contains the Main() function):

  1. “using System.Drawing”
  2. “using System.Windows.Forms”

Step Three: Modify the Main() Function

Perform the following steps to the Main() function:

  1. Remove the “args” parameter from Main().
  2. Add the following two lines:

static void Main()

{

   Application.EnableVisualStyles(); // <– ADD THIS LINE

  

   // your existing code goes here (if any)

 

   Application.Run(new Form1()); // <– ADD THIS LINE

}

You can optionally add “Application.SetCompatibleTextRenderingDefault(false);” right under the EnableVisualStyles() call, but it’s not required. I mention it because this is what the wizard adds when auto-generating a project, but its purpose is beyond me (if you know what this function does, please leave a comment).

Step Four: Add a New Form Resource to the Project

Add a new form to the project and keep the name as Form1.cs:

console_convert_add_form

Step Five: Modify Project Settings

To modify the project settings go to the Project menu and click on Properties. Under the first tab (Application), click the Output type drop-down box and change it from “Console” to “Windows Application.”

console_convert_project_settings

Step Six: Compile and Run!

We’re done! 🙂 Now try running the project. You should see a blank form without any console box:

console_convert_up_and_running

Conclusion

In my next post I’m going to show you an even simpler way of doing this very same thing. Instead of explicitly adding a Form resource to the project, we’ll just take the class which houses Main() and turn it into a form programmatically. You’ll even be able to use the Form Designer to add controls and modify layouts.

-Greg Dolley

*Get new posts automatically! Grab the RSS feed here. Want email updates instead? Click here.

Posted in C# Programming, General Programming, Tips and Tricks | 17 Comments »

Part 2: How to Make Native Calls from Managed Code in C++/CLI

Posted by gregd1024 on February 3, 2008

This is an extension from my previous post on C++/CLI marshalling. In this segment I’m going to talk about sending an object from managed code to native code. While doing this kind of marshalling is required less and less these days as we depend more on external .NET components instead of COM DLL’s or native C API’s, there may still be times where you’ll need to do it.

If you would like to play with the original source code discussed in this post, you can download it below:

Native Library

In order to keep the examples as simple as possible we’re going to create our own native library (.lib) instead of using some third party API (rest assured however, whether you’re calling the Win32 API or a third-party DLL, the process remains the same). Our library will contain one function and one native class. The class looks like this:

class NativeObject
{
   public:
      NativeObject();

   public:
      char m_byte;
      char *m_string;
      int m_int;
      float m_float_array[3];
};

We will be creating the .NET equivalent of this class in different project. You will see how to marshal the .NET equivalent object into the following native library function:

void SomeNativeFunction(NativeObject *obj)
{
   printf(“\r\nInside native library function. Object dump:\r\n\r\n”);
   printf(“obj->m_byte = %i\r\n”, obj->m_byte);
   printf(“obj->m_string = %s\r\n”, obj->m_string);
   printf(“obj->m_int = %i\r\n”, obj->m_int);
   printf(“obj->m_float_array[] = {%f, %f, %f}\r\n”,
                                  obj->m_float_array[0],
                                  obj->m_float_array[1],
                                  obj->m_float_array[2]);
}

I put both the class definition and the prototype of SomeNativeFunction() into a header file called, “NativeSampleAPI.h.” This header will used in the managed project so it can have access to the library’s type(s) and function(s).

Managed Object

Now we will create a C++/CLI project using the following wizard template: “CLR Console Application.” The first step is to create a managed class who’s layout exactly matches the native class’s layout byte-for-byte. For simple types such as int’s and char’s, choosing the correct managed type to match the corresponding native type is easy – in C++/CLI the native type “char” matches managed type “Byte,” the type “int” matches “Int32,” etc. However, for non-intrinsic types, choosing the equivalent can be confusing – how do you deal with an array which has an arbitrary size, or a string that is ANSI instead of unicode?

For these cases we use the “MarshalAs” member attribute to give the compiler more details on how we want the final unmanaged type to end up. See below for the complete conversion of our library’s native type to .NET:

[StructLayout(LayoutKind::Sequential)]
public ref class NativeObjectEquivalent
{
   public:
      NativeObjectEquivalent()
      {
         m_byte = 0x02;
         m_string = “Managed object”;
         m_int = 200;
         m_float_array = gcnew array<float>(3);
         m_float_array[0] = 1.0f;
         m_float_array[1] = 2.1f;
         m_float_array[2] = 3.2f;
      }

   public:
      System::Byte m_byte;

      [MarshalAs(UnmanagedType::LPStr)]
      String ^m_string;
      Int32 m_int;

      [MarshalAs(UnmanagedType::ByValArray,
                 SizeConst=3,
                 ArraySubType=UnmanagedType::R4)]
      array<float> ^m_float_array;
};

The “MarshalAs” attribute applies to the member immediately following it. It accepts either a short or an “UnmanagedType” enum as the first parameter telling the compiler exactly which native type to use. If you need to specify more information about the type, such as fixed string length or array size, you would then fill in a series of named parameters following the first. For example, it’s not enough to tell the compiler that “m_float_array” is an array – it also needs to know the array size and the native type of each element. That’s where “SizeConst” and “ArraySubType” come into play. “SizeConst=3” tells the compiler that “m_float_array” is an array of fixed size and the number of elements it contains is three. “ArraySubType=UnmanagedType::R4” tells the compiler that it’s a “float” array (a “double” array would have been specified with “R8” instead of “R4”).

Now that the two types match in size, let’s see how to pass the managed object to the native function. Take a look at the following code in our managed project:

int main(array<System::String ^> ^args)
{
   Console::WriteLine(“Constructing managed object…”);
   NativeObjectEquivalent ^obj = gcnew NativeObjectEquivalent();

 

   Console::WriteLine(“Writing managed object to unmanaged memory space…”);
   IntPtr ptr(Marshal::AllocHGlobal(Marshal::SizeOf(obj->GetType())));
   Marshal::StructureToPtr(obj, ptr, false);

   Console::WriteLine(“Passing managed object to native function…”);
   SomeNativeFunction((NativeObject *)ptr.ToPointer());

   Console::WriteLine();
   Console::WriteLine(“Press any key to continue…”);
   Console::ReadKey();

   return 0;
}

Let’s go through things line by line (not counting print messages). First we create an instance of NativeObjectEquivalent, our managed version of the native class, via gcnew. Then AllocHGlobal() is called in order to allocate a chunk of memory from the unmanaged heap. It’s important that the memory is not on the managed heap so we’re ensured the pointer will never move (managed pointers can have their address changed during heap compaction). At this point we call StructureToPtr(). This function marshals a managed object into an unmanaged block of memory pointed to by the IntPtr. Finally, we call our library function converting the IntPtr into a native void pointer via the ToPointer() call. We must cast the void pointer into a NativeObject pointer to satisfy the compiler.

And… we’re done! Let’s look at the output:

MarshalToNativeAPI_SampleOutput

Notice how m_string is set to “Managed object” – proving that the object inside our native function did indeed originate from the managed project. 😉

Conclusion

This post, of course, only scratches the surface on the many different types of marshalling that can take place. Hopefully it has given you a good starting point for figuring out more advanced marshalling by yourself. If you have any questions or comments feel free to send me an email via my Contact page.

-Greg Dolley

*Get new posts automatically! Subscribe via RSS here. Want email updates instead? Click here.

Posted in C++/CLI, Tips and Tricks | 5 Comments »

Part 1: How to Make Native Calls from Managed Code in C++/CLI

Posted by gregd1024 on January 30, 2008

Sometimes when working in a .NET environment we inevitably need to call a native function. With most .NET languages the programmer doesn’t need to have knowledge of the marshalling going on behind the scenes. However, programming in C++/CLI happens to be the exception.

While C++/CLI certainly does a better job at abstraction than the old managed C++ language in .NET 1.0, it doesn’t compare to the ease of C# or VB.NET.

This tutorial will be split into two posts: basic marshalling and advanced marshalling. This one will cover the basics – how simple data types are marshalled such as strings and character arrays.

The Marshal Class

Take a look at the following namespace:

  • System::Runtime::InteropServices

This namespace contains a class called “Marshal.” It is very versatile and will handle all the marshalling techniques presented in this tutorial. For most cases of managed to native calls, you’ll never have to look anywhere else.

Functions Which Take String Arguments

First, let’s look at a function which takes a series of native strings. We’re going to look at “printf()”. Since native strings are really just character buffer pointers, we need to convert a .NET “String” object into a character buffer pointed to by an IntPtr struct. Once we have an IntPtr, grabbing the native pointer comes down to calling one of its member functions. To do the first step we use the following function in Marshal:

  • System::IntPtr Marshal::StringToHGlobalAnsi(System::String ^s)

This function will allocate a character buffer and return an address via the IntPtr struct. Converting this into a native pointer is a simple matter of calling its “ToPointer()” member function. The “ToPointer()” function looks like this:

  • void *IntPtr::ToPointer(void)

Now we put both functions together like in the following code snippet:

// Get .NET version string, convert to native char *, and print to screen with printf()

 

Version ^v = Environment::Version;

String ^ver_string = String::Format(“{0}.{1}.{2}”, v->Major, v->Minor, v->Build);

 

char *native_string = (char *)Marshal::StringToHGlobalAnsi(ver_string).ToPointer();

printf(“.NET version: %s\r\n”, native_string);

Marshal::FreeHGlobal(IntPtr((void *)native_string));

We must call “FreeHGlobal()” because the previous call to “StringToHGlobalAnsi()” allocated a buffer of characters on the unmanaged heap (just like calling “malloc()” in C or C++). Otherwise we would end up with a memory leak.

Functions Which Return Strings

OK, now we’re going to look at native functions which return strings. This time, we need to do the opposite of what we did in the last section – take a char pointer buffer (or unicode buffer) and convert it into a .NET String object. We do this via the “PtrToStringAnsi()” function inside the Marshal class. It looks like this:

  • System::String ^Marshal::PtrToStringAnsi(System::IntPtr ptr)

You must pass it a managed pointer wrapper instead of a native pointer, but the IntPtr object has a constructor that will do this conversion automatically. You’ll see how to use it in the following example.

We’re going to read some characters from a file via the native “fread()” function. This function fills in a buffer pointed to by the first parameter and returns the number of bytes read. If the function had instead returned a pointer directly via its return value, the conversion technique would be no different.

char file_buffer[256];

FILE *fp = fopen(“c:\\Temp\\test.txt”, “rb”);

 

memset(file_buffer, 0, sizeof(char)*256);

fread(file_buffer, sizeof(char), 10, fp);

String ^file_buffer_string = Marshal::PtrToStringAnsi(IntPtr((void *)file_buffer));

 

fclose(fp);

Objects and Structures

Strings and character buffers may not be the only thing you need to marshal between a managed context and a native call. You may come across a function that takes some predefined object – such as a native struct or class. These cases will be covered in part two of this tutorial which I will be posting in the next couple days.

As always you can get new posts automatically using this RSS feed. Or if you prefer email updates, click here.

-Greg Dolley

Posted in C++/CLI, Tips and Tricks | 2 Comments »

Tip: What You Didn’t Know About Car Chargers

Posted by gregd1024 on January 20, 2008

What didn’t you know car chargers (i.e. iPod car charger, cell phone car charger, etc.)? Simple: you don’t need them! Yup, that’s right – don’t ever buy a “car” version of a charger for a device that comes with a regular wall A/C adapter. How come?

With a car charger you can only charge one device at a time and only the device it was made for. What if you could charge anything in your car with a device’s regular A/C adapter? Not only that, what if you could charge more than one device at a time?

There’s an easy way to do this: instead of buying a car charger, buy a DC/AC Inverter for your car! What this device does is convert your cigarette lighter socket into a standard wall outlet. Then you can plug the regular A/C adapter into the inverter – as if it was a wall in your house! Also, the cheapest inverters come with two outlets (others have four, six, etc.), so you can charge more than one device at a time.

Best of all, an inverter costs only about $25 dollars, not those rip-off prices you see for typical car chargers ($60 – $120 dollars). Since most people have no clue that an inverter will do the same thing, the OEM’s know they can charge more.

I’ve been using the same inverter for about a year and it works great! It has even survived amazingly hot summer temperatures when my car has been parked under the sun for an extended period (my car’s cabin thermometer would typically read 145 – 175 degrees). That’s what I call durability!

I’d recommend buying an inverter with a power rating of 150 watts. It’s probably more than you’ll ever need. You can charge a high powered laptop, cell phone, and a few other small devices all at the same time with that amount of power. Most laptops need 75 watts, but high powered one’s could require 90 or 120 watts. iPods, PDA’s and other small devices use almost nothing – about five watts max.

You can buy an inverter at any electronics store. I got mine at Fry’s Electronics, but Circuit City and Best Buy should have them too.

-Greg Dolley

*Get new posts automatically! Subscribe via RSS here. Want email updates instead? Click here.

Posted in Miscellaneous, Tips and Tricks | 7 Comments »

How to Fix – "C2039: ‘GetCurrentDirectoryA()’ : is Not a Member of ‘System::IO::Directory’"

Posted by gregd1024 on January 10, 2008

Have you ever received either one of these annoying error messages from the MSVC++ 9.0 compiler?

“C2039: ‘GetCurrentDirectoryW’ : is not a member of ‘System::IO::Directory'”

“C2039: ‘GetCurrentDirectoryA’ : is not a member of ‘System::IO::Directory'”

You’ll get this error when converting a native C++ project to a MC++ (managed) project and somewhere in your code there is a call to Directory::GetCurrentDirectory(). Below is a very simple example:

#include “stdafx.h”

#include <windows.h>

 

using namespace System;
using namespace System::IO;

 

int main(array<System::String ^> ^args)
{
    Console::WriteLine(L”Dir: “+Directory::GetCurrentDirectory()); // Error!
    Console::ReadKey();
    return 0;
}

The reason for the error is that “GetCurrentDirectory” is also defined as a macro in windows.h. The macro expands to “GetCurrentDirectoryA” or “GetCurrentDirectoryW.” So in the example above, the compiler actually sees “Directory::GetCurrentDirectoryW” which obviously isn’t defined in the “Directory” class.

The fix is simple – just “#undef” the macro:

#include “stdafx.h”

#include <windows.h>

 

using namespace System;

using namespace System::IO;

 

#undef GetCurrentDirectory

 

int main(array<System::String ^> ^args)

{
    Console::WriteLine(L”Dir: “+Directory::GetCurrentDirectory()); // OK

    Console::ReadKey();

    return 0;

}

Now the compiler sees the real “GetCurrentDirectory” function and there are no compile errors. 🙂

-Greg Dolley

Subscribe via RSS here. Want email updates instead? Click here.

Posted in General Programming, Tips and Tricks | 5 Comments »

How to Fix Visual Studio Bug: "’/RTC1′ and ‘/clr’ Options are Incompatible"

Posted by gregd1024 on December 31, 2007

Have you ever received this error when converting a native C++ project to MC++?

1>cl : Command line error D8016 : ‘/RTC1’ and ‘/clr’ command-line options are incompatible

While, yes, it’s true that ‘/RTC1’ (basic runtime checking) with ‘/clr’ (.NET support) are incompatible options, the problem is there’s no place in the Visual Studio IDE to turn off ‘/RTC1’ once it’s set (not even from the command line editor). The Project Settings dialog just lists different modes of runtime checking without a “disable” option:

basic_runtime_checks_image

In order to fix this problem, follow these steps:

  • Open up your “vcproj” file in a regular text editor.
  • Search for all the strings that look like:

BasicRuntimeChecks=”3″

  • Replace all instances with this string:

BasicRuntimeChecks=”0″

In your project file the “BasicRuntimeChecks” variable may not necessarily equal “3.” It just happened to be the default in my project. Whatever number appears as your default just replace it with “0” and that should fix the problem.

-Greg Dolley

Subscribe via RSS here. Want email updates instead? Click here.

Posted in General Programming, Tips and Tricks | 8 Comments »