Custom Tabs in MonoMac project - c#

I am using MonoMac to develop an application and so far have been delighted at how easy it is to use coming from the Windows world. However I am stumped on what should be an easy feature to implement: putting a close button in a tab header.
This was already asked here:
Add a close button to NSTabviewitem
And one of the solutions was to use chromium tabs here:
https://github.com/rsms/chromium-tabs
Is it possible to use something like that in a MonoMac project with MonoDevelop? I can add the library in xcode as a linked library but MonoDevelop doesn't seem to hold onto those changes.
Since (from my understanding) MonoDevelop basically generates a dynamic xCode project and discards it after editing I am not sure if it is possible and am hoping someone can shed some light on it for me.
I am not married to the idea of chromium tabs - open to any suggestions.

You are correct that you can't simply add the framework to the XCode project, because it's generated by MonoDevelop - it's not a 'real' project in that sense.
You have a couple of options:
1 - Write your own implementation in C#
2 - Choose an open source implementation (e.g. Chromium Tabs) and port it to C#. This should work but will obviously be time consuming. Also you may find that you need access to some Cocoa APIs that are not present in MonoMac yet - you would need to figure out a workaround or implement them.
3 - It's possible to bind a native framework into your app. Perhaps you can find someone that has already done this for the framework you're interested in; or you can do it yourself.
I've been struggling with #3 myself for a day or two now, but finally got it all figured out so I'll share the process with you and maybe this will be helpful.
I downloaded the chromium tabs source and compiled the framework. You will need to compile it as i386 only; since MonoMac currently only ships a 32 bit runtime
I added the ChromiumTabs.framework to my project, and set up a pre-build script to copy it to ${TargetDir}/${ProjectName}.app/Contents/Frameworks/
I load the framework manually inside Main, before the call to NSApplication.Init():
var baseAppPath = Directory.GetParent(Directory.GetParent(System.AppDomain.CurrentDomain.BaseDirectory).ToString());
var chromiumPath = baseAppPath + "/Frameworks/ChromiumTabs.framework/ChromiumTabs";
var hresult = Dlfcn.dlopen(chromiumPath, 0); // Non-zero result indicates success
Next, use parse.exe (available in MonoMac when you compile from source) and feed it the .h files from the framework. Use the generated output to create the interfaces that will define your binding (there is good documentation on binding types here). For example:
using System;
using System.Drawing;
using MonoMac.Foundation;
using MonoMac.AppKit;
namespace ChromiumTabs
{
[BaseType (typeof (NSWindowController))]
interface CTTabWindowController {
}
[BaseType (typeof (CTTabWindowController))]
interface CTBrowserWindowController {
[Export ("browser")]
CTBrowser Browser { get; }
[Export ("initWithBrowser:")]
IntPtr Constructor (CTBrowser browser);
}
[BaseType (typeof (NSObject))]
interface CTBrowser {
[Export ("addBlankTabInForeground:")]
CTTabContents AddBlankTabInForeground (bool foreground);
[Export ("createBlankTabBasedOn:")]
CTTabContents CreateBlankTabBasedOn (CTTabContents baseContents);
}
[BaseType (typeof (NSDocument))]
interface CTTabContents {
[Export ("initWithBaseTabContents:")]
IntPtr Constructor ([NullAllowed]CTTabContents baseContents);
[Export ("viewFrameDidChange:")]
void ViewFrameDidChange (RectangleF newFrame);
}
}
Now, feed that .cs file into bmac.exe (check the help for the arguments you need to supply). This will output a managed DLL which you can reference in your project.
You should now be able to use your new binding!
I did a very minimal binding on the library, just enough to get it up and running. You can download that here.

Related

Trouble calling C# 32 bit Com from 64 bit C# application

First thing, I know there are several articles about doing what I want to do. It is nothing special. But I have read numerous articles here and elsewhere and read multiple examples and I seem to get conflicting information as well as very mediocre success. I am asking people familiar with COM to be patient and help somebody who is just getting into COM for the first time.
I will explain what I believe to be what needs done based on my research and ask knowledgeable people to point out what I am doing wrong and help me fill in the knowledge gaps. My application uses third party 32-bit DLLs and 64-bit DLLs. There are a bunch of the 64-bit and only one 32-bit. This is why I am using a 64-bit application. If anyone cares, it is the Minolta kmsecs200.dll. The web site is clear that they do not have a 64 bit version.
The first step is to create the 32 bit COM wrapper. At this point, my sample code does not wrap anything. It just has one simple function. Here are the steps I took to create the DLL:
Create a new C#, windows, class Library (.Net Framework), .NET Framework 4
Name the project “SimpleCom”, rename the class and CS file to “JustOne”
In the project properties:
On Application Tab: Click "Assembly Information" and set “Make assembly COM-Visible”
On Build tab: Set Platform target to x86
On Signing tab: Select "Sign the assembly" and create a new Strong Name Key file named "StrongSimpleCom", no password protection
This is the JustOne.cs code:
using System.Runtime.InteropServices;
namespace SimpleCom
{
[Guid("EAA4976A-45C3-4BC5-BC0B-E47474C3C83F")]
public interface IJustOne
{
[DispId(1)]
string AddName(string name);
}
[Guid("0D53A3E8-E51A-49C7-BC0B-E47474C3C83F"),
ClassInterface(ClassInterfaceType.None)]
public class JustOne : IJustOne
{
public JustOne() { }
public string AddName(string name)
{ return "My name is: " + name; }
}
}
Register the 32-bit Assembly on the target machine:
From an administrative command prompt, navigate to the DLL folder
C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe SimpleCom.dll /codebase /tlb:myTlb.tlb
I used /codebase because I do not yet know how to call the third party DLL if I put my DLL in GAC. I do not really understand what the tlb file is for once registered. I would like to know if someone can tell me.
At this point, the COM object shows up in Visual Studio but I can not call it that way and I understand that. It just tells me it is registered at least in some sense of the word.
So I think I should be able to Invoke the 32 bit C# DLL that I wrote from a 32 bit C# application. But I just can not figure out how to do it. I can't seem to even find a good example of using invoke. I would really appreciate help on how to invoke "IJustOne" in a simple application.
Once that works, I can add some registry entries to make it out of process and make the 32 bit application into a 64 bit application. Here is one of the ways I have heard to modify the registry to make the 32 bit COM oup of process and use the DLLhost as the surrogate.
Techtalk.gfi.com method from 2009*
Navigate to: HKEY_CLASSES_ROOT\WOW6432Node\CLSID{EAA4976A….}
• Add “AppID” with value set to Guid
Navigate to: HKEY_CLASSES_ROOT\WOW6432Node\AppID
• Create a new key using the Guid as the name
• In the key, Add “DllSurrogate” with no value
Navigate to: HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID
• Create a new key using the Guid as the name
Again I am having trouble finding good straight forward examples of how to invoke the COM object. I have created a C# DLL wrapper that I can directly include in a simple C# 32 bit application so I am comfortable with wrapping the unmanaged 3rd party DLL. I would like to know how to ensure my wrapper DLL can find their DLL.
I do not know what I am doing wrong with registering the DLL and I do not know how to invoke it in a 64 bit application, or a 32 bit for that matter. I appreciate any assistance. I have spent several days trying to chase this down but in the end, my knowledge base is just not strong enough. But a recap of the big picture:
I am using 3rd part 32 bit unmanaged DLL. I need to call it from my 64 bit C# application. I believe the way to do it is wrap it in a managed C# 32 bit DLL wrapper and make it an out of process COM object the uses DLLhost as the surrogate.
Thanks again,
Dave
Simon pointed me in the right direction above. My DLL was registered just fine. I added it as a component through component services and everything worked after that. Thank You Simon.

Cannot resolve symbol 'Void'

At the head of my class (I am taking over a project from someone else), I have the following:
using Java.Util;
using Object = Java.Lang.Object;
using Void = Java.Lang.Void;
Void, is showing in red, with a "Cannot resolve symbol 'Void'" and cannot see what I may be missing.
I have checked the PC where this came from (and the application does build on that one) and have installed the same (yes, I saw, newer, but specifically installed the "same" items) Java items:
Java 7 Update 45
Java 6 Update 31
Java SE Development Kit 6 Update 31
This hasn't made any change.
I have checked the 'References' branch of the project and everything is showing the same (in fact, I cannot see a specific reference to Java anywhere)
Any help would be appreciated to sort this.
Please understand that I am not looking to change the code; just to get the code (as is) to compile without error.
[Update]
When I type out Java.Lang. the intellisense does not show Void in the dropdown list
[Further Update]
This project is tied to the development for a tablet; for which I hadn't installed some of the development software - installing these has resolved the issue and I can only assume that the Java namespace is buried within the software. Whilst there's no specific answer in the responses, most of the comments have certainly helped to steer me in the right direction.
There are several possible ways a C# project consuming Java bits,
Microsoft J#, which has been dead for a long time.
IKVM.NET, which originates from Mono.
dot42, a C# to Android compiler, which compiles C# to Android.
Xamarin.Android (aka Mono.Android).
Based on the fragment you pasted I think you might be opening a Xamarin.Android project in Visual Studio, as the using clauses match,
http://androidapi.xamarin.com/?link=N%3aJava.Util
http://androidapi.xamarin.com/?link=T%3aJava.Lang.Void
http://androidapi.xamarin.com/?link=T%3aJava.Lang.Object
Thus, you need to have Xamarin.Android completely installed on this machine. What you have (JRE and JDK) is obviously not enough.
dot42 does not have Java.Lang.Void and Java.Lang.Object, http://docs.dot42.com/Reference/NS.Java.Lang
I think these links would be helpful for you.
What is the difference between java.lang.Void and void?
http://docs.oracle.com/javase/7/docs/api/java/lang/class-use/Void.html
FAIL:
using Java.Lang.Void;
import Java.Lang.Void;
SUCCESS:
import java.lang.Void;
You have to use import instead of using.
import Java.Util.*;
Object blah = new Java.Lang.Object;
If you want to create an object that is null, do this:
Object obj = new Object();
If you want to add data set it equal to data such as a number.
obj = 7;

Communicating between C# and VBA

At the request of my boss I created a small set of scripts that are used to periodically monitor the status of certain devices and processes. This info is subsequently processed using a relatively elaborate VBA module that gathers all info, applies formulas, sets up ranges and generates graphs, etc.
There are two problems however:
I'm an amateur programmer, so my VBA routine is quite inefficient. That's not a huge problem for me (I just get up and get a coffee while it's running), but for other users this can be a hassle, as then don't know why it's taking so long. I want a graphical representation of progress.
The configuration of the application is done through a text file. I want to provide a decent GUI for setting up the configuration.
In order to achieve this, I'm looking for a way to let my C# WinForms application communicate with my VBA application. I know how to run a VBA routine from my C# app, but I don't know how I can let them comminicate in real-time.
Here are the two things I specifically want to achieve:
I already have a log file that's saved at the end of the VBA routine.
Instead of that however I want to send the log/debugging-messages to
my C# application in real-time (not just at the end of the
application) so the messages can be displayed in my GUI app as they
are generated by the VBA app.
I also want the VBA app to send info
about real-time progress to my GUI app so I can create a graphical
progress-bar in my GUI app.
I've already thought about communicating through the Standard Output. I know how to read from the Standard Output using C#/.Net, but I'm not sure how I would write to the StdOut stream using VBA.
I'm sure many would point out that what I'm trying to achieve is stupid and old-fashioned (or totally unnecessary), but as an amateur programmer it seemed like a really challenging and fun project for me that could teach me a thing or two.
Creating a C# COM-visible class is pretty easy, and (as you said in your comments) it is fun. Here's a small sample.
In a new C# Library project, add:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace CSharpCom
{
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
//The 3 GUIDs in this file need to be unique for your COM object.
//Generate new ones using Tools->Create GUID in VS2010
[Guid("18C66A75-5CA4-4555-991D-7115DB857F7A")]
public interface ICSharpCom
{
string Format(string FormatString, [Optional]object arg0, [Optional]object arg1, [Optional]object arg2, [Optional]object arg3);
void ShowMessageBox(string SomeText);
}
//TODO: Change me!
[Guid("5D338F6F-A028-41CA-9054-18752D14B1BB")] //Change this
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
interface ICSharpComEvents
{
//Add event definitions here. Add [DispId(1..n)] attributes
//before each event declaration.
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(ICSharpComEvents))]
//TODO: Change me!
[Guid("C17C5EAD-AA14-464E-AD32-E9521AC17134")]
public sealed class CSharpCom : ICSharpCom
{
public string Format(string FormatString, [Optional]object arg0, [Optional]object arg1, [Optional]object arg2, [Optional]object arg3)
{
return string.Format(FormatString, arg0, arg1, arg2, arg3);
}
public void ShowMessageBox(string SomeText)
{
MessageBox.Show(SomeText);
}
}
}
You will want to go into your project properties, to the "Signing" tab, check the box to sign your assembly, and create a new "strong name key file". This will help to prevent versioning issues with your registered DLL.
Compile it, and register the DLL using regasm in a Visual Studio command prompt. You will use either 32 or 64-bit regasm depending on what version of Office you are using... you will find RegAsm in C:\windows\Microsoft.NET\Framework or C:\windows\Microsoft.NET\Framework64 (32 and 64-bit, respectively):
C:\windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe /codebase /tlb CSharpCom.dll
This will register your DLL with Windows, so now in the VBA editor, you should be able to go to Tools->References and find your COM's namespace "CSharpCom". Check that box, and now you should be able to create your COM objects in VBA:
Sub TestCom()
Dim c As CSharpCom.CSharpCom
Set c = New CSharpCom.CSharpCom
c.ShowMessageBox c.Format("{0} {1}!", "Hello", "World")
End Sub
You can add forms to your COM object, and open them when the VBA calls a particular method; you should be able to use this to create a form with a progress bar. One thing to consider, though, is that VBA is single-threaded. This means that everything else gets frozen while your code is running, so things might get a little tricky.
Off the top of my head, you could create 3 methods in your COM-visible class: one to open the form, one to update progress (call VBA's DoEvents() method right after your VBA calls the update() method on your COM object, to allow Office to process screen updates), and one to close it. You should call Dispose() on the form; which could be done in the "close" method, but I think it could potentially cause memory leaks/problems if your VBA crashes, and your close method is never called -- just something else to consider.
You can use a .NET DLL with your VB6 project and create an instance of any object you have defined in your assembly. This is done by registering the .NET assembly (.dll) for COM interop (use in VB6) by creating a type library file (.tlb). The .tlb file contain extra information so that your VB6 project can use your .dll. Note, your VB6 project will not reference the .dll but the corresponding .tlb file. You can use the Regasm.exe utility to generate and register a type library and register the location of the managed assembly. Then its just a matter of creating an instance of your .NET object, whether it be a WinForm or some other cool class. =).
Dim MyDotNetObject As MyDotNetClass
Set MyDotNetObject = New MyDotNetClass
MyDotNetObject.SomeMethod(value1, value2)
''end of execution
Set MyDotNetObject = Nothing
See: http://support.microsoft.com/default.aspx?scid=kb;en-us;817248
I believe the code in this link does roughly what you want:
C# code creates a COM object (in the example it is IE, but from your description, you have already managed to create an instance of your VBA routine)
It attaches a .Net event handler (using +=) to an event raised by the COM object (when the title changes)
It defines sample event handling code
http://msdn.microsoft.com/en-us/library/66ahbe6y.aspx
I don't profess to understand this code, my objective is to show convoluted this solution would be! You should really build this in just one solution. A total VBA will solution will be quicker to develop (you only need to learn VBA forms which is easy), but old technology. A total C# solution will be slower to develop but then you will get to learn C#.
Performance actually is an issue. If it performs inefficiently now, what happens when you have 5x as many records to process? You should solve the performance issue before you get that many records.
The other answers to this question involve the VBA macro calling an external method. But there is an easier way. Your GUI app can attach to the workbook SheetSelectionChange event or sheet Change event, which will be triggered when any value changes.
Because you probably don't want to slow down everything, I would recommend adding an additional sheet, add named ranges to describe what each value means, then hook the sheet change event to intercept when these values are changed and update your GUI.

C# Vlc.DotNet Libraries - Null reference exception

Recently stumbled upon this post whilst trying to decide on the best way of getting a VLC player into C#.
Does VLC media player have a C# interface?
I downloaded the dll files and imported them into my project, but then realised I had no real idea of how to use them. Has anyone got a Windows Forms example of this code that works? The code have tried is shown below -
Vlc.DotNet.Core.Medias.MediaBase media = new
Vlc.DotNet.Core.Medias.PathMedia(#"C:\Users\...\SampleVideos\Wildlife.wmv");
Vlc.DotNet.Forms.VlcControl vlcControl1 = new Vlc.DotNet.Forms.VlcControl();
vlcControl1.Play(media);
I am also using the code in this link in the main program.cs of my project.
http://vlcdotnet.codeplex.com/wikipage?title=Forms
The current problem I experience is that upon starting the project it throws a NullReferenceException when it gets to ->
vlcControl1.Play(media)
The problem seems to be with the vlcControl but I am unsure why. The documentation seems to rather thin and I couldn't find any working examples on the codeplex site. If anyone has a working forms example or knows what I might have missed please let me know!
Here is the call stack present when the error occurs ->
RTSPViewer_Test.exe!RTSPViewer_Test.Form1.Form1_Load(object sender,
System.EventArgs e) Line 31 + 0xd bytes C#
RTSPViewer_Test.exe!RTSPViewer_Test.Program.Main() Line 30 + 0x1d bytes C#
When debugging it appears that the Media and Medias attribute of the VLC control are both null. When trying to set the Media of the control to the media object created above a
NullReferenceException
Checking the VLC control object Media does indeed equal null, but I am not sure why it hasn't been initialised properly.
I was unable to get the program to work using the latest version of the Vlc.dotnet libraries but instead used the alpha 2 version which was posted by Raj. I used VLC version 1.1.5 with this library to get the basic example to function properly. My end objective was to stream from an rtsp device, however this library does not appear to support this functionality yet.
For anyone looking to use a good C# wrapper for using VLC then this is a great example -
http://www.codeproject.com/Articles/109639/nVLC
Used the library files from VLC 1.1.1 with this project and works fine. Supports pretty much all the features that you would usually use in VLC but gives you much more control over what you use them for.
Many of the issues that arise when using these DLL wrappers arose from incorrect versions of the source DLL files. The VLC libraries are only 32 bit at this time, so you need to make sure to compile using x86 mode otherwise the libvlc.dll will not load properly and the application will crash. Using the above example you must also make sure that the libvlc.dll, libvlccore.dll and the plugins folder are included in the build folder.

Monodevelop warning "Could not generate code for widgets of type: xxxx"

About 2 years ago I worked on a C# project, using MonoDevelop V1 and later V2 (beta release, compiled from source, what a mission) under Fedora. The project went dead. Now I am bringing it back to life, but I have changed my development platform to Debian (testing, i.e. squeeze), which has MonoDevelop V2.2.
I am mostly very pleased with the features of V2.2, but I have a nasty little problem. All the code compiles OK, but at the end of the compilation run I am left with lots of warnings as in the subject line. Obviously, as soon as I try and run the application, I get exceptions left, right and center when I open anything that uses these widgets.
The funny thing is that the library containing the widgets compiles just fine. But somehow these widgets (it's not all of them, only one or two) don't get exposed on the interface, and then subsequent dialogs or windows using them throw the above warning.
Has anybody had this problem? I have googled this and all that comes up is Michael Hutchinson throwing his hands in the air and saying "sorry, can't help here". I really need a fix for this, otherwise I will have to rewrite substantial chunks of code from scratch.
I would recommend trying MonoDevelop 2.4, but in any case here are some hints.
If you have an assembly which uses custom widgets implemented in the same assembly, you may be having a chicken-egg problem, since MonoDevelop needs the built assembly in order to find the custom widgets, but that's the assembly you are trying to build. This problem can be easily solved by building again the project after you get the warnings you reported. Beware, you have to build, not rebuild, since rebuild will delete the assembly and you'll hit the same problem again.
If you are not having the above problem, or if the solution doesn't work, the problem may be that the objects.xml file that contains the information about the exported widgets is not properly updated. You'll find that file in the project that implements the custom widgets, in a hidden gtk-gui folder. Open the file and check if the all the custom widgets are declared there. If a widget is missing, try opening the source code file of the widget and do a small change (e.g. a whitespace change) and then build the project again. MonoDevelop should be properly updating the file.
If you are still having trouble, please file a bug report.
I think I found a way out. Not sure whether this is the "official" method, but it seems to work.
In this library a normal widget's class definition starts like this:
namespace Amino.Common
{
//! A text entry combined with a pop-up date selector, very useful for otherwise busy dialogs
public class DatePicker : Gtk.Bin
{
If I now add two additional declarations right in front of the class statement, like this:
namespace Amino.Common
{
//! A text entry combined with a pop-up date selector, very useful for otherwise busy dialogs
[System.ComponentModel.Category("Common")]
[System.ComponentModel.ToolboxItem(true)]
public class DatePicker : Gtk.Bin
{
then
That widget gets included in the objects.xml file and
The entire solution compiles as expected (and runs as expected).
Maybe somebody could shed some additional light on this, I would love to understand this better.

Categories

Resources