var speechEngine = new SpVoiceClass();
SetVoice(speechEngine, job.Voice);
var fileMode = SpeechStreamFileMode.SSFMCreateForWrite;
var fileStream = new SpFileStream();
try
{
fileStream.Open(filePath, fileMode, false);
speechEngine.AudioOutputStream = fileStream;
speechEngine.Speak(job.Script, SpeechVoiceSpeakFlags.SVSFPurgeBeforeSpeak | SpeechVoiceSpeakFlags.SVSFDefault); //TODO: Change to XML
//Wait for 15 minutes only
speechEngine.WaitUntilDone((uint)new TimeSpan(0, 15, 0).TotalMilliseconds);
}
finally
{
fileStream.Close();
}
This exact code works in a WinForm app, but when I run it inside a webservice I get the following
System.Runtime.InteropServices.COMException was unhandled
Message="Exception from HRESULT: 0x80045003"
Source="Interop.SpeechLib"
ErrorCode=-2147201021
Does anyone have any ideas what might be causing this error? The error code means
SPERR_UNSUPPORTED_FORMAT
For completeness here is the SetVoice method
void SetVoice(SpVoiceClass speechEngine, string voiceName)
{
var voices = speechEngine.GetVoices(null, null);
for (int index = 0; index < voices.Count; index++)
{
var currentToken = (SpObjectToken)voices.Item(index);
if (currentToken.GetDescription(0) == voiceName)
{
speechEngine.SetVoice((ISpObjectToken)currentToken);
return;
}
}
throw new Exception("Voice not found: " + voiceName);
}
I have given full access to USERS on the folder C:\Temp where the file is to be written. Any help would be appreciated!
I don't think the System.Speech works in windows service. It looks like there is a dependency to Shell, which isn't available to services. Try interop with SAPI's C++ interfaces. Some class in System.Runtime.InteropServices may help on that.
Our naming convention requires us to use a non-standard file extension. This works fine in a Winforms app, but failed on our web server. Changing the file extension back to .wav solved this error for us.
Make sure you explicitly set the format on the SPFileStream object. ISpAudio::SetState (which gets called in a lower layer from speechEngine.Speak) will return SPERR_UNSUPPORTED_FORMAT if the format isn't supported.
I just got the webservice to spawn a console app to do the processing. PITA :-)
Related
I am attempting to get the metadata from a few music files and failing miserably. Online, there seems to be absolutely NO HOPE in finding an answer; no matter what I google. I thought it would be a great time to come and ask here because of this.
The specific error I got was: Error HRESULT E_FAIL has been returned from a call to a COM component. I really wish I could elaborate on this issue, but I'm simply getting nothing back from the COMException object. The error code was -2147467259, and it in hex is -0x7FFFBFFB, and Microsoft have not documented this specific error.
I 70% sure that its not the file's fault. My code will run through a directory full of music and convert the file into a song, hence the ConvertFileToSong name. The function would not be running if the file were to not exist is what I'm trying to say.
The only thing I can really say is that I'm using Dotnet 6, and have a massive headache.
Well, I guess I could also share another problem I had before this error showed up. Dotnet6 has top level code or whatever its called, this means that I can't add the [STAThread] attribute. To solve this, I simply added the code bellow to the top. Not sure why I have to set it to unknown, but that's what I (someone else on Stack Overflow) have to do. That solved that previous problem that the Shell32 could not start, but could that be causing my current problem? Who knows... definitely not me.
Thread.CurrentThread.SetApartmentState(ApartmentState.Unknown);
Thread.CurrentThread.SetApartmentState(ApartmentState.STA);
Here is the code:
// Help from: https://stackoverflow.com/questions/37869388/how-to-read-extended-file-properties-file-metadata
public static Song ConvertFileToSong(FileInfo file)
{
Song song = new Song();
List<string> headers = new List<string>();
// initialise the windows shell to parse attributes from
Shell32.Shell shell = new Shell32.Shell();
Shell32.Folder objFolder = null;
try
{
objFolder = shell.NameSpace(file.FullName);
}
catch (COMException e)
{
int code = e.ErrorCode;
string hex = code.ToString();
Console.WriteLine("MESSAGE: " + e.Message + ", CODE: " + hex);
return null;
}
Shell32.FolderItem folderItem = objFolder.ParseName(file.Name);
// the rest of the code is not important, but I'll leave it there anyway
// pretty much loop infinetly with a counter better than
// while loop because we don't have to declare an int on a new
// line
for (int i = 0; i < short.MaxValue; i++)
{
string header = objFolder.GetDetailsOf(null, i);
// the header does not exist, so we must exit
if (String.IsNullOrEmpty(header)) break;
headers.Add(header);
}
// Once the code works, I'll try and get this to work
song.Title = objFolder.GetDetailsOf(folderItem, 0);
return song;
}
Good night,
Diseased Finger
Ok, so the solution isn't that hard. I used file.FullName which includes the file's name, but Shell32.NameSpace ONLY requires the directory name (discluding the file name).
This is the code that fixed it:
public static Song ConvertFileToSong(FileInfo file)
{
// .....
Shell32.Shell shell = new Shell32.Shell();
Shell32.Folder objFolder = file.DirectoryName;
Shell32.FolderItem folderItem = objFolder.ParseName(file.Name);
// .....
return something;
}
When I run this code:
var stream = File.OpenRead(#"C:\tmp\PdfToTest.PDF");
var latestVersion = GhostscriptVersionInfo.GetLastInstalledVersion();
rasterizer = new GhostscriptRasterizer();
rasterizer.Open(stream, latestVersion, false);
I am getting this error
An exception of type 'Ghostscript.NET.GhostscriptAPICallException' occurred in Ghostscript.NET.dll but was not handled in user code
Additional information: An error occured when call to 'gsapi_init_with_args' is made: -15
The error is in this line:
rasterizer.Open(stream, latestVersion, false);
Anyone could point me what it is causing this to happen?
I am running this in local machine. Installed the Ghostscript on Package manager console. Everything seems to be right, but it simple doesn't work.
-15 is a 'rangecheck' error. There should be considerable extra backchannel information which might give some useful details. However since you are not using Ghostscript directly I can't tell you where it might be going.
You should put the PDF file you are using as input somewhere public at least so we can look at it.
Ideally you should reproduce the problem with Ghostscript itself, from the command line, but in any event you must supply the configuration information (ie what settings you have used). The version of Ghostscript (and whether its 32 or 64 bit) would also be useful information.
I'm afraid there's nothing much anyone can do with what you've given us to go on.
This is my working example.
So I call the method ResizePDF(string filePath) and give the file path including extension (eg. C:\tmp\file.pdf) as parameter.
The method returns the memoryStream with the resized file that I can use to do whatever.
There are some work to do around it, however it is working so far.
internal MemoryStream ResizePDF(string filePath)
{
string inputFilePath = String.Format(#"{0}", filePath);
GhostscriptPipedOutput gsPipedOutput = new GhostscriptPipedOutput();
string outputPipeHandle = "%handle%" + int.Parse(gsPipedOutput.ClientHandle).ToString("X2");
MemoryStream memStream = null;
using (GhostscriptProcessor processor = new GhostscriptProcessor())
{
try
{
processor.Process(GetGsArgs(inputFile, outputPipeHandle));
byte[] rawDocumentData = gsPipedOutput.Data;
memStream = new MemoryStream(rawDocumentData);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
gsPipedOutput.Dispose();
gsPipedOutput = null;
}
}
return memStream;
}
private string[] GetGsArgs(string inputFilePath, string outputFilePath)
{
List<string> switches = new List<string>();
switches.Add("-empty");
switches.Add("-dQUIET");
switches.Add("-dSAFER");
switches.Add("-dBATCH");
switches.Add("-dNOPAUSE");
switches.Add("-dNOPROMPT");
switches.Add("-dPDFSETTINGS=/ebook");
switches.Add("-sDEVICE=pdfwrite");
switches.Add("-sPAPERSIZE=a4");
switches.Add("-sOutputFile=" + outputPipeHandle);
switches.Add("-f");
switches.Add(inputFilePath);
return switches.ToArray();
}
Thanks you all.
I need some help on calling foxprogram from c# code.
We have dedicated machine where we have fox releated program.
Machine Name : TestFox
We have shared folder \\TestFox\FoxPrograms
I need to call init.prg which is present in \\TestFox\FoxPrograms [It is built in vfp9]
I used the below code
try
{
string foxCommand = "init.prg";
var parse = new FoxApplication();
parse.DefaultFilePath = #"\\TestFox\FoxPrograms";
parse.DoCmd(foxCommand);
}
catch (Exception ex)
{
//I m getting exception
//{System.Runtime.InteropServices.COMException (0x80020009):
//Exception occurred. (Exception from HRESULT:
//0x80020009 (DISP_E_EXCEPTION)) at VisualFoxpro.Application.DoCmd
//(String bstrCmd)
//at CallFox.Program.CallFoxPraser(String step)
//in C :\Users\ssnagendrakumar\documents\
//visual studio 2010\Projects\CallFox\CallFox\Program.cs:line 32}
}
I refered vfp9.exe in solution to get FoxApplication()
Can someone help me? please
I believe you need to use the VisualFoxpro.FoxApplication class, and you are passing invalid syntax - to execute a VFP program you need to use the DO command:
var parse = new VisualFoxpro.FoxApplication;
string foxCommand = "do init.prg";
parse.DefaultFilePath = #"\\TestFox\FoxPrograms";
parse.DoCmd(foxCommand);
After scouring the web I am completely stuck on an application I am building to push directories up to Amazon S3 using C# (Targeting .NET 4.5). I am getting NullReferenceExceptions on the line of code that pushes the directory files using the UploadDirectory(TransferUtilityUploadDirectoryRequest) method of the TransferManager class. The problem is I cannot find anything that is null! The debugger doesn't show anything null either, so I'm obviously missing something here.
I read up that if you are uploading to buckets that have periods in them, you need to change the protocol to HTTP otherwise a NullReferenceException might be thrown, however I've done this as well and am continuing to receive the error, even when I created another bucket for testing that has no periods in it.
The portion of my code up to & including the line that causes the exception is below. The class called S3Info is just a helper class that I created that just stores some configuration info such as access/secret keys and other info:
public static void uploadDirectories(S3Info info, List<DirectoryInfo> dirs, Logger logger = null)
{
AmazonS3Config alterConfig = new AmazonS3Config();
alterConfig.CommunicationProtocol = Protocol.HTTP;
AmazonS3Client s3Client = new AmazonS3Client(info.getCredentials(), alterConfig);
TransferUtility directoryTransferUtil = new TransferUtility(s3Client);
TransferUtilityUploadDirectoryRequest uploadDirRequest;
PutObjectRequest completeFileUploadRequest;
uint uploadSuccessCount = 0;
if (dirs == null || dirs.Count == 0)
{
logger.log("Nothing to upload.");
return;
}
//upload directory with PDFs
foreach (DirectoryInfo dir in dirs)
{
try
{
//configure upload request
uploadDirRequest = new TransferUtilityUploadDirectoryRequest();
uploadDirRequest.BucketName = info.selectedBucket.BucketName;
uploadDirRequest.Directory = dir.FullName;
uploadDirRequest.KeyPrefix = dir.Name + #"\";
uploadDirRequest.SearchOption = SearchOption.TopDirectoryOnly;
uploadDirRequest.SearchPattern = "*.pdf";
uploadDirRequest.Timeout = 600000; //10 minutes
//upload directory!
directoryTransferUtil.UploadDirectory(uploadDirRequest); //exception thrown here
I'm a bit stuck at this point so I'm open to any suggestions the community can provide. Thanks.
EDIT: Stack Trace-
Object reference not set to an instance of an object. :
at Amazon.S3.Transfer.Internal.UploadDirectoryCommand.Execute()
at Amazon.S3.Transfer.TransferUtility.UploadDirectory(TransferUtilityUploadDirectoryRequest request)
at S3Delivery.AmazonActions.uploadDirectories(S3Info info, List`1 dirs, Logger logger) in c:\Users\jblacker\Documents\Visual Studio 2012\Projects\S3Delivery\S3Delivery\AmazonActions.cs:line 173
Line 173 is the line referred to above.
A patched version of the SDK (version 1.5.30.1) was released earlier today that fixes this issue.
I posted this same question on the AWS Forums. Apparently the API was broken for the method: UploadDirectory() in version 1.5.30 of the .NET SDK.
Amazon has just posted a patch as version 1.5.30.1
I have an issue where I need to be able to have a compiled exe ( .net 3.5 c# ) that I will make copies of to distribute that will need to change a key for example before the exe is sent out.
I cannot compile each time a new exe is needed. This is a thin client that will be used as part of a registration process.
Is it possible to add a entry to a resource file with a blank value then when a request comes in have another application grab the blank default thin client, copy it, populate the blank value with the data needed.
If yes how? If no do you have any ideas? I have been scratching my head for a few days now and the limitation as due to the boundaries I am required to work in.
The other idea I has was to inject the value into a method, which I have no idea how I would even attempt that.
Thanks.
Convert the assembly to IL, do a textual search and replace, recompile the IL to an assembly again. Use the standard tools from the .NET SDK.
Instead of embedding the key in the assembly, put it in the app.config file (or another file delivered with the application) and prevent your application from running if the key is not present and valid. To protect it against modification by users, also add an RSA signature the config file.
This code could be used to generate XML containing your key.
public static void Main()
{
Console.WriteLine(GenerateKey());
}
public static Byte[] Transform(Byte[] bytes, ICryptoTransform xform)
{
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
{
using (CryptoStream cstream = new CryptoStream(stream, xform, CryptoStreamMode.Write))
{
cstream.Write(bytes, 0, bytes.Length);
cstream.Close();
stream.Close();
return stream.ToArray();
}
}
}
public static string GenerateKey()
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
// This is the private key and should never be shared.
// Generate your own with RSA.Create().ToXmlString(true).
String rsaPrivateKey = "<RSAKeyValue><Modulus>uPCow37yEzlKQXgbqO9E3enSOXY1MCQB4TMbOZyk9eXmc7kuiCMhJRbrwild0LGO8KE3zci9ETBWVVSJEqUqwtZyfUjvWOLHrf5EmzribtSU2e2hlsNoB2Mu11M0SaGd3qZfYcs2gnEnljfvkDAbCyJhUlxmHeI+35w/nqSCjCk=</Modulus><Exponent>AQAB</Exponent><P>4SMSdNcOP0qAIoT2qzODgyl5yu9RubpIU3sSqky+85ZqJHXLUDjlgqAZvT71ROexJ4tMfMOgSWezHQwKWpz3sw==</P><Q>0krr7cmorhWgwCDG8jmzLMo2jafAy6tQout+1hU0bBKAQaPTGGogPB3hTnFIr84kHcRalCksI6jk4Xx/hiw+sw==</Q><DP>DtR9mb60zIx+xkdV7E8XYaNwx2JeUsqniwA3aYpmpasJ0N8FhoJI9ALRzzp/c4uDiuRNJIbKXyt6i/ZIFFH0qw==</DP><DQ>mGCxlBwLnhkN4ind/qbQriPYY8yqZuo8A9Ggln/G/IhrZyTOUWKU+Pqtx6lOghVdFjSxbapn0W8QalNMFGz7AQ==</DQ><InverseQ>WDYfqefukDvMhPHqS8EBFJFpls/pB1gKsEmTwbJu9fBxN4fZfUFPuTnCIJsrEsnyRfeNTAUFYl3hhlRYZo5GiQ==</InverseQ><D>qB8WvAmWFMW67EM8mdlReI7L7jK4bVf+YXOtJzVwfJ2PXtoUI+wTgH0Su0IRp9sR/0v/x9HZlluj0BR2O33snQCxYI8LIo5NoWhfhkVSv0QFQiDcG5Wnbizz7w2U6pcxEC2xfcoKG4yxFkAmHCIkgs/B9T86PUPSW4ZTXcwDmqU=</D></RSAKeyValue>";
rsa.FromXmlString(rsaPrivateKey);
String signedData = "<SignedData><Key>Insert your key here</Key></SignedData>";
Byte[] licenseData = System.Text.Encoding.UTF8.GetBytes(signedData);
Byte[] sigBytes = rsa.SignData(licenseData, new SHA1CryptoServiceProvider());
String sigText = System.Text.Encoding.UTF8.GetString(Transform(sigBytes, new ToBase64Transform()));
System.Text.StringBuilder sb = new StringBuilder();
using (System.Xml.XmlWriter xw = System.Xml.XmlTextWriter.Create(sb))
{
xw.WriteStartElement("License");
xw.WriteRaw(signedData);
xw.WriteElementString("Signature", sigText);
xw.WriteEndElement();
}
return sb.ToString();
}
Example output from this code:
<?xml version="1.0" encoding="utf-16"?>
<License>
<SignedData>
<Key>Insert your key here</Key>
</SignedData>
<Signature>cgpmyqaDlHFetCZbm/zo14NEcBFZWaQpyHXViuDa3d99AQ5Dw5Ya8C9WCHbTiGfRvaP4nVGyI+ezAAKj287dhHi7l5fQAggUmh9xTfDZ0slRtvYD/wISCcHfYkEhofXUFQKFNItkM9PnOTExZvo75pYPORkvKBF2UpOIIFvEIU=</Signature>
</License>
Then you can use code like this to verify it. You never have to distribute the private key:
public static Boolean CheckLicenseSignature(String licXml)
{
try
{
System.Xml.XmlDocument xd = new System.Xml.XmlDocument();
xd.LoadXml(licXml);
String licSig = xd.SelectSingleNode("/License/Signature").InnerText;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
String rsaPublicKey = "<RSAKeyValue><Modulus>uPCow37yEzlKQXgbqO9E3enSOXY1MCQB4TMbOZyk9eXmc7kuiCMhJRbrwild0LGO8KE3zci9ETBWVVSJEqUqwtZyfUjvWOLHrf5EmzribtSU2e2hlsNoB2Mu11M0SaGd3qZfYcs2gnEnljfvkDAbCyJhUlxmHeI+35w/nqSCjCk=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
rsa.FromXmlString(rsaPublicKey);
Byte[] licenseData = System.Text.Encoding.UTF8.GetBytes(xd.SelectSingleNode("/License/SignedData").OuterXml);
return rsa.VerifyData(licenseData, new SHA1CryptoServiceProvider(), Transform(System.Text.Encoding.UTF8.GetBytes(licSig), new FromBase64Transform()));
}
catch (System.Xml.XmlException ex)
{
return false;
}
catch (InvalidOperationException ex)
{
return false;
}
}
From within the capability of the .NET code itself, I'm not sure if this is doable. But it is possible to dynamically generate a .NET DLL which contains some key that can be referred from the main application. That is, if you wouldn't mind a second file in the distribution.
Or if you don't mind to use Ildasm to disassemble the .exe, change the key, then use Ilasm to reassemble, then you can do something to automate that.
The accepted answer is GARBAGE!
I HAVE DONE THIS SUCCESSFULLY. MUCH EASIER
Just put your base application (.net) that needs the key somewhere with a string resource FILLED WITH "XXXXXXXXXXXXXXX" (more than you'll need)
.Net resources are usually kept at the top of the code so you will find them fast skipping the first 100,000 bytes in my case.
Then you just read it in and look for those XXXXXX's. When you find them you replace them with the real API key and replace the rest of the X's with spaces you just trim off in code. This is the answer. It works and it works well.
ApiToken at = new ApiToken(UserId, SelectedCID);
at.MakeToken();
byte[] app = System.IO.File.ReadAllBytes(Path.Combine(AppDomain.CurrentDomain.GetData("DataDirectory").ToString(), "notkeyedapp.exe"));
for (int i = 100000; i < app.Length; i++)
{
if (app[i] == 0x58 && app[i + 1] == 0x58 && app[i + 2] == 0x58)
{
for (int j = 0; j < 128; j++)
{
if (at.Token.Length >= j + 1)
app[i + j] = System.Text.Encoding.ASCII.GetBytes(at.Token[j].ToString())[0];
else
app[i + j] = 0x20;
}
break;
}
}
string filename = "SoftwareProduct for - " + BaseModel.CompanyName.Replace(".", "") + ".exe";
return File(app, System.Net.Mime.MediaTypeNames.Application.Octet, filename);
I don't think You can get away without recompiling Your .exe and having key embedded into said .exe. The compilation process can be automated though via use of ildasm.exe and ilasm.exe as Daniel Earwicker suggested in his response https://stackoverflow.com/a/2742902/2358659
I'd like to expand on that if anyone else stumbles across this topic in the future.
I recently was facing similar problem due to my poor source code version control habits. In a nutshell I had an executable that was supposed to write some data to a Google Spreadsheet by referencing it's ID. Long after executable was released came another request from a different team to use the tool, but it had to write same information into a different spreadsheet in order to keep data separate for two teams. At the time I did not have the original source code, hence I was not able to change the static variable holding the original spreadsheet ID. What I did was as follows:
Using CMD.exe → call "C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\ildasm.exe" "myApplication.exe" /out="myApplication.il"
Using Notepad++ → Find and replace original ID to new ID inside myApplication.il file. This action can also be automated by writing own C# application to do this, or using PowerShell, or using vb/j-script or using some other find and replace tool available off-the-shelf, like FART (using CMD.exe → call fart.exe myApplication.il "OldKey" "NewKey")
Using CMD.exe → call "C:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe" "myApplication.il" /res="myApplication.res" /key="myApplicationKeyFile.snk"
As You see, all of these steps can be put into one .bat file that takes "NewKey" as an input and produces new .exe with NewKey embedded.
I hope that helps.
What comes to my mind, but not tried yet: Create a default String in your program, for example as
static public string regGuid = "yourguidhere";
Then, search the compiled EXE with any decent hex editor. If you find the string, replace it with another test. If you still can execute the program, you could try to automate this process and voila! Here you are.