Intercommunication with two dlls but without known each other - c#

I need a struct as function parameter that is not known in the given dlls.
I want to process two different types. The types are generated as two different dlls. I instanciate many of those types via Xml-Serialization. A third party application load the dlls and start to make instances from the given xml files. Then i iterate over the instances and call a function from the dll to do something like an export. On processing i get global data i want to share to the next instance. The problem on this is, they dont know about the global data. They got only a function parameter typeof(object). If i implement the same struct in each of those dlls i cant cast it into the struct, because dll A and dll B are different. So what can i do... ?
//Third party application
object globalData = null; //Type is not known in this application
//serialisation here...
I_SVExternalFruitExport[] instances = serialisation(....);
foreach(I_SVExternalFruitExport sv in instances)
{
globalData = sv.ProcessMyType(globalData, sv);
}
//--------------------------------------------------------
// one DLL AppleExport implements I_SVExternalFruitExport
using Apple.dll
struct s_mytype // s_mytype is known in this dll
{
List<string> lines;
...
}
local_sv;
public object ProcessMyType(object s_TypeStruct, object sv)
{
local_sv = (Apple)sv;
if(globalData != null) globalData = new s_mytype();
else globalData = (s_mytype)s_TypeData;
//Do Stuff
return globalData;
}
//--------------------------------------------------------
// second DLL OrangeExport implements I_SVExternalFruitExport
using Orange.dll
struct s_mytype //s_mytype is known in this dll
{
List<string> lines;
...
}
Orange local_sv; // Orange is known because of using Orange.dll
public object ProcessMyType(object s_TypeStruct, object sv)
{
local_sv = (Orange)sv;
if(globalData != null) globalData = new s_mytype();
else globalData = (s_mytype)s_TypeData; //This cast says... s_TypeData is not s_mytype because of two dlls A and B but i know they have the same structure.
//Do Stuff
return globalData;
}
I need a struct that is known in my dlls but not in the third party application, because i want to regenerate my dlls, maybe with some more information in the struct. I dont want to update my third party application every time i change my dlls.

I think i got an answer:
I will make my struct s_mytype{} also serializeable:
[Serializable]
public struct s_mytype
{
public List<string> lines;
[System.Xml.Serialization.XmlElementAttribute("Lines", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string[] Lines
{
get { return lines.ToArray(); }
set { lines.AddRange(value); }
}
}
My function "ProcessMyType()" now have to return a string with xml data:
public string ProcessMyType(object s_TypeStruct, object sv)
Now the only thing is, that every instance of an "Apple" or "Orange" have to deserilize the xml first, and it get bigger and bigger with each instance.
My Generator give the garantee that in every dll is the same struct s_mytype.
Maybe this post make the problem more clear. If there is a easier way or a way with less overload like deserialize, please let me know.

Related

What is syntax for creating a class in C# that would be equal to a Module in VB.net

I do almost all of my programming in VB.net (all flavors). I am now been assigned a task to make a new routine in an existing C# application. What I want to be able to do is pass a string variable to a class where I can figure out device type of a symbol handheld and figure out where an executable resides on device.
I am trying to keep the class to contain changes we make going forward in one place.
so a brief description is on a screen there will be a button. on that button click I want pass the text of the button to a (what would be a module in VB) a class and depending on text being passed and device type call a separate executable that lives on the device.
Everything I have tried so far has thrown errors.
On my button click i have
String Reponse = clsCallAction("Activity");
but that gets a message that clsCallAction is a type but is used like a variable.
here is the smaple of clsCallaction
internal static partial class clsCallAction
{
public static object GetPath(object lAppName)
{
string resp = "";
if (lAppName.Equals("Activity"))
{
resp = #"\application\activity.exe";
}
return resp;
}
}
If I put new in front of the clsCallAction("Activity") on button click I get a
cannot create instance of the static class 'clsCalACtion'
appreciate any pointers. very new at C#
It would look something like this:
public static class CallAction
{
public static object GetPath(object lAppName)
{
string resp = "";
if (lAppName.Equals("Activity"))
{
resp = #"\application\activity.exe";
}
return resp;
}
}
And would be used like this:
String Reponse = CallAction.GetPath("Activity");
Don't prefix classes with cls
Avoid using object if possible - it just makes everything harder work than it needs to be.. Kinda like calling everything "thing" - ("Put the thing in the thing and open the thing" is harder to understand than "put the key in the lock and open the door")

Class Array usage generates the error "NullReferenceException: Object reference not set to an instance of an object"

I am currently working on a server system for a game called Reign of Kings. I am using hooks and commands given by the Oxide developers to make my server system. Back in the PAWN Language, we could do something like enumeration of player data inside an array, which converts it to a 2d array - something cool. like PlayerData[playerid][data] and data could be anything from an interger called pAdminLevel to a string called pPassword.
I get it that in C#, things are different. So I tried to replicate the method like this:
pData[] PlayerData = new pData[MAX_PLAYERS];
public class pData
{
private int _admin;
public int admin { get { return _admin; } set { _admin = value; } }
public void ClearInfo()
{
_admin = 0;
}
}
so basically whenever I want to call a player's name, I can use PlayerData[playerid].admin.
But I get the error:
5:13 PM [Error] Failed to call hook 'OnPlayerConnected' on plugin 'ServerCommands' (NullReferenceException: Object reference not set to an instance of an object)
After much testing I made it absolutely sure that the problem is infact the way I call PlayerData[x].admin and PlayerData[x].ClearInfo().
You're not initializing the members of your new array. Unlike in languages like C++, the contents of the array are reference types, and therefore your code is the C++ equivalent of creating an array of pointers and trying to use the members of the array right away.
Try something like this this instead:
pData[] PlayerData = new pData[MAX_PLAYERS];
for(int i=0; i < MAX_PLAYERS; i++)
{
PlayerData[i] = new pData();
}
This will put a new pData object in each element of the array, and your code should then work as expected.

managing memory with c++/cli interop

Most of the code I have seen deletes the pointer in the finalizer/destructor:
public ref class CPPObjectWrapper
{
private:
CPPObject *_cppObject;
public:
CPPObjectWrapper()
{
_cppObject = new CPPObject();
}
CPPObjectWrapper(IntPtr ^ptr)
{
_cppObject = ptr->ToPointer();
}
~CPPObjectWrapper()
{
delete _cppObject;
_cppObject = 0;
}
!CPPObjectWrapper()
{
if (_cppObject != 0) delete _cppObject;
}
IntPtr^ GetPointer()
{
return gcnew IntPtr(_cppObject);
}
}
My question is what would be standard practice if the library your wrapping does something like this:
void AddObject(CPPObject *cppObject)
{
// adds to a std::list
}
CPPObject* FindObject(/* criteria */)
{
// return reference to std::list item based on criteria
}
If your c# wrapper does this:
void AddObject(CPPObjectWrapper ^cppObject)
{
_internal->addObject(cppObject->GetPointer()->ToPointer());
}
CPPObjectWrapper^ FindObject(/* criteria */)
{
CPPObject *cppObject = _internal->findObject(/* criteria */);
return gcnew CPPObjectWrapper(gcnew IntPtr(cppObjet));
}
You run into a memory issue because your managed object should not delete the pointer because its referenced in another object. The same is true when returning. Would you simply add functionality to tell your managed wrapper not to free the memory when ownership is transferred?
A classic situation when dealing with mixed mode projects, and your suggestion is OK!
It would make sense to have a bool in the constructor that tells it not to destroy the pointer if the same object is used in another non-wrapped object. The ideal case is that every object was wrapped, and the destruction would be done by the CLR.
You can make a generic base class out of this (using the code you already have there), setting the bool by default by the subclass. You are guaranteed to have this functionality many times over. Another tip is to have a virtual OnFinalize() method that is called from the CLR destructor (!) that can do special operations in the subclass, like calling some special free function provided by the native library.

Type equality check in C#

With
public abstract class CompositionPlugin { ... }
and
public class MyCompositionPlugin : CompositionPlugin { ... }
I want to check if an object's type is equal to a given type:
public class Framework {
public IList<CompositionPlugin> CompositionPlugins = new List<CompositionPlugin>();
public CompositionPlugin GetCompositionPlugin(Type ofType)
{
foreach (CompositionPlugin plugin in CompositionPlugins)
{
if (plugin.GetType().Equals(ofType))
return plugin;
}
throw new ArgumentException("A composition plugin of type " + ofType.FullName + " could not be found");
}
}
Where the method is called like this:
Framework framework = new Framework();
// Adding the plugin to the framework is done by loading an assembly and
// checking if it contains plugin-compatible classes (i.e. subclasses
// of <CompositionPlugin>)
framework.RegisterAssembly("E:\\Projects\\Framework\\MyPlugin\\bin\\Debug\\MyPlugin.dll");
CompositionPlugin plugin = framework.GetCompositionPlugin(typeof(MyCompositionPlugin));
Yet, when testing, this check always fails, even though I most definitely have that type of object in the list that I request.
In my understanding, it should return the first instance of MyCompositionPlugin that is found inside the CompositionPlugins-List.
Is my type check wrong? Why? How is it done correctly?
You want to use IsAssignableFrom on your Type:
if (ofType.IsAssignableFrom(plugin.GetType())
Equals only handles cases where types are exactly the same. IsAssignableFrom also handles the case where ofType may be a type that your plugin inherits from, or an interface that is implemented.
Not an answer but too long for a comment...
Are you sure the issue is not in how you call the method or populate your collection?
The comparison itself should be ok, as demonstrated by this simplified version of your code:
class A {}
bool TestType(A item, Type ofType)
{
return item.GetType().Equals(ofType);
}
now:
Console.WriteLine(TestType(new A(), typeof(A))); // True
Console.WriteLine(TestType(new A(), typeof(string))); // False
EDIT
I think #vcsjones is right. You're trying to compare a derived class to a base class.
In the line foreach (CompositionPlugin plugin in CompositionPlugins) you're declaring plugin to be a CompositionPlugin but in the client code you're comparing it with typeof(MyCompositionPlugin). (RE-EDIT no, I'm wrong, your case corresponds to the 4th of my Console.WriteLines that returns true)
See this example with a truth table for Equals in a scenario similar to yours:
class CompositionPlugin {}
class MyCompositionPlugin : CompositionPlugin {}
// Define other methods and classes here
bool TestType(CompositionPlugin item, Type ofType)
{
return item.GetType().Equals(ofType);
}
now
Console.WriteLine(TestType(new CompositionPlugin(),
typeof(CompositionPlugin))); //True
Console.WriteLine(TestType(new CompositionPlugin(),
typeof(MyCompositionPlugin))); //False
Console.WriteLine(TestType(new MyCompositionPlugin(),
typeof(CompositionPlugin))); //False
Console.WriteLine(TestType(new MyCompositionPlugin(),
typeof(MyCompositionPlugin))); //True
use the keyword is
if (plugin is ofType)
return plugin;
EDIT:
I have to go with #vcsjones on this one. Use the isassignablefrom function.
But if you really think it should work, what I always do is create quick function to write debug text to file.
public class Framework {
public IList<CompositionPlugin> CompositionPlugins = new List<CompositionPlugin>();
public CompositionPlugin GetCompositionPlugin(Type ofType)
{
using(var writer = System.IO.File.CreateText(#"C:\test.log"))
{
writer.WriteLine("ofType: " + ofType.toString());
foreach (CompositionPlugin plugin in CompositionPlugins)
{
writer.WriteLine("plugin: " + plugin.GetType().toString());
if (plugin.GetType().Equals(ofType))
return plugin;
}
}
throw new ArgumentException("A composition plugin of type " + ofType.FullName + " could not be found");
}
}
Turns out, the information I initially left out of the question, deeming it not important, was so after all.
The MyCompositionPlugin and CompositionPlugin are both defined in different assemblies, that the executing program loads dynamically at runtime.
The .NET-Runtime now consideres a type loaded from a different assembly another than the one referenced by the executing assembly, rendering the MyCompositionPlugin-Type in the Program to be considered unequal to the MyCompositionPlugin loaded from another assembly, even if they are actually the same.
The solution to comparing the two for equality (in that they are the same "Class" in the common sense) is to break it down to a string-equality of the defining assemblies, which is arguably dirty, but does the trick.
public CompositionPlugin GetCompositionPlugin(Type ofType)
{
foreach (CompositionPlugin plugin in CompositionPlugins)
if (ofType.AssemblyQualifiedName.Equals(plugin.GetType().AssemblyQualifiedName))
return plugin;
throw new ArgumentException("A composition plugin of type " + ofType.FullName + " could not be found");
}
Cudos to Paolo Falabella who pointed to this question
Your problem is most likely due to the fact that the assembly is loaded a second time and therefor the equality fails, it's best to avoid the assembly being loaded again, so you can use normal type comparison instead of needing to use that dirty string comparison. I had the same problem, my plugin interface was defined in a separate assembly, this assembly was present in the start up folder but also in the plugin folder from which the plugin assemblies where dynamically loaded, by consequence interface type equality failed. I removed the interface dll from the plugin folder and after that everything worked as expected.

"Use of unassigned local variable" error with an Interface

I'm having trouble with some syntax. I'm not really familiar with interfaces so please excuse my ignorance.
VS2010 is giving me an error at... application.Name = System.AppDomain.CurrentDomain.FriendlyName;
public static void AddApplication(string applicationName = null, string processImageFileName = null)
{
INetFwAuthorizedApplications applications;
INetFwAuthorizedApplication application;
if(applicationName == null)
{
application.Name = System.AppDomain.CurrentDomain.FriendlyName;/*set the name of the application */
}
else
{
application.Name = applicationName;/*set the name of the application */
}
if (processImageFileName == null)
{
application.ProcessImageFileName = System.Reflection.Assembly.GetExecutingAssembly().Location; /* set this property to the location of the executable file of the application*/
}
else
{
application.ProcessImageFileName = processImageFileName; /* set this property to the location of the executable file of the application*/
}
application.Enabled = true; //enable it
/*now add this application to AuthorizedApplications collection */
Type NetFwMgrType = Type.GetTypeFromProgID("HNetCfg.FwMgr", false);
INetFwMgr mgr = (INetFwMgr)Activator.CreateInstance(NetFwMgrType);
applications = (INetFwAuthorizedApplications)mgr.LocalPolicy.CurrentProfile.AuthorizedApplications;
applications.Add(application);
}
I can make that error go away by setting application to null but that causes a run-time null reference error.
Edit:
Here's where I'm adapting the code from. I hope it gives more context
http://blogs.msdn.com/b/securitytools/archive/2009/08/21/automating-windows-firewall-settings-with-c.aspx
You never initialize
application
before using it here:
application.Name = System.AppDomain.CurrentDomain.FriendlyName;
The variable application is defined as:
INetFwAuthorizedApplication application
You need to assign an instance of a class that implements the interface INetFwAuthorizedApplication.
Somewhere there must be one (or probably more) classes in your project that look something like this:
public class SomeClass : INetFwAuthorizedApplication
{
// ...
}
public class AnotherClass : INetFwAuthorizedApplication
{
// ...
}
You need to determine what class you should use (SomeClass, AnotherClass) then assign an appropriate object, e.g. like this:
INetFwAuthorizedApplication application = new SomeClass();
Interfaces are used to describe what an object does, not what it is specifically. To put into "real world" terms, an interface might be like:
ISmallerThanABreadbox with a FitIntoBreadbox() method. I can't ask you to give me "the smaller than a breadbox" ... as that doesn't make any sense. I can only ask you to give me something that "IS smaller than a breadbox". You have to come up with your own object that makes sense to have the interface on it. An apple is smaller than a breadbox, so if you have a breadbox that only holds items smaller than it, an apple is a good candidate for the ISmallerThanABreadbox interface.
Another example is IGraspable with a Hold() method and FitsInPocket bool property. You can ask to be given something that IS graspable that may or may not fit in your pocket, but you can't ask for "the graspable".
Hope that helps...

Categories