.NET Managed DLL passing and receiving information

Thought I share a tip when passing information to and from .NET assemblies.

I am giving up getting full support for unicode characters in my e-mails and am looking into sending my e-mails from .NET instead.

I have always been challenged with getting data back, and usually program just crash, so I have resolved to write only and returing simple strings.

However, the DLLExport package has a way that works fine for more complex tasks.
One can define a struct that has exact size.

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
 public struct EmailInfo
 {
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
     public String emailTo;

     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
     public String emailCC;
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1001)]
     public string emailText;
 }

//my function takes a struct of this type as parameter.

 [DllExport("AskEmailInformation",CallingConvention = CallingConvention.Winapi)]
 public static int AskEmailInformation(ref EmailInfo info)
 {
   //read anything from passed group
 }

In Clarion, I declare the function to take a LONG parameter. This will be used to pass the group.

Module('CpDotNetUtils')
			AskEmailInformation(Long emailGroup),long, name('AskEmailInformation'),Pascal, raw,dll(_fp_)
	end

!the info group is defined like this. In this case I have to use Cstring, else the null terminator stops us from reading elements beyond element 1.

info                        group
emailTo                          Cstring(256)
emailCC                         Cstring(256)
emailText                        cstring(1001)
				end

!After loading the library and function, I just send the address

AskEmailInformation(address(info))

Then anything I enter in .NET window is readable in Clarion. However, the same character restrictions apply, so for example storing the data in a DB strips of all the attributes.

Not your question, but of course sending emails from nettalk allows full unicode support.

I use NetTalk, but the characters are distorted when strings are passed as parameters, even before entering the e-mail function. I can make program understand the characters with windows settings, but it messes.with the data.

One of the really hard things to grasp when dealing with these strings, is that “looking at them” can be tricky. Because the way in which you “look” can alter what you see. (Let’s call it the Unicode Heisenberg Principle.)

Probably the best way to avoid this is to look not t the strings themselves, but rather as their raw representation. For this I use StringTheory.PeekRam(st:hex).
This sends the contents of the string to debugview, but importantly not “as a string” but as raw byte values.

The problem with sending it to debugview as text, or MESSAGE, or the screen is that all those approaches require that the receiver (the screen in this case) decide “the encoding of the string” before displaying it to you. In Clarion’s case that means it assumes the string is ANSI encoded.
So “displaying” a string can be the root of your problem - you’re seeing an “interpretation” of what is actually in the RAM. Using PeekRam you see the “rawness” of it, which can help you both understand the actual encoding, which then leads you to more accurately converting the encoding to the one you want.

I’m assuming that in your dictionary, for this table, you have the OEM switch OFF.

I would start by simply reading a record. And then doing a PeekRam on the field. Then in the output you look to see “what number is used” for your special character. Is that an ANSI number, or is it a unicode Number(s). This is step number 1. Only by inspecting this string can you know what the encoding is, and from there proceed.

[In some cases different records have different encodings. This is especially true if your input can come from multiple laces - like desktop app and web app. It’s also true if users paste data from the clipboard - because the encoding on the clipboard can be anything as well.]

In short - this may seem like a lot of work, but fully understanding how things are stored is critical to using them correctly.

Often a structure like that has Info_Size LONG as the first member so the callee can check it to verify it’s what was expected and allow different versions.

Will see in API like:

typedef struct _OSVERSIONINFOA {
  DWORD dwOSVersionInfoSize; <=== Size(OSVERSIONINFOA)
  DWORD dwMajorVersion;
  DWORD dwMinorVersion;
  DWORD dwBuildNumber;
  DWORD dwPlatformId;
  CHAR  szCSDVersion[128];
} OSVERSIONINFOA;

The EX has more fields on the end so a different size, this is the PInvoke:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]  
struct OSVERSIONINFOEX {
   public int dwOSVersionInfoSize;  
   public int dwMajorVersion;  
   public int dwMinorVersion;  
   public int dwBuildNumber;  
   public int dwPlatformId;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
   public string szCSDVersion;
   public UInt16 wServicePackMajor;  
   public UInt16 wServicePackMinor;  
   public UInt16 wSuiteMask;
   public byte wProductType;  
   public byte wReserved;

}