Saturday, February 25, 2012

Making a DVD for Windows in MacOS X.

Windows, it seems, is not very file system savvy. I wanted to back up my MacOS files to a DVD, but then I decided that I wanted a copy on my Windows machine. The thing that you must understand is that there is a great physical distance between the machines. It was easiest to just make blank DVD image in Mac OS by using Disk Utility, and then fill it. The CDR format that MacOS used did not work when I copied that file to Windows to burn because it was not an ISO. It seems that windows still does not use UDF on DVDs, so you need to put in the old ISO extensions.

sudo hdiutil makehybrid -joliet -iso dvdimage.cdr -o dvdimage.iso

The only issue is that the extensions require disk space, so 100MiB on the DVD was taken by the conversion, so leave a little bit of empty space on the disk.

Friday, February 17, 2012

System.DllNotFoundException: Unable to load DLL, figured it out.

In my previous post, I was trying to make a DLL that would load from C#, and in one case, had the exception:

System.BadImageFormatException: An attempt was made to load a program with an in
correct format. (Exception from HRESULT: 0x8007000B)

Interestingly, I found that I could also generate this one by solving the problem above:

System.DllNotFoundException: Unable to load DLL 'simpleDLL.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

If one has .NET 2.0, the C# binds as 32-bit, so an explicit 64-bit DLL might try to call a 32-bit DLL. I used Microsoft's sysinterals to understand what was happening and Dependency Walker to check my DLLs.

In closing, if you get a System.DllNotFoundException even when you DLL is in the same directory as your executable, it is a binding issue and change from .NET 2.0 to something higher (I used 3.5). If you get a BadImageFormatException, it is due to the binary format, so be sure that the DLL matches your machine bit width.

Sunday, February 12, 2012

DLLs and C#

Hardware is not a mystery to me. C is not a mystery to me. UNIX is not a mystery to me.
Windows is a mystery to me. I had to modify a C# application to use a DLL written in C++.

I started by reading all of the documentation, which took about 3 days. Creating Reusable Code seemed to be a good place to start; however, it's terribly. I have created the demo program and documented the problems along the way which is what Microsoft should have done in the first place.

I have created a sample project that has a DLL which is called from C#. I looked for a long time for a functional example. This is a functional example by someone who does not know the Windows lingo or assumptions. The source code is available at the bottom of the page as zip files. In summary, I started on VS2005, but ended up in VS2010.

In VS2005, I created a solution (this is MS term for a tome of projects) called "DLLExampleWithCSharp". I then created a project called "simpleDLL" that is a Win32API project that is a DLL through the project wizard and exported the functions. This is the first part of where I went wrong. The wizard only partially completes the requirements for a DLL. If you will be including the DLL through headers, it is a fine method, but for "unmanaged DLL" code, it will not work for you. I will return to this topic later.

Using the wizard's format, I changed my function to be
(simpleDLL.h)
SIMPLEDLL_API size_t simpleDLL_message(char *stringio, size_t ui_length);
(/simpleDLL.h)
(simpleDLL.c)
SIMPLEDLL_API size_t simpleDLL_message(char *stringio, size_t ui_length)
{
 char *cp_message = "suigin spars with windows.\n";
 size_t i_message_length = strlen(cp_message);
 if(ui_length < i_message_length)
 {
  i_message_length = ui_length;
 }
 strncpy(stringio,cp_message, i_message_length);
 return(i_message_length);
}
(/simpleDLL.c)
I now have a function that will take a string pointer and allocation length, and copy the cp_message into it. I now make my C# application to call the DLL. (CSharpCallsDLL.cs)
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;  //required to call the DLL
namespace CSharpCallsDLL
{
 class Program
 {
  [DllImport("simpleDLL.dll")]
  public static extern UInt32 simpleDLL_message(StringBuilder stringio, UInt32 ui_length);
  static void Main(string[] args)
  {
   StringBuilder s_str = new StringBuilder("000000000");
   UInt32 ui_len = (UInt32)s_str.Length;
   try
   {
    UInt32 ui_result = simpleDLL_message(s_str, ui_len);
    Console.Out.WriteLine("The result:");
    Console.Out.WriteLine("ui_result=" + ui_result + ", stringio=" + s_str);
   }
   catch (Exception e)
   {
    Console.Out.WriteLine(e);
   }
  }
 }
}
(/CSharpCallsDLL.cs) I then start up my Visual Studio 2005 Command Prompt and run the program, CSharpCallsDLL.exe.
C:\Users\suigin\Documents\Visual Studio 2005\Projects\DLLExampleWithCSharp\CSharpC
allsDLL\bin\Release>CSharpCallsDLL.exe
System.DllNotFoundException: Unable to load DLL 'simpleDLL.dll': The specified m
odule could not be found. (Exception from HRESULT: 0x8007007E)
   at CSharpCallsDLL.Program.simpleDLL_message(String stringio, UInt32 ui_length
)
   at CSharpCallsDLL.Program.Main(String[] args) in C:\Users\suigin\Documents\Visu
al Studio 2005\Projects\DLLExampleWithCSharp\CSharpCallsDLL\Program.cs:line 30
And, it dies with "System.DllNotFoundException". The DLL is not found, so I either have to add it to my path, but I will just copy the DLL. "copy simpleDLL.dll ..\CSharpCallsDLL\bin\Release\.", so simpleDLL.dll is not in the same directory as CSharpCallsDLL.exe. It is also worth noting that C# projects and C++ projects have a different directory layout, which I found to just be a quirk, so be sure that you are in the correct "Release" directory. The next error that I encountered was "System.BadImageFormatException".
C:\Users\suigin\Documents\Visual Studio 2005\Projects\DLLExampleWithCSharp\CSharpC
allsDLL\bin\Release>CSharpCallsDLL.exe
System.BadImageFormatException: An attempt was made to load a program with an in
correct format. (Exception from HRESULT: 0x8007000B)
   at CSharpCallsDLL.CSharpCallsDLL.simpleDLL_message(String stringio, UInt32 ui
_length)
   at CSharpCallsDLL.CSharpCallsDLL.Main(String[] args) in C:\Users\suigin\Documen
ts\Visual Studio 2005\Projects\DLLExampleWithCSharp\CSharpCallsDLL\CSharpCallsDL
L.cs:line 30
The official Microsoft documentation for System.BadImageFormatException is rather worthless, and I could guess what the problem was. Basically, my version of .NET is too old for what I was trying to do. Visual Studio 2005 is .NET 2.0, and I have 64-bit Windows7 machine. I generally develop for the lowest possible machine; however, in this case, I'll have to upgrade. Here enters Visual Studio 2010. (In other news, I would really love to know how to fix that error, but I the best I could find was here, but I couldn't understand it.) I redid everything that I did above, and it magically got past that exception, and went on to the next one.
C:\Users\suigin\Documents\Visual Studio 2010\Projects\DLLExampleWithCSharp\CSharpC
allsDLL\bin\Release>CSharpCallsDLL.exe
System.EntryPointNotFoundException: Unable to find an entry point named 'simpleD
LL_message' in DLL 'simpleDLL.dll'.
   at CSharpCallsDLL.CallDLL.simpleDLL_message(String stringio, UInt32 ui_length
)
   at CSharpCallsDLL.CallDLL.Main(String[] args) in C:\Users\suigin\Documents\Visu
al Studio 2010\Projects\DLLExampleWithCSharp\CSharpCallsDLL\CallDLL.cs:line 33
The entry to the DLL is the most important thing, and System.EntryPointNotFoundException says that I did not call the correct function name. There should be a method to recall a method manifest, but there does not seem to be. This is where Microsoft should have example code. The issue is that C# cannot see the entry point into the DLL even though I know it is there. I found that there was a tool which I could use to see the entries from the VS2010 shell, called dumpbin (I note that other pages for dumpbin are terrible).
C:\Users\suigin\Documents\Visual Studio 2010\Projects\DLLExampleWithCSharp\CSharpC
allsDLL\bin\Release>dumpbin /exports simpleDLL.dll
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file simpleDLL.dll

File Type: DLL

  Section contains the following exports for simpleDLL.dll

    00000000 characteristics
    4F368F07 time date stamp Sat Feb 11 10:53:43 2012
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 00001010 ?simpleDLL_message@@YAIPADI@Z = ?simpleDLL_message@@YA
IPADI@Z (unsigned int __cdecl simpleDLL_message(char *,unsigned int))

  Summary

        1000 .data
        1000 .rdata
        1000 .reloc
        1000 .rsrc
        1000 .text
Wow, what a function name. I found that I could use that awful thing to call my function, but I knew there must be a better way. I seems that it did not know how to make nice names by default. I found an obscure note in a linker how-to regarding a possibility from the days of Win 3.11, which I can no longer find the link. If you include 'extern "C"', it will solve some problems that were not specific. My new function declaration is:
extern "C" SIMPLEDLL_API size_t simpleDLL_message(char *stringio, size_t ui_length);
Upon compilation, the DLL entry makes much more sense.
C:\Users\suigin\Documents\Visual Studio 2010\Projects\DLLExampleWithCSharp\CSharpC
allsDLL\bin\Release>dumpbin /exports simpleDLL.dll
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file simpleDLL.dll

File Type: DLL

  Section contains the following exports for simpleDLL.dll

    00000000 characteristics
    4F3693CF time date stamp Sat Feb 11 11:14:07 2012
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 00001010 simpleDLL_message = _simpleDLL_message

  Summary

        1000 .data
        1000 .rdata
        1000 .reloc
        1000 .rsrc
        1000 .text
The addition of 'extern "C"' has made all of the difference in the entry point definition. The program now runs and gives the following output:
C:\Users\suigin\Documents\Visual Studio 2010\Projects\DLLExampleWithCSharp\CSharpC
allsDLL\bin\Release>CSharpCallsDLL.exe
The result:
ui_result=9, stringio=suigin sp
In summary, I now know the syntax for C++ DLL calls from C#. The project files are the working Visual Studio 2010 project and the broken Visual Stuidio 2005 project.

Wednesday, February 8, 2012

Virtual CDROM and Windows 7

I probably should update this more often, but I only seem to do it when something gets me in a ruckus, and today is Windows and mounting ISOs.

I have never understood why Microsoft has never included inherent loopback mounting functionality in Windows, particularly when they release just about everything as an .iso. Interestingly, it's not just me: http://connect.microsoft.com/WindowsServerFeedback/feedback/details/351231/mount-iso-files

To mount a CDROM/DVD in Windows 7/Vista, I have used:
http://www.slysoft.com/en/virtual-clonedrive.html
http://www.magiciso.com/tutorials/miso-magicdisc-history.htm
I seem to prefer MagicDisc though.

On Windows XP, Microsoft supplies a tool:
http://download.microsoft.com/download/7/b/6/7b6abd84-7841-4978-96f5-bd58df02efa2/winxpvirtualcdcontrolpanel_21.exe

And with those tools, I now have the same functionality that I had with System 6 on a Mac IIsi.