I'm trying to build an out-of-process COM server in C#. I've found this example from Microsoft: http://support.microsoft.com/kb/977996
I've build it and tested with a little VBScript:
Set app = GetObject("", "CSExeCOMServer.CSSimpleObject")
WScript.Echo(app.HelloWorld())
It works, but not when I do like this (skip the first argument of GetObject):
Set app = GetObject(, "CSExeCOMServer.CSSimpleObject")
WScript.Echo(app.HelloWorld())
I don't understand the difference between this two calls. I need the second form, because I want to make my calls from an environnement where only the second way is available.
What can I change to the server in order to make this works?
Ok, as often, I've found the solution by myself. In fact:
GetObject("", "CSExeCOMServer.CSSimpleObject")
is the same thing as:
CreateObject("CSExeCOMServer.CSSimpleObject")
If you were looking for a bad designed API, I've found one (but I don't know the whole story, may be someone here can explain me why it is like this).
The problem in my case is that the Microsoft sample doesn't register an object in the ROT (Running Object Table). So the GetObject call can not find an active object. I've resolved this by creating an instance of my class after adding this method to the constructor:
public void AddToROT()
{
IRunningObjectTable rot = null;
IMoniker moniker = null;
try
{
// Get the ROT
rot = GetRunningObjectTable(0);
// Create a moniker for the graph
moniker = CreateItemMoniker("!", "{" + CLASS_ID + "}");
// Registers the graph in the running object table
cookie = rot.Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, this, moniker);
}
finally
{
if (null != moniker) Marshal.FinalReleaseComObject(moniker);
if (null != rot) Marshal.FinalReleaseComObject(rot);
}
}
Related
I am having trouble with getting access to the default C#-LanguageService in IVsExpansionClient.FormatSpan(IVsTextLines pBuffer, TextSpan[] ts). I need a Source-Instance of the current LanguageService to be able to create an EditArray for the incoming Span.
I was able to receive a COM-Object with the following code:
pBuffer.GetLanguageServiceID(out var languageServiceId);
var provider = Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider;
var vssp = provider.GetService(typeof(IOleServiceProvider)) as IOleServiceProvider;
var iunknown = new Guid(VSConstants.IID_IUnknown.ToString());
IntPtr ptr;
if (ErrorHandler.Succeeded(vssp.QueryService(ref languageServiceId, ref iunknown, out ptr)))
{
try
{
service = Marshal.GetObjectForIUnknown(ptr);
lang = (LanguageService)service;
}
finally
{
Marshal.Release(ptr);
}
}
But the cast lang = (LanguageService)service; fails. I have no idea what type that COM-Object behind service is. So my question is, how do I get the current LanguageService of an open editor?
I have taken parts of the code from here:
https://github.com/microsoft/VSSDK-Extensibility-Samples/blob/346f5b0289e5fb8de639ba96fb10703df06cd22d/WPFDesigner_XML/WPFDesigner_XML/ViewModel.cs#L275
Thank you!
The language services implement a number of different interfaces, you'd be then trying to query it for whatever interface you want. You mentioned C#, and in our case we don't actually derive from the package framework LanguageService at all, so that cast would fail.
You may want to clarify in your question what you're trying to achieve, since that's not exactly clear to me.
I am writing a Rider/ReSharper nav-from-here plugin which is supposed to determine a target type based on a symbol I am standing on using some simple rules, and finally, navigate to it.
The first part is okay, I have managed to form the FQN needed, but I am struggling with the navigation. I found this StackOverflow post, and thought I might try this approach. So I have been trying to use TypeFactory.CreateTypeByCLRName for like two hours to create an IDeclaredType instance to be able to get the IDeclaredElement using GetTypeElement() and eventually get its declarations. But the API seems to have changed and no matter what I do I cannot get my code to work.
Here is what I've got so far:
// does not work with Modules.GetModules(), either
foreach (var psiModule in solution.GetPsiServices().Modules.GetSourceModules())
{
var type = TypeFactory.CreateTypeByCLRName("MyNamespace.MyClassName", psiModule);
var typeElement = type.GetTypeElement();
if (typeElement != null)
{
MessageBox.ShowInfo(psiModule.Name); // to make sure sth is happening
break;
}
}
The weird part is, I actually see a message box - but only when the tab with MyClassName.cs is active. When it is in focus, everything is fine. When it's not or the file is closed, the class does not get resolved, type.IsResolved is false.
What am I doing wrong?
To do this, you should have a IPsiModule instance from the context where you plan to use the type you're looking for. You can get it from some syntax node you're working with via .GetPsiModule() method or via many other ways (like dataContext.GetData(PsiDataConstants.SOURCE_FILE)?.GetPsiModule().
void FindTypes(string fullTypeName, IPsiModule psiModule)
{
// access the symbol cache where all the solution types are stored
var symbolCache = psiModule.GetPsiServices().Symbols;
// get a view on that cache from specific IPsiModule, include all referenced assemblies
var symbolScope = symbolCache.GetSymbolScope(psiModule, withReferences: true, caseSensitive: true);
// or use this to search through all of the solution types
// var symbolScope = symbolCache.GetSymbolScope(LibrarySymbolScope.FULL, caseSensitive: true);
// request all the type symbols with the specified full type name
foreach (var typeElement in symbolScope.GetTypeElementsByCLRName(fullTypeName))
{
// ...
}
}
For our current project we are using DBus (1.6.n).
It is largely accessed from C++ in shared memory mode, and this works really well.
I am now trying to access the same DBus from a C# program.
In order to try things out first, I downloaded the latest version of dbus-sharp I could find, and started the daemon included in the download to see if I could connect to it from my test C# app.
Whenever I make a connection, the daemon console shows that I am communicating with it, but as soon as I try to access any methods on the connection I get the error;
'Access is denied: DBus.BusObject'
Here is the code I have tried;
DBus.Bus dBus = null;
try
{
//input address comes from the UI and ends up as "tcp:host=localhost,port=12345";
//dBus = new Bus(InputAddress.Text + inputAddressExtension.Text);
//string s = dBus.GetId();
//dBus.Close();
//DBus.Bus bus = DBus.Bus.System;
//DBus.Bus bus = Bus.Open(InputAddress.Text + inputAddressExtension.Text);
//DBus.Bus bus = DBus.Bus.Session;
//DBus.Bus bus = DBus.Bus.Starter;
var conn = Connection.Open(InputAddress.Text + inputAddressExtension.Text);
var bus = conn.GetObject<Introspectable>(#"org.freedesktop.DBus.Introspectable", new ObjectPath("/org/freedesktop/DBus/Introspectable"));
bus.Introspect();
}
finally
{
if(dBus != null)
dBus.Close();
}
The commented code produces the same error eventually too.
I have stepped through with the debugger and it always gets to the following code in the TypeImplementer.cs;
public Type GetImplementation (Type declType)
{
Type retT;
lock (getImplLock)
if (map.TryGetValue (declType, out retT))
return retT;
string proxyName = declType.FullName + "Proxy";
Type parentType;
if (declType.IsInterface)
parentType = typeof (BusObject);
else
parentType = declType;
TypeBuilder typeB = modB.DefineType (proxyName, TypeAttributes.Class | TypeAttributes.Public, parentType);
if (declType.IsInterface)
Implement (typeB, declType);
foreach (Type iface in declType.GetInterfaces ())
Implement (typeB, iface);
retT = typeB.CreateType (); <======== Fails here ==========
lock (getImplLock)
map[declType] = retT;
return retT;
}
I have not found any useful examples or documentation about accessing DBus from C#, and there seem to be few recent entries about this anywhere, so maybe no-one else is trying this.
I am running the daemon in the same folder as the test program.
As I am running on windows, the daemon is listening on the tcp setting;
string addr = "tcp:host=localhost,port=12345";
Since this is the example included with the download, I thought it would be really simple to get it going, but alas no luck yet.
Has anyone else been here and know the next piece of the puzzle?
Any ideas would be appreciated.
Having received no comment or response, I will answer the question with the information I have found since asking it.
There appears to be no useful C# interface to DBus. (By useful, I mean one that works!)
The only information or examples I could find are not up to date and no effort appears to be being expended on providing a working interface.
I have decided to interface with DBus by using a C++ implementation written as a Windows service, and my C# program will send messages to DBus via the service. This seems to work ok, so satisfies the business need.
I am disappointed not to be able to get the C# to DBus working, but there are lots of service bus implementations that work on Windows, so in future I will look at implementing those instead of DBus.
If anyone does come up with a workable, documented solution to accessing DBus from C# on Windows, I would still be interested to see it.
I had the same error when I created new test project and add dbus cs source files to it main project assembly. It was when IBusProxy type dynamically created in dynamically created assembly.
asmB = AppDomain.CurrentDomain.DefineDynamicAssembly (new AssemblyName ("NDesk.DBus.Proxies"), canSave ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run);
modB = asmB.DefineDynamicModule ("NDesk.DBus.Proxies");
......
retT = typeB.CreateType ();
I think it was cause current running assembly isnt friendly for created assembly. And just when I add to project compiled NDesk.DBus.dll this error disappeared.
I have ventured into the world of MEF for the first time and I am trying to figure out if it'll do what I am trying to accomplish. I am writing a windows service that is needed to call a few DLLs that are going to contain some business logic and then work with the datalayer. It was requested that these DLLs be "hotswappable" when the the windows service is running. I was hoping MEF can help me with this. I am attempting to test this out with a console application:
bool bFlag = true;
while(bFlag) {
DirectoryCatalog catalog;
CompositionContainer container;
catalog = new DirectoryCatalog(#"C:\serviceTest");
container = new CompositionContainer(catalog);
try {
var x = container.GetExport<IAlgorithm>();
var y = x.Value.Process("");
foreach(var z in y.Messages) {
Console.WriteLine(z.Message);
}
} catch(Exception ex) { Console.WriteLine("error"); }
container.ReleaseExports(container.GetExports<IAlgorithm>());
var o = Console.ReadLine();
if(o.Trim() != string.Empty) {
bFlag = false;
}
}
So now with that application running I drop the DLL that implements IAlgorithm into the folder and Process returns the messages I am using in the DLL. I then update that dll to return a different message and try to replace the previously used one, but I cannot. The file is locked by the application. Is there a way around this?
I've tried a few different ways to go about this code and my latest is trying container.ReleaseExports. I have tried disposing everything as well and get the same result. Am I doing something wrong, am I missing something, or is this simply not possible?
This seems like a duplicate post. Please take a look at this post. overwriting-dlls-in-mef
"This is not an MEF issue - it is your appdomain standard setup that locks the DLL's touched."
I usually get this error and (always) don't know how to solve it.
This time I got it also, it seems that I'm not understanding a concept or missing something
Here's the code
// create a new twitteroo core with provided username/password
TwitterooCore core = new TwitterooCore(username, password);
// request friends timeline from twitter
Users users = core.GetTimeline(Timeline.Friends); // error here
Please some help and also some explanations of what's happening
Thanks
This error is a pain, it basically means some vairable you're accessing is still Null.
In this instance, where do you initialise Timeline? Should your code be something like:
Users users = core.GetTimeline().Friends;
OK, I've been looking at the twiteroo documentation, which is a bit sparse, and I think you definitely need to instantiate an instance of Timeline to pass into GetTimeline, (which returns a collections of Users, not very well named IMHO). What I can't figure out is how to initiate an instance of Timeline.
OK, it's not Timeline that's null, (that's an Enum!) so as bthb says, it can only be the core, perhaps the username or password are wrong, or it can't connect to twitter?
I found the problem finally
It was because of my Firewall seems to be blocking connections to Visual Studio.
Now it works with no changes at all :)
Thanks for all your support
It could be core, username, password, or Timeline.Friends, impossible to know which by the info you have given us.
If I were you I'd put a breakpoint on the line that errors, then stick a watch on Timeline.Friends and check its not null, if its not then put a watch on core.GetTimeline(Timeline.Friends) and see if thats returning null.
It should give you a nudge in the right direction, you'll probably have to read the documentation for the twitter API your using to find out why either of these is returning null.
How about checking your code like:
Users users = null;
if (Timeline != null)
{
TwitterooCore core = new TwitterooCore(username, password);
if (core != null)
{
var friends = Timeline.Friends
if (friends != null)
users = core.GetTimeline(Timeline.Friends);
}
}
If this runs without exceptions one of the objects was probably null.
There are two specific phrases in the error message, object reference and instance of an object. These concepts are very basic when dealing with OOP languages.
First, an object reference can be thought of a variable in a function or class. This term may also refer to function parameters that expect a specific reference to an object. Initially the value of a variable is NULL until it is set to a value using the '=' operator. Frequently you will have a variable declaration and the '=' operation in the same statement.
The term instance of an object refers to an object that has been created using the syntax new. When you call new to initialize an object, an unused memory location is allocated to store a copy of the object until the program ends, or the object goes out of scope and is freed by the garbage collector. At creation time the object properties are defined by the constructor method called to create the object.
Consider this code:
Integer my_int;
my_int = new Integer(5);
In this example, 'my_int' is the object reference to an Integer object instance being created.
If you try to access 'my_int', before assigning it a reference to an Integer instance, then you would have the error, "an object reference (my_int) not set to an instance of an object (Integer)".
If you decompile the dll you will see that GetTimeline(Enum) takes in a Enumeration argument.
The Constructor call will be fine:
TwitterooCore core = new TwitterooCore(username, password);
Source:
public TwitterooCore(string username, string password)
{
this._username = username;
this._password = password;
}
GetTimeline is were the connection is attempted.
public Users GetTimeline(Timeline timeline)
{
WebClient client = new WebClient();
XmlDocument document = new XmlDocument();
string xml = string.Empty;
byte[] buffer = null;
client.set_Credentials(this.GetCredentials());
buffer = client.DownloadData(this.GetTimelineUrl(timeline));
xml = Encoding.UTF8.GetString(buffer);
document.LoadXml(xml);
return this.DecodeStatusXml(document);
}
May be Timeline.Friends is null and may be Timeline is null. I suggest you look at the stack trace of exception and into documentation of your twitter framework.