I'm developing an app in MapBasic that calls methods in a .NET assembly library
This is how I Declare the method in my MapBasice enviroment.
Declare Method showMainWindow Class "mynamespace.AldebaranInterface" Lib "Aldebaran.dll" ()
Sub ShowWindow
Call showMainWindow()
End Sub
Sub formEventHandler
'Reacting to some button click. I need to call this Sub from somewhere in mynamespace.AldebaranInterface
End Sub
What I need is to callback some Sub or Funcion in my MapBasic application from my .NET C# code. Let's say execute some portion of MapBasic code when the user clicks some button that is in my .NET form.
Is there a way to do that? If so. How can I achieve it?
Any Help would be highly appreciated.
I'm not sure what is your .dll is supposed to do, I guess it's a form, since you need your mapbasic code to react to button click.
In order to send command to mapbasic you need to create instance of Mapinfo’s COM object.
Here is the link on how to do it. I personally use second approach.
So after you create class:
public class Mapinfo
{
private object mapinfoinstance;
public Mapinfo(object mapinfo)
{
this. mapinfoinstance = mapinfo;
}
public static Mapinfo CreateInstance()
{
Type mapinfotype = Type.GetTypeFromProgID("Mapinfo.Application");
object instance = Activator.CreateInstance(mapinfotype);
return new Mapinfo(instance);
}
public void Do(string command)
{
parameter[0] = command;
mapinfoType.InvokeMember("Do",
BindingFlags.InvokeMethod,
null, instance, parameter);
}
public string Eval(string command)
{
parameter[0] = command;
return (string)mapinfoType.InvokeMember("Eval", BindingFlags.InvokeMethod,
null,instance,parameter);
}
}
, you need to add button clicked event:
appMapInfo = Mapinfo.CreateInstance();
//It's good idea to pass this path string from your MapBasic code
//as method parameter in your .dll
string appMapInfoFilePath = #"D:\YourMBXPath\YourMBX.MBX";
//argumet you want to pass to MapBasic code
string argForMapBasic = ...;
string runCommand;
string subCommand;
subCommand = "dim i_chan_num as integer i_chan_num = DDEInitiate(\"\"MapInfo\"\",\"\"" + appMapInfoFilePath + "\"\")";
subCommand = subCommand + " DDEExecute i_chan_num, \"\"" + argForMapBasic + "\"\" DDETerminate i_chan_num";
runCommand = String.Format("Run Command \"{0}\"", subCommand);
appMapInfo.Do(runCommand);
Now on MapBasic side, you should create Sub RemoteMsgHandler (MapBasic Reference: A reserved procedure name, called when a remote application sends an execute message.)
Sub RemoteMsgHandler
Dim command as String
'command - string passed from your C# code (string argForMapBasic)
command = CommandInfo(CMD_INFO_MSG)
'pass a command to your procedure
Call yourProcedure(command)
End Sub
Related
I have a piece of code that works well for me using an obsolete function. I'll strip down to minimal parts:
private dynamic pSentFolderItems; //will reference the Items of an Outlook Folder
public void WatchEmail2(object app, string emailID)
{
pApp = app; //this is actually an Outlook Application instance
//below reference to the Items object comes back as ComObject
pSentFolderItems = pApp.Session.GetDefaultFolder(5).Items;
//get the type through Reflection on the instance
Type olItemsType = pApp.GetType().Assembly.GetType("Microsoft.Office.Interop.Outlook.ItemsClass", false, true);
//pSentFolderItems = Marshal.CreateWrapperOfType(pSentFolderItems, olItemsType);
//above works every time but is marked Obsolete!!
//http://go.microsoft.com/fwlink/?LinkID=296519
//I'm struggling to implement the generic version of the CreateWrapperOfType method, as errors occur
//and I cannot input the type parameters without errors
pSentFolderItems = Marshal.CreateWrapperOfType<ShouldBeComObjectType, ShouldBeOlItemsType>(pSentFolderItems);
//.....rest of code........
}
Here is VB Code:
Public Class OVBO
Private pApp As Object
Public pMailId As String = ""
Public itemSent As Boolean = False 'change to a map?
Public itemWatching As Boolean = False
Public pSentFolderItems As Object
Public Sub WatchEmail2(app As Object, emailID As String)
pMailId = emailID
pApp = app
If Not itemWatching Then
pSentFolderItems = pApp.Session.GetDefaultFolder(5).Items
Dim olType As Type = pApp.GetType().Assembly.GetType("Microsoft.Office.Interop.Outlook.ItemsClass", False, True)
Dim myFlags As BindingFlags = BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.NonPublic
Dim evt As EventInfo = olType.GetEvent("ItemAdd", myFlags)
Dim evtHandlerType As Type = evt.EventHandlerType
Dim finalD As [Delegate] = [Delegate].CreateDelegate(evtHandlerType, Me, "MailSent2")
Dim addHandlerArgs() As Object = {finalD}
'The below works to return an Items Object(from a ComObject) that can be passed to the method handler invocation
pSentFolderItems = Marshal.CreateWrapperOfType(pSentFolderItems, olType)
'The above is obsolete, and am struggling to work with the non-obsolete method at [MSDN][1]
Dim miAddHandler As MethodInfo = evt.GetAddMethod()
miAddHandler.Invoke(pSentFolderItems, addHandlerArgs)
itemWatching = True
End If
Console.WriteLine("Watching {0}", emailID)
End Sub
'rest of class
End Class
Please note there are no references to the Outlook dll, and no Interop references.
So I am wondering if anyone can help translate the obsolete method call into the new way.
I am creating a windows desktop application using c# , my solution has 2 projects
the first one is a project that hold all the GUI and classes for a Login system (using SQL db) , after the a success login my function return the full data of the actual user :
private void Login(string User, string Pass)
{
DataTable Table = new DataTable();
Table = UserConnecction.Log_in(User, Pass);
int Count = Table.Rows.Count;
switch (Count)
{
case 1:
User_info.UserID = Convert.ToInt32(Table.Rows[0][0]);
User_info.UserName = Table.Rows[0][1].ToString();
User_info.Password = Table.Rows[0][2].ToString();
User_info.Email = Table.Rows[0][3].ToString();
User_info.Pack = Convert.ToInt32(Table.Rows[0][4]);
MessageBox.Show("" + User_info.UserID);
Main Main = new Main(User_info.UserName);
Main.ShowDialog();
this.Hide();
break;
case 0:
default:
MessageBox.Show("Incorrect Login ! ");
break;
}
}
And my second solution holds some functions that need the ID of the connected user , so I want basically to pass that parameter to the seonce project when the user login
I already tried to use the first project as a reference but it seems like you can only uses functions and classes and not passing a parameter cause it will always displays 0 !
Thank you !
Your 'main' project is the form-application. You need to reference the second project by Add reference (and click project-tab) and check the project you need.
Then in your first project, in a button_click handler or something you can use:
public void Button_loginHandler()
{
var x = new namespaceSecondProject.Class(constructor info);
}
So if I have one project (the second project in your class):
namespace TestProject
{
public class User
{
public string Username {get; set;}
public string Password {get; set;}
public datetime LastLoginDate {get;set;}
public void SetLastLogin()
{
LastLoginDate = datetime.now;
}
}
}
in your first project (your windows forms): you can use:
var newUser = new TestProject.User{ Username = "me", Password = "you"};
And if you want to use a function it is
newUser.SetLastLogin();
Pls note that this makes no sense, but hope to see that you can use classes and function like you want..
I have developed in the past in VB.net and I simply can't figure out how to properly call this function and how to get the response so I can display it on a web page response.
I translated the example c# code to VB. Here is my code behind for an aspx page that I wish to use to make the request and then display the response in my page:
Imports OffAmazonPaymentsService
Imports OffAmazonPaymentsService.Model
Public Class WebForm1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Response.Write(GetOrderReferenceDetails(???service???, "asdfsadf", "asdfsadf", "asdfasdf"))
End Sub
Private Shared Function GetOrderReferenceDetails(service As IOffAmazonPaymentsService, sellerId As String, amazonOrderReferenceId As String, addressConsentToken As String) As GetOrderReferenceDetailsResponse
' Required parameters
Dim request As New GetOrderReferenceDetailsRequest()
request.SellerId = sellerId
request.AmazonOrderReferenceId = amazonOrderReferenceId
' Optional parameters
request.AddressConsentToken = addressConsentToken
Return service.GetOrderReferenceDetails(request)
End Function
End Class
I don't know how to call that function's first (service) parameter and to then display the contents of the response.
Let me know if my question is not clear enough.
here is the example they gave in c sharp format....
using OffAmazonPaymentsService;
using OffAmazonPaymentsService.Model;
public class GetOrderReferenceDetailsSample
{
/**
* Sample GetOrderReferenceDetails method that takes generic inputs, constructs a request object,
* and make a call to the service.
*/
private static GetOrderReferenceDetailsResponse GetOrderReferenceDetails(
IOffAmazonPaymentsService service,
string sellerId,
string amazonOrderReferenceId,
string addressConsentToken)
{
// Required parameters
GetOrderReferenceDetailsRequest request = new GetOrderReferenceDetailsRequest();
request.SellerId = sellerId;
request.AmazonOrderReferenceId = amazonOrderReferenceId;
// Optional parameters
request.AddressConsentToken = addressConsentToken;
return service.GetOrderReferenceDetails(request);
}
}
Disclaimer: my VB is "rusty" so debug and improve as necessary
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
Dim props As OffAmazonPaymentsServicePropertyCollection = OffAmazonPaymentsServicePropertyCollection.getInstance()
Dim client As New OffAmazonPaymentsServiceClient(props)
Dim result as GetOrderReferenceDetailsResponse = GetAmzOrderRef(client, props, "oref", "token")
End Sub
Private Shared Function GetAmzOrderRef(service As IOffAmazonPaymentsService, props As OffAmazonPaymentsServicePropertyCollection, amazonOrderReferenceId As String, addressConsentToken As String) As GetOrderReferenceDetailsResponse
Dim request as New GetOrderReferenceDetailsRequest()
With request
.SellerId = props.MerchantID
.AmazonOrderReferenceId = amazonOrderReferenceId
.AddressConsentToken = addressConsentToken
End With
Return service.GetOrderReferenceDetails(request)
End Function
Notes:
you should have your config values set (web.config or app.config as necessary), that's where OffAmazonPaymentsServicePropertyCollection.getInstance() will obtain values
the above sample code will fail (as expected) because of dummy values for reference id and token, but that "error" is from the Amazon API (already) - e.g. response error "invalid reference id" or "invalid token" etc....
Hth....
I have WinForm called Form1 and there are Button1, MemoEdit1 and 2 TextBoxes named TextBox1 and TextBox2. At runtime user should be able write C# code in MemoEdit1 in order to manipulate the TextBox controls. F.e: at runtime user typed into MemoEdit1 simple code like: TextBox2.Text = "Hello" + TextBox1.Text;
So, when I click on Button1, I need to compile and execute the code.
Question may sound so simple as I am a newbie in compiling/executing code during runtime in C#.
Could you pls, help?
Thanks.
Take a look on this snippet
public class Evaluator
{
public void Eval(string Code)
{
Microsoft.CSharp.CSharpCodeProvider Provider = new Microsoft.CSharp.CSharpCodeProvider(); // Create an provider
System.CodeDom.Compiler.ICodeCompiler Compiler = Provider.CreateCompiler(); // Create An Compiler
System.CodeDom.Compiler.CompilerParameters Parameters = new System.CodeDom.Compiler.CompilerParameters(); // Create a parameters of the compiler
Parameters.GenerateInMemory = true; // It should generate the compiled assembly in the memory
System.CodeDom.Compiler.CompilerResults Results = Compiler.CompileAssemblyFromSource(Parameters, Code); //Compile it
///Now you just need to use reflection to call its methods
object SomeClass = Results.CompiledAssembly.CreateInstance("ClassName"); //Name of the class you want to create an instance
var Method = SomeClass.GetType().GetMethod("MethodName"); //Name of the Method you want to call
Method.Invoke(SomeClass, null); // change null for the argument it needs
}
}
if you want to just write code you will have to add the an class and a Method to wrap the user code and then you call it through the Invoke, you will probably have to reference your own assembly into this assembly
I have a main form that is launched and then it can go to any of the other forms I have created. But the kicker is that I have written a class that I call that returns a string with the name of the form to go to.
Currently I don't have this working so I am going from form to form like this (statically written linking code):
this.Hide();
CloudAccess nextForm1 = new CloudAccess();
//Where CloudAccess is the class of the next form.
nextForm1.ShowDialog();
What I want is something like this:
FormController pick = new FormController();
//Where FormController is the Class I create an object of and ask what's next
string next = pick.whereToGo(); //lets say it returns "CloudAccess"
this.Hide();
next nextForm1 = new next(); //next is desired to be the contents of the string
nextForm1.ShowDialog();
The problem is that I don't know how to use the returned string to make the new object and use it. I've been looking at Invoke and Reflection topics like this one: Use string value to create new instance
But I'm new to C# and I'm not sure how to apply that to this scenario.
Thoughts? Thanks!
Here's the working code from what fejejosco said:
string asdf = "CloudAccess";
Type CAType = Type.GetType("namespace." + asdf);
Form nextForm2 = (Form)Activator.CreateInstance(CAType);
nextForm2.ShowDialog();
Thanks!
Get the type of the form: Type.GetType("name.space." + formname), so if your class is name.space.CloudAccessForm, then pass in CloudAccessForm as formname, and it will give you the type. Then you can instantiate it with Activator.CreateInstance(type). Then cast it to a Form, and show it.