
mooman_fl
Avatar/Signature-
Posts
194 -
Joined
-
Last visited
About mooman_fl
- Birthday 06/07/1970
Personal Information
-
Visual Studio .NET Version
Enterprise
-
.NET Preferred Language
VB.NET
mooman_fl's Achievements
Newbie (1/14)
0
Reputation
-
As with many code conversions, it can probably be done, but I wouldn't be pretty or practical. Conversion between such different languages is best done by hand. Think of Google Translate. You can translate a book from Chinese to English with it, but the results are going to be less than desirable. I will not really be recognizable as the original work, and most likely won't be useable as good reading material.
-
That makes sense. Guess I wasn't stuck on stupid, just on ignorant. :o EDIT: Ok, I got it worked out temporarily so I can continue to progress by just having everything compile to the same directory. You were right and that seemed to have solved the problem. Since I tend to do my unit testing as I go, the parts that deal with using a specific plugin directory were already tested and found to work. :cool: I am assuming that what was happening is that the plugins were copying the interface assemblies to the plugin directory because they are dependencies. Ideally I would like to stop this from happening so that I can continue to develop and test as the component would typically be used. So if you have any ideas, I am open to suggestion. :D EDIT (AGAIN): WOOOOOT!!!!! Got all the basic functionality of the control added. It will now load plugins successfully. You still have to do a DirectCast in your app's code at the point that you want it to load plugins, but that is unavoidable since the control operates with no knowledge of the plugin interfaces you might want to use. There are some bells and whistles still to add, and a few things that will make it even more flexible... but at least it is working. The code within an app for loading in which plugins are available, then loading a particular one and using it looks like this: 'this will be our usable plugin Dim plugTest As IStrings.IProcessString 'This does all the grunt work. 'It determines available plugin assemblies, and loads info on them. 'It does this without retaining a loaded assembly in memory. PowerPlug1.StartPluginEngine() 'This loads the first plugin assembly in the list. PowerPlug1.Plugins.Item(0).Load() 'This makes the plugin reference plugTest = DirectCast(PowerPlug1.Plugins.Item(0).PluginObjects.Item(0).Plugin, IStrings.IProcessString) 'This uses it. MessageBox.Show(plugTest.StringOperation("This is a test.")) 'This result in this instance reverses the string. I could still use an answer to the above question though, since I still have a bit of work to go. Again, thanks for all the help. Truely!
-
Thats odd. I made those same changes yesterday after your original explaination, and still got the error. So I thought I was just misunderstanding you. However after cutting and pasting your solution, it is still giving that error: Unable to cast object of type 'Plugin1.PluginInfo' to type 'IPlug.IPlugInfo'. Can you think of any reason why it might be giving an error on one computer, but not the other? My computer is an HP Pavilion Athlon 64 X2 running Vista 32bit Home with 2GB RAM. Here is the complete exception detail: System.InvalidCastException was unhandled Message="Unable to cast object of type 'Plugin1.PluginInfo' to type 'IPlug.IPlugInfo'." Source="PowerPlug" StackTrace: at PowerPlug.Gateway.GetPluginInfo(String FullPath) in C:\Users\Aarons\Documents\Visual Studio 2005\Projects\PowerPlug\PowerPlug\Shim\Gateway.vb:line 81 at PowerPlug.Gateway.GetPluginInfo(String FullPath) at PowerPlug.PowerPlug.StartPluginEngine() in C:\Users\Aarons\Documents\Visual Studio 2005\Projects\PowerPlug\PowerPlug\PowerPlug.vb:line 200 at TestApp.Form1.Form1_Load(Object sender, EventArgs e) in C:\Users\Aarons\Documents\Visual Studio 2005\Projects\PowerPlug\TestApp\Form1.vb:line 22 at System.EventHandler.Invoke(Object sender, EventArgs e) at System.Windows.Forms.Form.OnLoad(EventArgs e) at System.Windows.Forms.Form.OnCreateControl() at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible) at System.Windows.Forms.Control.CreateControl() at System.Windows.Forms.Control.WmShowWindow(Message& m) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ScrollableControl.WndProc(Message& m) at System.Windows.Forms.ContainerControl.WndProc(Message& m) at System.Windows.Forms.Form.WmShowWindow(Message& m) at System.Windows.Forms.Form.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) at System.Windows.Forms.SafeNativeMethods.ShowWindow(HandleRef hWnd, Int32 nCmdShow) at System.Windows.Forms.Control.SetVisibleCore(Boolean value) at System.Windows.Forms.Form.SetVisibleCore(Boolean value) at System.Windows.Forms.Control.set_Visible(Boolean value) at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.Run(ApplicationContext context) at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun() at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel() at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine) at TestApp.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81 at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart()
-
Ok, I am getting the feeling that I am just stuck on stupid because I am not getting what you are saying. What am I doing different than is done in previous plugin examples (the one done by Divil and the one by myself based on his)? In both examples you make an interface that both your app and the plugin implement. At runtime you find the class in the plugin that implements that interface, then load it and cast it to the common interface which then allows you access to the properties, methods, etc. As far as I can tell, I am doing pretty much the exact same thing as in the plugin examples I mentioned, yet I am getting this error on the casting. Here, I am just going to attach my project minus executables. The above code is in Gateway.vb in the Shim folder within the PowerPlug project. It is called near the end of the StartPluginEngine method in PowerPlug.vb. I normally don't ask others to fix something for me, so if you could just take a look and give me a better idea of how what I am doing is wrong. What the program currently does correctly until it hits this code is accept a directory where plugins can be found, and accept a list of assemblies that carry additional interfaces that constitute a valid plugin. IPlug.IPlugInfo is included in the control assembly and all plugins reference that assembly to the get the interface. At run time makes a collection listing all files in the plugin directory, and validates them against the needed plugin interfaces. For each valid plugin assembly it sets a property (IsPlugin) to "True". So far all of this works correctly. The next step I was working on was to pull the information from the valid plugins that reside in the plugin directory into the class implementing the IPlug.IPlugInfo and populate the Plugins.PluginInformation part of the collection with the data in it. This is where it is getting the error. As a side note, since this is all done before the user chooses to load a plugin, this is done inside another AppDomain so that after this initial information is gathered the references to the Assemblies, and their associated resources, are freed. It is a VS2005 project. PowerPlug.zip
-
I understand that. However, after making a new variable called tempInterface as IPlug.IPlugInfo I tried casting tempRef to that instead. I got the exact same error. The type I am trying to cast ONLY implements that interface with nothing added. This is the IPlug.IPlugInfo interface: Public Interface IPlugInfo ReadOnly Property Name() As String ReadOnly Property Version() As String ReadOnly Property Description() As String ReadOnly Property Company() As String ReadOnly Property Creator() As String ReadOnly Property Copyright() As String ReadOnly Property Email() As String ReadOnly Property Homepage() As String End Interface And this is the Plugin1.PluginInfo that I am trying to cast: Public Class PluginInfo Implements IPlug.IPlugInfo Public ReadOnly Property Company() As String Implements IPlug.IPlugInfo.Company Get Return "Madcow Inventions" End Get End Property Public ReadOnly Property Copyright() As String Implements IPlug.IPlugInfo.Copyright Get Return "©2007" End Get End Property Public ReadOnly Property Creator() As String Implements IPlug.IPlugInfo.Creator Get Return "Tim Browning" End Get End Property Public ReadOnly Property Description() As String Implements IPlug.IPlugInfo.Description Get Return "First dummy plugin for testing" End Get End Property Public ReadOnly Property Email() As String Implements IPlug.IPlugInfo.Email Get Return "mooman_fl@yahoo.com" End Get End Property Public ReadOnly Property Homepage() As String Implements IPlug.IPlugInfo.Homepage Get Return "http://www.madcowinventions.com/" End Get End Property Public ReadOnly Property Name() As String Implements IPlug.IPlugInfo.Name Get Return "Single Digit Plugin" End Get End Property Public ReadOnly Property Version() As String Implements IPlug.IPlugInfo.Version Get Return "1.0" End Get End Property End Class Maybe there is a reason why one can't cast to the other, but I am just not seeing it. As I mentioned, the main control calls this from within another AppDomain... could that cause the problem?
-
This is related to the plugin project I mentioned on the other thread. The app is set up as a User Control that find and loads plugins. The main interface it checks for to determine a valid plugin is within the control assembly. The plugin references this interface (IPlug.IPluginInformation) as does the class that I am trying to DirectCast to. I do one thing a little out of the ordinary however: I load a new AppDomain and this part of the code is within the second AppDoman. It iterates through the Types in the plugin assembly just fine, and correctly determins that it implements the desired interface. I can use Assembly.CreateInstance to get a reference to the Class Object, however when I try to DirectCast it to the PluginInformation class that also Implements the same interface, I get: Unable to cast object of type 'Plugin1.PluginInfo' to type 'IPlug.IPlugInfo'. Plugin1.PluginInfo is the name of the class in the plugin that implements the IPlug.IPlugInfo interface. I am a little stumped as to what is the problem. Is it because I am doing this in second AppDomain? If so, why is it even recognizing the interface to begin with? Here is the code for the method that does this: Friend Function GetPluginInfo(ByVal FullPath As String) As PluginInformation Dim tempAssembly As [Assembly] Dim IPlugName As String = GetType(IPlug.IPlugInfo).ToString Dim temp As Type Dim tempRef As Object Dim tempPlugInfo As PluginInformation tempAssembly = [Assembly].LoadFile(FullPath) For Each Exported As Type In tempAssembly.GetTypes 'cycle through the types that are in the assembly If Exported.IsPublic Then If Not ((Exported.Attributes And TypeAttributes.Abstract) = TypeAttributes.Abstract) Then temp = Exported.GetInterface(IPlugName, True) 'checks for a match against default interface If Not (temp Is Nothing) Then 'if it is there, set the flag tempRef = tempAssembly.CreateInstance(Exported.FullName) 'when it hits the following line it gives the error tempPlugInfo = DirectCast(tempRef, IPlug.IPlugInfo) End If End If End If Next Return tempPlugInfo End Function Any help would be appreciated.
-
MEF sounds like it is pretty powerful and would do the job. However it is also quite complex and not very intuitive. In addition, for most simple apps that just want to accept some plugins it is like using a sledgehammer to crack a nut. A person that has written a plugin based app before using the methods discussed above, would have to learn an entirely new way of doing things just to get off the ground. Sometimes a steep learning curve can actually hinder a project rather than pushing it forward, especially if the powerful advantages that create the learning curve aren't needed.
-
Wow, I didn't expect to pop in here for a look after so much time away and find a discussion so relevant to what I am currently working on underway. Any plugin that supplies GUI material should have it's GUI elements put on a control within the plugin. A method should be provided in the Interface that gets an instance of this control, which the main app can then add where it see's fit. An example of this that I wrote a while back is either in the Code Library, or Tutorials section. Can't remember which of the top of my head. EDIT: Here it is http://www.xtremedotnettalk.com/showthread.php?t=70920&highlight=plugin Also, when scanning the plugins directory for valid plugins, you should do that in a separate AppDomain. The problem is that if you do it in your main AppDomain it keeps a copy of ALL assemblies loaded even after you supposedly release them; whether they are a valid plugin or not. Using a separate AppDomain allows you to release these references and the memory associated with them once the secondary AppDomain is closed. You can verify that this is happening currently by adding the return string from the following function to a MessageBox after you scan for plugins in the plugin directory. You should throw a couple of assemblies that aren't valid plugins to test. If you see them in the list of loaded assemblies after the scan is completed, it is due to the problem I mention. [vbnet] Public Function ShowAssemblies() As String Dim sb As New System.Text.StringBuilder For Each LoadedAssembly As Assembly In AppDomain.CurrentDomain.GetAssemblies() sb.Append(LoadedAssembly.GetName().Name) sb.Append(vbCrLf) Next Return sb.ToString.TrimEnd(vbCrLf, " ", vbTab) End Function[/vbnet] Incidentally, I am currently working on (after quite a long sabatical from the project) a User Control that you can drop in any project that instantly makes it plugin enabled. In the design time interface you can add the plugin directory, and assembies that carry your plugin interfaces. At runtime it checks the directory for the appropriate interfaces in assemblies within the plugin directory and allows you to load them at will, and provides the access to their methods, properties, etc. It just seemed a lot easier to do this work once in a generic enough way that it could be used without modification from project to project.
-
Well I got part of the problem solved. My program no longer crashes when you shut it down if you bypass the Access Violation. I don't want to release it with the error bypassed though since that could introduce some nasty bugs later. Basically the crashing on exit problem was a String issue. Evidently C++ doesn't handle strings the same way and I was unable to get my code to accept or pass strings properly to the host application (not the DLL I was trying to reference). I just changed that parameter to a Long type and the crash-on-exit bug went away. Unfortunately the Access Violation is still there. I am hoping I can get this solved.
-
Ok, I changed it to a stdcall. Unfortunately that had no visible effect. I did get a reply from the author of the DLL, however he has almost no experience with .Net and his answer just didn't sound right to me. But then that could be just MY inexperience in some areas. Here is the reply that he gave: Almost none, and absolutely none with regard to calling external DLLs. I would guess that the low-level stack handling I do within CallFunctionPtr is causing the crash and that the problem is caused by the .NET environment is using it's own stack and that this stack is fairly small (less than 80 bytes). If this is the case then I don't have a solution for that without slowing the command down for everyone - it's not an issue that occurs with the DBPro stack. If you want to send me a small example DLL and the code to go with it, I can take a look and see if I get any ideas. Does this answer sound plausible to you (no pun intended, but certainly enjoyed)? Here is a post from another forum on the web that talks about a similar sounding problem, unfortunately I have just enough knowledge to see this as a possible cause, and not enough to solve it: http://www.thescripts.com/forum/thread672441.html
-
Unfortunately, I know for certain it is not a problem with the data types. Between knowing how DarkBasic Pro handles data types, the help file description for this command, and the string table entry (resource hacked to get a peek) for this command in the DLL I am pretty certain (99.9%) that it isn't a problem with mismatched data types. I become 100% certain when you add to that the fact that if I use Try/Catch with an empty Catch section to trap the Access Violation error, the command works as expected until you exit the application at which time it crashes. To give a little more insight, here is the Help File entry for the command as it is used in DarkBasic Pro: It is an overloaded function, but I am using the first one that takes a Long type with no other arguments. Here is the string table entry from within the DLL: CALL FUNCTION PTR%L%CallFunctionPtrAs you can see the section "%L%" means that it takes a data type of Long with no return value. You can see in my first post how I load the DLL function for use. Here is how I use it in my code: Try MatrixFunctionPointers.CallFunctionPtr(currentmessage.Handler) Catch ex As Exception MessageBox.Show(ex.ToString) End TryThe property "currentmessage.Handler" is of type Long and is poplated with a value from another command within the DLL that holds the "CallFunctionPtr" command. The command that gives the value is one that is intended to pass the correct value for that command. If I remove the MessageBox command from the Catch portion, it doesn't give an error and works as expected... then crashes when you try to exit the program. If it helps, here is a link to the author's page where you can get the DLLs, it is in a pack of 28 of them. EDIT: I am using the Matrix1Util_20.dll. The link to download them is the first of two links at the bottom of the first post on the page. http://forum.thegamecreators.com/?m=forum_view&t=85209&b=18 They are made as plugins for DarkBasic Pro, but plugins can be referenced by other DLLs. DarkBasic Pro and most of the plugins are written in unmanaged code, however the process for getting a .Net DLL to work as a plugin is well understood by the community. I hope this helps. I will be willing to zip up my code and attach it if need be. However, without DarkBasic Pro there would be little point. My code compiles just fine... the error is only revealed when you run it within the intended environment. I am as sure as I can be that it is a problem with my managed code calling an unmanaged code function that does something .Net doesn't like. I have a question up on the author of the DLL's forum entry to match this one... but since I don't believe the problem is with his DLL, I figured this forum might be able to help as well.
-
As usual I am having a bit of trouble and I am hoping one of the gurus out there can shed some light. I think I know what the problem is, I just don't know how to fix it even after searching myself half blind. I am working with a third-party DLL written in unmanaged code. I used DLL import to pull it into my project like so (yes it is a plugin for DarkBasic Pro if you recognized it): <DllImport("Matrix1Util_20.dll", EntryPoint:="CallFunctionPtr", CallingConvention:=CallingConvention.Cdecl)> _ Friend Shared Sub CallFunctionPtr(ByVal FunctionPointer As Long) End SubThe problem comes when I try to use the function. It works, then crashes immediately with an "System.AccessViolationException: Attempted to read or write protected memory." If I Try/Catch this and bypass the error, the thing functions as it should, but crashes upon closing with an empty error dialog (no text, just an "Ok" button). What that DLL does is call a function via a pointer in an unmanaged application. In this case, the application in question lables both Subs and Functions as a "Function" in my test code there was no return value. I have looked up information on things like this but all I could find were references to similar problems where the imported function had a callback and was solved by making a delegate with the "UnmanagedFunctionPointer" attribute, however this function doesn't have a visible callback. Any help or advice on how to solve this is appreciated. If you need more info or code just let me know.
-
Just off the top of my head, and maybe someone has a better idea, I would make a class with a method that holds the code you want in your KeyDown event. Just call that method from the KeyDown handler on each of the dialogs rather than repeating the whole code.
-
I decided to bypass this problem and go about it a whole different way.
-
I am needing to serialize a hashtable at designtime in a component and need some advice. Should I inherit from HashTable for from DictionaryBase, and what is the best method to carry this out? I need the key and value to be set at designtime in the properties window.