I use an Open Office API in my ASP .NET application for reading text content from *.doc files.
public static bool getTextV2(string siteURL, string[] search)
{
//Create a new ServiceManager Type object
Type tServiceManager = Type.GetTypeFromProgID("com.sun.star.ServiceManager", true);
//Create a new ServiceManager Com object using our
//ServiceManager type object
object oServiceManager = System.Activator.CreateInstance(tServiceManager);
//Create our Desktop Com object
object oDesktop = Invoke(oServiceManager, "createinstance",
BindingFlags.InvokeMethod,
"com.sun.star.frame.Desktop");
//Create an array for our load parameter
Object[] arg = new Object[4];
arg[0] = siteURL;
arg[1] = "_blank";
arg[2] = 0;
arg[3] = new Object[] { };
//Create our new blank document
object oComponent = Invoke(oDesktop,
"loadComponentFromUrl",
BindingFlags.InvokeMethod,
arg
);
//Create an empty array for the getText method
arg = new Object[0];
//Get our Text Com object
Object oText = Invoke(oComponent,
"getText",
BindingFlags.InvokeMethod,
arg
);
Object Text = Invoke(oText,
"getString",
BindingFlags.InvokeMethod,
arg
);
string content = Text.ToString();
content = content.ToLower();
bool flag = true;
foreach (string current in search)
{
if (!content.Contains(current)) flag = false;
}
arg = new Object[0];
Invoke(oComponent,
"dispose",
BindingFlags.InvokeMethod,
arg
);
return flag;
}
public static object Invoke(object obj, string method, BindingFlags binding, params object[] par)
{
return obj.GetType().InvokeMember(method, binding, null, obj, par);
}
But I have the following error:
Retrieving the COM class factory for component with CLSID {82154420-0FBF-11D4-8313-005004526AB4} failed due to the following error: 80080005.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Runtime.InteropServices.COMException: Retrieving the COM class factory for component with CLSID {82154420-0FBF-11D4-8313-005004526AB4} failed due to the following error: 80080005.
Source Error:
Line 56: //Create a new ServiceManager Com object using our
Line 57: //ServiceManager type object
Line 58: object oServiceManager = System.Activator.CreateInstance(tServiceManager);
Line 59: //Create our Desktop Com object
Line 60: object oDesktop = Invoke(oServiceManager, "createinstance",
So, there is a error at line 58.
Any ideas?
Quick guess: could it be that user under which your are running app never opened OpenOffice before. Try login as that user and run OpenOffice it will ask few questions, then close OpenOffice and logout. Then try to run your app again....
Related
I am attempting to convert established code into a .dll which will be able to be loaded as required by the main program. The .dll does not require any input parameters from the main program and is intended to only return a string value. My primary resource has been this answer.
The dll code is structured:
namespace DLL
{
class DLLClass
{
public string PublicString(string OutputString)
{
// ... existing code ...
return OutputString;
}
}
}
The main program attempts to load the .dll, execute the logic, and retrieve the returned string for display in the console:
static void Main()
{
var DLLPath = new FileInfo("DLL.dll");
Assembly assembly = Assembly.LoadFile(DLLPath.FullName);
Type t = assembly.GetType("DLL.DLLClass");
object obj = Activator.CreateInstance(t);
MethodInfo method = t.GetMethod("PublicString");
string TargetString = (string)method.Invoke(obj, null);
Console.WriteLine("End of dll");
Console.WriteLine(TargetString);
Console.ReadLine();
}
This method presently fails as a TargetParameterCountException ("Parameter count mismatch") occurs at the .Invoke line. The debug information indicates the OutputString remains null at the time of the exception, meaning the code within the .dll does not appear to have run yet.
Thank you in advance for any assistance in this matter.
Change the below code
string TargetString = (string)method.Invoke(obj, null);
to
object[] parametersArray = new object[] { "Hello" };
string TargetString = (string)method.Invoke(obj, parametersArray);
You are not passing parameter value to the calling method so that it is having such issue.
I am trying to load an assembly, System.Speech, via reflection, so that I can use the SpeakAsync method to read aloud some text.
I wrote this:
System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom("System.Speech.dll");
System.Type type = assembly.GetType("System.Speech.SpeechSynthesizer");
var methodinfo = type.GetMethod("SpeakAsync", new System.Type[] {typeof(string)} );
if (methodinfo == null) throw new System.Exception("No methodinfo.");
object[] speechparameters = new object[1];
speechparameters[0] = GetVerbatim(text); // returns something like "+100"
var o = System.Activator.CreateInstance(type);
methodinfo.Invoke(o, speechparameters);
But get the error
System.NullReferenceException: Object reference not set to an instance of an object
Your code contains bug, you can't work with class if you specified incorrect namespace (neither via reflection nor without it)
You use incorrect namespace here (that's why you received null reference exception ):
System.Type type = assembly.GetType("System.Speech.SpeechSynthesizer");//type == null
Here is example of correct namespaces:
System.Type type = assembly.GetType("System.Speech.Synthesis.SpeechSynthesizer");
Update1:
Another note. invoke returns a prompt, and you shouldn't exit the programm while asynchronous method is working (off course, only if you really want to listen speech to the end). I added few lines to your code to wait until speach will be finished:
internal class Program
{
private static void Main(string[] args)
{
var assembly = Assembly.LoadFrom("System.Speech.dll");
var type = assembly.GetType("System.Speech.Synthesis.SpeechSynthesizer");
var methodinfo = type.GetMethod("SpeakAsync", new[] {typeof(string)});
if (methodinfo == null) throw new Exception("No methodinfo.");
var speechparameters = new object[1];
speechparameters[0] = "+100"; // returns something like "+100"
var o = Activator.CreateInstance(type);
var prompt = (Prompt) methodinfo.Invoke(o, speechparameters);
while (!prompt.IsCompleted)
{
Task.Delay(500).Wait();
}
}
}
Update 2
Make sure you have the correct language pack.
MSDN
Update 3
If you use Mono, try to make sure that this feature should works on Mono. I gues there are some problems with Mono realization.
I'm getting this unhandled exception error:
An unhandled exception of type 'System.Reflection.TargetInvocationException' (Exception has been thrown by the target of an invocation) occurred in the 3rd line of bool variable in the following code of BackEndUtil.cs
public static bool iMigrateProcess(string inputXML, out string outputXML,object objWebClient, string webSessionID)
{
outputXML = "";
object[] args = new Object[] { inputXML, outputXML };
bool bSuccess = (bool)objWebClient.GetType().InvokeMember("Process",
BindingFlags.Default | BindingFlags.InvokeMethod, null, objWebClient, args);
outputXML = (string)args[1];
return bSuccess;
}
Here is the process method from other file (reference.cs)
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://BackendWebService.domain/Process", RequestNamespace="http://BackendWebService.domain/", ResponseNamespace="http://BackendWebService.domain/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string Process(string inputXML) {
object[] results = this.Invoke("Process", new object[] { inputXML });
return ((string)(results[0]));
}
Here I was consuming a web service (.asmx file) to stitch two image files. Here the inputXML seems to be fine containing XML of the file path of uploaded image file on server. However, the code doesn't go beyond line 3.
This code wasn't made by me so I have no idea how to troubleshoot this.
There are two InnerExceptions:
Make sure the file image is a valid managed assembly.
Make sure you have supplied a correct file path for the assembly.
Here is the code of iMigrateProcess from the Call Stack attached above.
public static bool iMigrateProcess(cDataContainer inputDC, out cDataContainer outputDC, object objWebClient)
{
return iMigrateProcess(inputDC, out outputDC, objWebClient, "");
}
public static bool iMigrateProcess(cDataContainer inputDC, out cDataContainer outputDC, object objWebClient, string webSessionID)
{
outputDC = null;
object[] args = new Object[] { inputDC, outputDC };
bool bSuccess = (bool)objWebClient.GetType().InvokeMember("Process",
BindingFlags.Default | BindingFlags.InvokeMethod, null, objWebClient, args);
outputDC = (cDataContainer)args[1];
return bSuccess;
}
I'm using the code at This Site to call a webservice dynamically.
[SecurityPermissionAttribute(SecurityAction.Demand, Unrestricted = true)]
public static object CallWebService(string webServiceAsmxUrl, string serviceName, string methodName, object[] args)
{
System.Net.WebClient client = new System.Net.WebClient();
//-Connect To the web service
using (System.IO.Stream stream = client.OpenRead(webServiceAsmxUrl + "?wsdl"))
{
//--Now read the WSDL file describing a service.
ServiceDescription description = ServiceDescription.Read(stream);
///// LOAD THE DOM /////////
//--Initialize a service description importer.
ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
importer.ProtocolName = "Soap12"; // Use SOAP 1.2.
importer.AddServiceDescription(description, null, null);
//--Generate a proxy client. importer.Style = ServiceDescriptionImportStyle.Client;
//--Generate properties to represent primitive values.
importer.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties;
//--Initialize a Code-DOM tree into which we will import the service.
CodeNamespace nmspace = new CodeNamespace();
CodeCompileUnit unit1 = new CodeCompileUnit();
unit1.Namespaces.Add(nmspace);
//--Import the service into the Code-DOM tree. This creates proxy code
//--that uses the service.
ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit1);
if (warning == 0) //--If zero then we are good to go
{
//--Generate the proxy code
CodeDomProvider provider1 = CodeDomProvider.CreateProvider("CSharp");
//--Compile the assembly proxy with the appropriate references
string[] assemblyReferences = new string[5] { "System.dll", "System.Web.Services.dll", "System.Web.dll", "System.Xml.dll", "System.Data.dll" };
CompilerParameters parms = new CompilerParameters(assemblyReferences);
CompilerResults results = provider1.CompileAssemblyFromDom(parms, unit1);
//-Check For Errors
if (results.Errors.Count > 0)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError oops in results.Errors)
{
sb.AppendLine("========Compiler error============");
sb.AppendLine(oops.ErrorText);
}
throw new System.ApplicationException("Compile Error Occured calling webservice. " + sb.ToString());
}
//--Finally, Invoke the web service method
Type foundType = null;
Type[] types = results.CompiledAssembly.GetTypes();
foreach (Type type in types)
{
if (type.BaseType == typeof(System.Web.Services.Protocols.SoapHttpClientProtocol))
{
Console.WriteLine(type.ToString());
foundType = type;
}
}
object wsvcClass = results.CompiledAssembly.CreateInstance(foundType.ToString());
MethodInfo mi = wsvcClass.GetType().GetMethod(methodName);
return mi.Invoke(wsvcClass, args);
}
else
{
return null;
}
}
}
This works fine when I use built in types, but for my own classes, I get this:
Event Type: Error
Event Source: TDX Queue Service
Event Category: None
Event ID: 0
Date: 12/04/2010
Time: 12:12:38
User: N/A
Computer: TDXRMISDEV01
Description:
System.ArgumentException: Object of type 'TDXDataTypes.AgencyOutput' cannot be converted to type 'AgencyOutput'.
Server stack trace:
at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at TDXQueueEngine.GenericWebserviceProxy.CallWebService(String webServiceAsmxUrl, String serviceName, String methodName, Object[] args) in C:\CkAdmDev\TDXQueueEngine\TDXQueueEngine\TDXQueueEngine\GenericWebserviceProxy.cs:line 76
at TDXQueueEngine.TDXQueueWebserviceItem.Run() in C:\CkAdmDev\TDXQueueEngine\TDXQueueEngine\TDXQueueEngine\TDXQueueWebserviceItem.cs:line 99
at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object[]& outArgs)
at System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(RuntimeMethodHandle md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object[]& outArgs)
at System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(IMessage msg, IMessageSink replySink)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.EndInvokeHelper(Message reqMsg, Boolean bProxyCase)
at System.Runtime.Remoting.Proxies.RemotingProxy.Invoke(Object NotUsed, MessageData& msgData)
at TDXQueueEngine.TDXQueue.RunProcess.EndInvoke(IAsyncResult result)
at TDXQueueEngine.TDXQueue.processComplete(IAsyncResult ar) in C:\CkAdmDev\TDXQueueEngine\TDXQueueEngine\TDXQueueEngine\TDXQueue.cs:line 130
For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
The classes reference the same assembly and the same version. Do I need to include my assembly as a reference when building the temporary assembly? If so, how?
Thanks.
Update
It appears that the best solution will be to build a routine that can map from AssemblyX.MyCustomType to an equivalent GeneratedAssembly.MyCustomType.
In my example, MyCustomType contains more types (which should all be part of the generated assembly) so it appears I need a method to do this "deep copy". Also, some of the properties of the TDXDataTypes.AgencyOutput are arrays of other classes, just to make things more fun...
I've created a new question for the mapping.
I reproduced the issue on my local machine and fixed that issue..
Following is what you need to do to make the custom object work
Ur current code is like this
object wsvcClass = results.CompiledAssembly.CreateInstance(foundType.ToString());
MethodInfo mi = wsvcClass.GetType().GetMethod(methodName);
return mi.Invoke(wsvcClass, args);
Let me try to explain the most probable reason for the problem to come.
when u r invoking a method in the assembly called as "methodname" in the webservice u r trying to pass the parameters required for that as args[] to the function "CallWebService"
This args[] when passed will be successfully working when u try to pass a normal parameters like primitive types including string.
But this is what u might be doing when u try to pass a custom object as a parameter
Three things that are done in this.
create an object of that type outside the CallWebService function (using reflection). when you do that way what happens is an instance of the customobject created with a temporary dll name internally.
once you set the set the properties of the object and send it across to the CallWebService function as an object in the args array.
U are trying to create an instance of the webservice by creating the dynamic dll.
object wsvcClass = results.CompiledAssembly.CreateInstance(foundType.ToString());
When you finally try to invoke the method with the instance of the dynamic assembly created
you are trying to pass your customobject that is created at step 1,2 via args property.
At the time of invocation the CLR tries to see if the customobject that is passed as input and the method that is being invoked are from the same DLL.
Which is obviously not from the way the implementation is done.
So following is the approach that should be used to overcome the problem
U need to create the custom object assembly with the same assembly that you used to the create the webservice instance...
I implemented this approach completely and it worked out fine:
MethodInfo m = type.GetMethod(methodName);
ParameterInfo[] pm = m.GetParameters();
object ob;
object[] y = new object[1];
foreach (ParameterInfo paraminfo in pm)
{
ob = this.webServiceAssembly.CreateInstance(paraminfo.ParameterType.Name);
foreach (PropertyInfo propera in ob.GetType().GetProperties())
{
if (propera.Name == "AppGroupid")
{
propera.SetValue(ob, "SQL2005Tools", null);
}
if (propera.Name == "Appid")
{
propera.SetValue(ob, "%", null);
}
}
y[0] = ob;
}
The class you compile dynamically will not be equal to the one you reference directly, and thus you cannot cast one to the other. For two classes to be equal, they have to come from the same assembly (or you can roll your own deserialization).
I would look into using something like AutoMapper to map between the two classes. You will set up a map from the compiled type to your references type, and then map the classes.
[Edit - code which compiles]
Example using AutoMapper:
object ret = DynWebservice.CallWebService(...);
Mapper.CreateMap(ret.GetType(), typeof(TDXDataTypes.AgencyOutput));
TDXDataTypes.AgencyOutput ao = (TDXDataTypes.AgencyOutput)Mapper.Map(ret, ret.GetType(), typeof(TDXDataTypes.AgencyOutput));
For passing custom objects, one way could be to de/serialize your custom object. Also see How to: Enable a Web Service to Send and Receive Large Amounts of Data and C# – Dynamically Invoke Web Service At Runtime
I've used the code here (http://www.crowsprogramming.com/archives/66) to dynamically call a web service and was able to convert the type by serializing it to XML and then back again. In my case, the type I'm trying to get to (T) is in a class file generated by WSDL.EXE pointing at the web service that I'm calling dynamically.
public T ConvertType<T>(object input)
{
XmlSerializer serializer = new XmlSerializer(input.GetType());
XmlSerializer deserializer = new XmlSerializer(typeof(T));
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
serializer.Serialize(sw, input);
}
using (StringReader sr = new StringReader(sb.ToString()))
{
return (T)deserializer.Deserialize(sr);
}
}
I want to convert an OpenOffice Impress Presentation file and convert it to HTML or JPEG.
I have found a few examples, but they appear to be broken. I would like to do it, in a way that it does not matter what version of OpenOffice is installed, and I do not want to bundle any interop dlls with my application. Therefore, I am looking for a solution that is done in C# reflection, preferably, or Perl using Win32-OLE.
Also, how would you hide the OpenOffice GUI?
Check out this solution . There might need some changes on the declaration of the PropertyValues
public void Conversion(string sourcefile, string exportfile)
{
Type tServiceManager = Type.GetTypeFromProgID("com.sun.star.ServiceManager", true);
object oServiceManager = System.Activator.CreateInstance(tServiceManager);
object oDesktop = Invoke(oServiceManager,"createinstance",BindingFlags.InvokeMethod,"com.sun.star.frame.Desktop");
//Load Document
Object[] arg = new Object[4];
arg[0] = PathConverter(sourcefile); // or "private:factory/swriter" for a blank Document
arg[1] = "_blank";
arg[2] = 0;
object loadproperty1 = CreatePropertyValue("Hidden", true); // Executes the OpenOffice without UI
arg[3] = new Object[] { loadproperty1};
object oComponent = Invoke(oDesktop,"loadComponentFromUrl",BindingFlags.InvokeMethod,arg);
//Create an array for the storeToUrl method
arg = new Object[2];
arg[0] = PathConverter(exportfile);
object storeproperty1 = CreatePropertyValue("Overwrite", true); // Overrites if file exits and prevents errors
object storeproperty2 = CreatePropertyValue("FilterName", "HTML (StarWriter)"); // Export to HTML
arg[1] = new Object[] { storeproperty1,storeproperty2 };
Invoke(oComponent,"storeToUrl",BindingFlags.InvokeMethod,arg);
}
I published a previous solution regarding the exportformats and the string you need to pass
Helper Methods:
private static object CreatePropertyValue(object serviceManager,string name, object value)
{
object propertyvalue = Invoke(serviceManager, "Bridge_GetStruct", BindingFlags.CreateInstance|BindingFlags.InvokeMethod|BindingFlags.GetProperty,
"com.sun.star.beans.PropertyValue");
Invoke(propertyvalue, "Name", BindingFlags.SetProperty, name);
Invoke(propertyvalue, "Value", BindingFlags.SetProperty, value);
return propertyvalue;
}
private static object Invoke(object obj, string method, BindingFlags binding, params object[] par)
{
return obj.GetType().InvokeMember(method, binding, null, obj, par);
}
/// Convert into OO file format
/// The file.
/// The converted file
private static string PathConverter( string file)
{
try
{
file = file.Replace(#"\", "/");
return "file:///"+file;
}
catch (System.Exception ex)
{
throw ex;
}
}
Use OpenOffice::OODoc, it understands the XML format of OpenOffice documents, requires no openoffice binaries to be running or even to have openoffice installed.