Converting some VB.NET code to C# - Need Advice - c#

I am working with the original MMO that ever opened called VZones and they have a dll file that allows you to call the functions from this dll to do certain things within the program.
I have found some VB.NET code and the problem I am having is converting it to a way that will work with C# (using VS 2017)
You setup the DLL calls with this, which works fine:
[DllImport("vzdapi.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern string DapiGetText(string BufferIn, int LengthIn, int Timeout);
The problem is I need to convert this VB.NET code that is from someone else to what will work in C#. I have tried a few different options but the program just closes and never gives me an error.
object obj1 = (object)new string(char.MinValue, 32678);
vzText.Text = this.DapiGetText(Conversions.ToString(obj1), Strings.Len(RuntimeHelpers.GetObjectValue(obj1)), 1500);
The problem arises in the Conversions.ToString part, which I have of course tried to just make obj1.ToString() and that may work fine but the place I think is getting caught up is when it tries to run the middle code "Strings.Len(RuntimeHelpers.GetObjectValue(obj1))".
Does anyone have any help into getting this into something that will work in C#? Thanks!

I'm wondering if the conversions are necessary as the initial object you define is already a string, try the following solution:
string obj = new string(char.MinValue, Int16.MaxValue);
vzText.Text = this.DapiGetText(obj, obj.Length, 1500);

Related

Run compiled C# from exe

I am working on my own scripting language using C# and ANTLR, and I've been able to implement almost everything I wanted.
I know that one can't make a perfect language on themselves, so I wanna build in a way to import functions from C# scripts. For that, i've researched about DLLImport anc calling functions from that, but i just cant seem to get that to work.
I am currently stuck at an EntryPointNotFoundException, however, my system uses object instead of strictly defined types, which threw a PInvoke: cannot return variants exception.
Here's some code i tried:
Program.cs
[DLLImport("mydll.dll", EntryPoint = "main", Charset = Charset.Unicode)]
static extern object main(object[] args)
main(Array.empty<object>())
C# class library used for creatng the dll
public class Test
{
public static object main(object[] args)
{
Console.WriteLine("Test sucessful!");
return 0;
}
}
Be forgiving if i am just overthinking this or don't know something obvious, I am still a pretty inexperienced developer.
For everyone who tries to acheive the same thing, here is the solution based on #PMF's comment:
var asm = Assembly.LoadFrom("YourDLL.dll");
var type = asm.GetType("YourNamespace.YourClass");
var method = type.GetMethod("YourMethod");
object[] args = new object[0];
method.Invoke(Activator.CreateInstance(type, Array.Empty<object>()), args);

Undefined symbols when trying to use native C++ .so in Mono Pinvoke

Recently I have been trying to get some Point Cloud Library functionality going in my .NET framework application, and considering that there is no completely functional wrapper for PCL for C#, I made my own for a few functions as a test. Something like this:
[DllImport(DllFilePath, CallingConvention = CallingConvention.Cdecl)]
public extern static IntPtr StatisticalOutlierFilter(IntPtr data, int length, int meanK = 50, float mulThresh = 1.0f);
Which calls a function from a C++ library, such as this:
EXPORT VectorXYZ* StatisticalOutlierFilter(VectorXYZ* data, int length, int meanK, float mulThresh) {
auto processedCloud = process.StatisticalOutlierFilter(data, length, meanK, mulThresh);
auto processedVector = convert.ToVectorXYZ(processedCloud);
return processedVector;
}
Where EXPORT is defined such for gcc:
#define EXPORT extern "C" __attribute__ ((visibility ("default")))
And relevant processing function from PCL is implemented such in a class (note that the returned is a boost shared pointer):
PointCloud<PointXYZ>::Ptr Processors::StatisticalOutlierFilter(VectorXYZ* data, int length, int meanK, float mulThresh) {
auto cloud = PrepareCloud(data, length);
PointCloud<PointXYZ>::Ptr cloud_filtered(new PointCloud<PointXYZ>);
StatisticalOutlierRemoval<PointXYZ> sor;
sor.setInputCloud(cloud);
sor.setMeanK(meanK);
sor.setStddevMulThresh(mulThresh);
sor.filter(*cloud_filtered);
return cloud_filtered;
}
This procedure works well with a dll built w/MSVC and running the whole thing on Windows, though the final target is gcc/Linux/Mono, where I get several errors of the following type (this is from mono debug):
'libavpcl_dll.so': '/usr/lib/libavpcl_dll.so: undefined symbol: _ZN3pcl7PCLBaseINS_8PointXYZEE13setInputCloudERKN5boost10shared_ptrIKNS_10PointCloudIS1_EEEE'.
I have investigated quite a bit so far, and have set my CmakeLists.txt to set(CMAKE_CXX_VISIBILITY_PRESET hidden) , therefore, I imagine, only functions I defined as EXPORT should be visible and imported - however, that is not the case, and I get the aforementioned errors. PCL was installed on Windows via vcpkg and on Xubuntu via apt. I am somewhat stumped as to what is the error source, considering the code runs well on windows, and builds without issue on Linux. Thanks.
I've been running into the same issue as you. I solved it by adding each reference library into the CMakeLists.txt file (I was missing the reference files which gave me the similar missing symbol issues).
I'm at the 'I don't know why this worked' stage but I can give you step by step implementation (I'm also trying to use DllImport into .NET on Linux).
Started with this:
https://medium.com/#xaviergeerinck/how-to-bind-c-code-with-dotnet-core-157a121c0aa6
Then added my in-scope files thanks to the main comment here: How to create a shared library with cmake?:
add_library(mylib SHARED
sources/animation.cpp
sources/buffers.cpp
[...]
)
run cmake .
run make -j$(grep -c ^processor /proc/cpuinfo)
copy path to .so file
DllImport path from above to my c# app

ICE: trying to add a local var with the same name, but different types. during [_RegisterClipboardFormat]

I have a PoC to use some existing Java-codebase in some UWP-app using the most current Visual Studio Community 19 version 16.3.2 and the latest released IKVM 8.1.7195.0. The app builds and runs fine in Debug-mode, but fails to build already in Release-mode with the following error:
MCG0004:InternalAssert Assert Failed: ICE: trying to add a local var
with the same name, but different types. during
[_RegisterClipboardFormat] Ams.Oms.Poc
RegisterClipboardFormat is part of IKVM:
#DllImportAttribute.Annotation(value = "user32.dll", EntryPoint = "RegisterClipboardFormat")
private native static int _RegisterClipboardFormat(String format);
#cli.System.Security.SecuritySafeCriticalAttribute.Annotation
private static int RegisterClipboardFormat(String format)
{
return _RegisterClipboardFormat(format);
}
https://github.com/ikvm-revived/ikvm/blob/master/openjdk/sun/awt/IkvmDataTransferer.java#L95
What I'm wondering is which local variable the error message is referring to? Might be something added implicitly or might have to do with String in Java vs. string in C#? OTOH that file is clearly named .java.
Didn't find much about the error message in general, only the following two links seems to be more interesting:
Variables having same name but different type
Why doesn't C# allow me to use the same variable name in different scopes?
So I'm currently even unsure where the message comes from, Visual Studio/C# directly or IKVM during running code during building Release-mode. I strongly suspect the error is coming from Visual Studio/C#, though.
Searching for the function itself doesn't reveal much of help as well:
Sorry, AWT is not a supported part of IKVM.
https://sourceforge.net/p/ikvm/bugs/225/
Others seemed to have the same problem, because CN1 simply disabled that code entirely in their fork of IKVM:
//#DllImportAttribute.Annotation(value = "user32.dll", EntryPoint = "RegisterClipboardFormat")
//private native static int _RegisterClipboardFormat(String format);
#cli.System.Security.SecuritySafeCriticalAttribute.Annotation
private static int RegisterClipboardFormat(String format)
{
throw new Error("Not implemented");
//return _RegisterClipboardFormat(format);
}
https://github.com/ams-ts-ikvm/cn1-ikvm-uwp/blob/master/openjdk/sun/awt/IkvmDataTransferer.java#L95
Any ideas? Thanks!
There seems to be a workaround by not changing any code at all: The settings of the Release-build contain a checkbox if to use the .NET native toolbox for the build, which is enabled by default. By disabling that the build succeeds without any code change and is as fast as the Debug-build again. Before changing that, the Release-build took a lot longer as well.
Don't know what that means regarding actually calling native code, if that fails or not, because my app doesn't use those. I guess it would fail, depending on if it works in Debug or not. Additionally, I'm not sure if the Windows store accepts such a modified Release-build, but as UWP-apps aren't forced to use native code at all, I guess there's a good chance things are going to work.

Get computer name via WSOCK32.DLL in C#

I am migrating some VB6 code to C# (.NET 4.5.2) and got stuck into a piece of code that is calling the gethostname method from the WSOCK32.DLL to apparently retrieve the computer name. All the code samples that I have found so far point to
this code. And since I haven't been able to successfully PInvoke the gethostname method in C#, I can't help asking if is there an alternative to it.
This
[DllImport("WSOCK32.DLL", SetLastError = true)]
internal static extern long gethostname(string name, int nameLen);
string host = string.Empty;
var res = gethostname(host, 256);
fails with the following error:
The runtime has encountered a fatal error. The address of the error was at 0x6a13a84e, on thread 0xd88. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
I also read about using System.Environment.MachineName or the "COMPUTERNAME" environment variable, but I am interested in how the result differs than what gethostname method returns.
What options do I have?
I am developing on a 64bit system but I don't know if/how this affects working with WSOCK32.DLL since I found no documentation about it.
You cannot send an zero-length immutable C# string and expect it to get turned into something new. You are probably experiencing a buffer overflow. You need to use a StringBuilder instead:
[DllImport("WSOCK32.DLL", SetLastError = true)]
internal static extern long gethostname(StringBuilder name, int nameLen);
var builder = new StringBuilder(256);
var res = gethostname(builder, 256);
string host = builder.ToString();
More info here:
Passing StringBuilder to PInvoke function
C# PInvoke out strings declaration
http://pinvoke.net/default.aspx/ws2_32/gethostname.html
Also, there is really no reason for using that really old DLL function to get the name of the local computer. Just use System.Environment.MachineName instead.

ShSetFolderPath works on win7, doesn't on XP

I'm trying to use ShSetFolderPath function in C#. I work on Win7, I've managed to use ShSetKnownFolderPath and it works fine.
Since this function is unavaible in WinXP, i tried to invoke ShSetFolderPath. Because i'm not familiar with invoking, I've done some searching and found something on some French forum. I don't speak French, but this declaration makes sense (as written in Remarks of function documentation in MSDN library):
[DllImport( "Shell32.dll", CharSet = CharSet.Unicode, EntryPoint = "#232" ) ]
private static extern int SHSetFolderPath( int csidl, IntPtr hToken, uint flags, string path );
I call it like that:
private static int CSIDL_DESKTOP = 0x0000;
public static void SetDesktopPath(string path)
{
int ret;
ret = SHSetFolderPath(CSIDL_DESKTOP, IntPtr.Zero, 0, path);
if (ret != 0)
{
Console.WriteLine(ret);
Console.WriteLine(Marshal.GetExceptionForHR(ret));
}
}
It works in Win7, but in XP function returns -2147024809, which means "Value does not fall within the expected range".
My guess is, it's something wrong with Dll importing. Any idea?
Funny thing.
I've taken another look at CSIDL list. And I've realized I was trying to change some "low-level" reference (i guess) to desktop:
CSIDL_DESKTOP = 0x0000, // <desktop>
While I actually wanted to change just folder location, and i should've use this:
CSIDL_DESKTOPDIRECTORY = 0x0010, // <user name>\Desktop.
And THIS works.
It explains everything. Shame on me.
Nah, that's not it. The error code, converted to hex, is 0x80070057. The 7 indicates a Windows error, 57 is error code 87, ERROR_INVALID_PARAMETER, "The parameter is incorrect".
A couple of possible reasons. First is that entry point #232 isn't actually the entry point for SHSetFolderPath(). You might be calling a different function, it wouldn't know what to do with the argument values you pass. Hard to say, it is an unnamed entry point on XP's version of shell32.dll. Or it could be that XP just isn't happy about you changing the desktop folder path. Not that surprising, there's a heckofalot it has to do to actually implement that, refreshing all Explorer.exe views, rebuilding the desktop contents and whatnot.
Check this thread for possible help.

Categories