How to load images from Resources, please? Some of my images are located inside a folder.
My image is saved as Resource (cf. Build Action). I don't use a .resx file.
I'm able to retrieve the list of all my resources with the help of this function:
public static string[] GetResourceNames()
{
var asm = Assembly.GetEntryAssembly();
string resName = asm.GetName().Name + ".g.resources";
using (var stream = asm.GetManifestResourceStream(resName))
using (var reader = new System.Resources.ResourceReader(stream))
{
return reader.Cast<DictionaryEntry>().Select(entry => (string)entry.Key).ToArray();
}
}
but I'm not able to load the resource (an image in my case).
Here are my tests:
string[] resourceNames = GetResourceNames();
Assembly assembly = Assembly.GetExecutingAssembly();
string projectName = assembly.GetName().Name;
string gresourceName = assembly.GetName().Name + ".g.resources";
//string gresourceName = assembly.GetName().Name + ".Properties.Resources";
var rm = new System.Resources.ResourceManager(gresourceName, typeof(Resources).Assembly);
var list = resourceNames.OrderBy(q => q).ToList(); //sort
//get all png images
foreach (string resourceName in list)
{
if (resourceName.EndsWith(".png"))
{
try
{
Console.WriteLine(resourceName.ToString());
//var test = (Bitmap)rm.GetObject(resourceName);
Stream imageStream = assembly.GetManifestResourceStream(gresourceName + "." + resourceName);
}
catch (Exception ex) {
Console.WriteLine("EXCEPTION: " + ex.Message);
}
}
}
In my case:
assembly = "VisualStudioTest"
resourceName = "testImages/add_32x32.png"
I've tried all combinations without success.
By example:
assembly.GetManifestResourceStream("VisualStudioTest.Properties.Resources.testImages.add_32x32.png")
assembly.GetManifestResourceStream("VisualStudioTest.g.resources.testImages.add_32x32.png")
According to Build actions page, Resource Build Type is for WPF projects. Are you working on a WPF project?
Using Embedded Resources instead would look like this:
var asm = Assembly.GetEntryAssembly();
foreach (string resourceName in asm.GetManifestResourceNames())
{
if (resourceName.EndsWith(".png"))
{
try
{
Console.WriteLine(resourceName.ToString());
Stream imageStream = assembly.GetManifestResourceStream(resourceName);
}
catch (Exception ex)
{
Console.WriteLine("EXCEPTION: " + ex.Message);
}
}
}
One trick I use in my own code is to query the resource names to match the short file name I'm looking for (e.g. "add_32x32.png") and just use that fully qualified name to pull the image.
private Image fromResource(string shortFileName)
{
var asm = GetType().Assembly;
var resource =
asm
.GetManifestResourceNames()
.First(_ => _.Contains(shortFileName));
using (var stream = asm.GetManifestResourceStream(resource))
{
return new Bitmap(stream);
}
}
I am working on functionality that allows users to write VB scripts and attach them to controls as actions. If user wants to perform something more or something specific he can write it in VB script and attach it, for example, to button (whole application is something like powerpoint presentation but with dynamic data etc).
The problem is i have issue compiling the script in C# project.
Input is at least two files (one main script, and other are additional).
This is first method that prepares references adn calls the compilation method.
public CompilerErrorCollection CompileClient(string fname, string[] VbFiles)
{
string currentDir = CurrentWorkingDir();
List<string> names = new List<string>();
string[] anames = CompilerHelper.DefaultReferencedAssembliesWpf;
foreach (string s in anames)
{
names.Add(s);
}
AddReference(names, Path.Combine(currentDir, "PresentationBase.dll"), true);
var sFolderPath = currentDir + "\\S";
AddReference(names, Path.Combine(sFolderPath, "Client.WPF.Common.dll"), true);
AddReference(names, Path.Combine(sFolderPath, "Client.WPF.CommonControls.dll"), true);
AddReference(names, Path.Combine(sFolderPath, "Client.WPF.CommonModels.dll"), true);
AddReference(names, Path.Combine(sFolderPath, "Client.WPF.Presentation.dll"), true);
AddReference(names, Path.Combine(sFolderPath, "Client.WPF.SyncfusionControls.dll"), true);
AddReference(names, Path.Combine(sFolderPath, "ClientAd.WPF.dll"), true);
AddReference(names, Path.Combine(sFolderPath, "ClientCore.dll"), true);
AddReference(names, Path.Combine(sFolderPath, "ClientInfrastructure.dll"), true);
AddReference(names, Path.Combine(sFolderPath, "ClientWcf.dll", true),
string filenamestamp = fname + ".stamp";
string stampPath = Path.Combine(currentDir, filenamestamp);
try
{
string uid = Funcs.UniqeID(true, 12);
TextWriter wr2 = File.CreateText(stampPath);
wr2.WriteLine(uid + " " + DateTime.Now);
wr2.Close();
}
catch (Exception ex)
{
/ ... /
}
CompilerErrorCollection lcErrors;
CompilerHelper.Compile(VbFiles, out lcErrors, names, fname);
return lcErrors;
}
Compile method:
public static Assembly Compile(string[] files, out CompilerErrorCollection errors,
List<string> referencedAssemblies, string outputAssemblyFileName)
{
try
{
FileInfo sourceFile = new FileInfo(files[0]);
CodeDomProvider provider = null;
errors = new CompilerErrorCollection();
bool compileOk = false;
if (sourceFile.Extension.ToUpper(CultureInfo.InvariantCulture) == ".VB")
{
//provider = CodeDomProvider.CreateProvider("VisualBasic");
provider = new VBCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
}
else
{
Console.WriteLine("Source file must have a .vb extension");
}
if (provider != null)
{
CompilerParameters cp = new CompilerParameters();
// Generate an executable instead of
// a class library.
cp.GenerateExecutable = false;
// Specify the assembly file name to generate.
cp.OutputAssembly = outputAssemblyFileName; //exeName;
// Save the assembly as a physical file.
cp.GenerateInMemory = true;
// Set whether to treat all warnings as errors.
cp.TreatWarningsAsErrors = false;
cp.WarningLevel = 4;
cp.TempFiles.KeepFiles = false;
cp.IncludeDebugInformation = true;
string[] names = new string[referencedAssemblies.Count];
int nr = 0;
foreach (string name in referencedAssemblies)
{
names[nr] = name;
nr++;
}
cp.ReferencedAssemblies.AddRange(names);
// Invoke compilation of the source file.
//CompilerResults cr = provider.CompileAssemblyFromFile(cp, sourceName);
CompilerResults cr = provider.CompileAssemblyFromFile(cp, files);
errors = cr.Errors;
if (cr.Errors.Count > 0)
{
// Display compilation errors.
Debug.WriteLine("Errors building assembly into {0}", cr.PathToAssembly);
foreach (CompilerError ce in cr.Errors)
{
Debug.WriteLine(" {0}", ce.ToString());
Debug.WriteLine("");
}
}
else
{
// Display a successful compilation message.
Debug.WriteLine("Source built into {0} successfully.", cr.PathToAssembly);
}
// Return the results of the compilation.
if (cr.Errors.Count > 0)
{
return null;
}
else
{
return cr.CompiledAssembly;
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
throw;
}
return null;
}
And this are references from system:
public static string[] DefaultReferencedAssembliesWpf =
{
NetRootFolderx86_En + "System.dll",
NetRootFolderx86_En + "System.Core.dll",
NetRootFolderx86_En + "System.Data.dll",
NetRootFolderx86_En + "System.Data.DataSetExtensions.dll",
NetRootFolderx86_En + "System.Windows.Forms.dll",
NetRootFolderx86_En + "PresentationCore.dll",
};
After line with CompilerResults cr = provider.CompileAssemblyFromFile(cp, files); i got those errors:
error BC30009: Reference required to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' containing the implemented interface 'System.Collections.Generic.IList`1'. Add one to your project.} object {System.CodeDom.Compiler.CompilerError}
error BC30451: 'MessageBox' is not declared. It may be inaccessible due to its protection level.} object {System.CodeDom.Compiler.CompilerError}
error BC30009: Reference required to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' containing the implemented interface 'System.Collections.Generic.IList`1'. Add one to your project.} object {System.CodeDom.Compiler.CompilerError}
After i add reference netstandard i get another error with System.Windows.Browser, then with System.Private.CoreLib.dll and adding those don't help.
Does someone have any experience in compiling in similar way or know what I am missing?
The scripts compiles fine without errors when i create VB Console app Project in visual studio.
Why do I even need netstandard in this project?
Ok, so i have reinstalled .Net Framework 4.8 and after attaching netstandard.dll from .Net Framework directory everything is fine now.
I have been creating a plugin model where code will be written on the server and a dll output will be created and downloaded to the client side.
This works well, but as we also want to have debugging support for the code that is generated in server, I tried the following code to download on client.
public OutputResponse GetObject(string fileName, string sourceCode)
{
string[] assemblies = this.GetAssemblies();
string codeLanguage = "cs";
var dllFilePath = Path.Combine(Path.GetTempPath(), fileName + ".dll");
var pdbFilePath = Path.Combine(Path.GetTempPath(), fileName + ".pdb");
//Delete Existing file
if (File.Exists(dllFilePath))
File.Delete(dllFilePath);
if (File.Exists(pdbFilePath))
File.Delete(pdbFilePath);
Dictionary<string, string> compilerInfo = new Dictionary<string, string>();
compilerInfo.Add("CompilerVersion", "v4.0");
CodeDomProvider provider = CodeDomProvider.CreateProvider(codeLanguage, compilerInfo);
var compilerParameter = new CompilerParameters();
compilerParameter.WarningLevel = 3;
compilerParameter.GenerateExecutable = false;
compilerParameter.GenerateInMemory = false;
compilerParameter.IncludeDebugInformation = true;
compilerParameter.CompilerOptions = "/debug:pdbonly";
compilerParameter.TempFiles = new TempFileCollection(Environment.GetEnvironmentVariable("TEMP"), true);
compilerParameter.TempFiles.KeepFiles = true;
compilerParameter.OutputAssembly = dllFilePath;
foreach (var assembly in assemblies)
compilerParameter.ReferencedAssemblies.Add(assembly);
var results = provider.CompileAssemblyFromSource(compilerParameter, sourceCode);
string sourceFile = string.Empty;
string pdbFile = Path.Combine(Path.GetDirectoryName(results.PathToAssembly), string.Concat(Path.GetFileNameWithoutExtension(results.PathToAssembly), ".pdb"));
foreach(string file in results.TempFiles)
{
var extension = Path.GetExtension(file);
switch(extension)
{
case ".cs":
sourceFile = file;
break;
}
}
var response = new OutputResponse(results.PathToAssembly, pdbFile, sourceFile);
return response;
}
The dll is generated correctly, and I am renaming the pdb and source file to the dll name, and downloaded to the client folder.
Now when a method is called using in the application which plugs in the dll, the Visual Studio cannot attach the debugger. It says "A matching symbol file was not found in this folder".
Can anyone help me on how to solve this problem.
I updated my gPRC version for the WebApplication from 0.12.0 to 0.13.0 and it started failing to create a Channel object. Following is the exception thrown:
It is trying to locate grpc_csharp_ext.dll at AppData\\Local\\Temp\\Temporary ASP.NET Files\\root\\c8490d1a\\9f150f28\\assembly\\dl3\\5d08d985\\2c1c8757_6474d101\\nativelibs\\windows_x86\\grpc_csharp_ext.dll. I even stored the DLL in local bin folder but that didn't help. This problem does not occur if I create a Console app. I am not sure why it is trying to search the dll at the said location? Does anyone know how to make it work for a web application?
Edit This issue is fixed by GRPC Community as per Link. I have also verified the same. Now we need to keep the grpc_csharp_ext.dll under bin\nativelibs\windows_x86\ (for 32 bit dll) and bin\nativelibs\windows_x64\ (for 64 bit dll)
Asp.net performs Shadow Copying Assemblies during dynamic compilation. It copies Grpc.Core.dll but not the folder nativelibs that contains the native grpc_csharp_ext.dll files.
I have resolved this issue by programmatically coping the nativelibs folder.
Invoke the copy method from Application_Start in Global.asax.
public class WebApplication : HttpApplication
{
protected void Application_Start()
{
GrpcInitializer.EnsureGrpcCSharpExtNativeDll();
}
}
Copier:
public static class GrpcInitializer
{
public static void EnsureGrpcCSharpExtNativeDll()
{
var grpcCoreAssembly = Assembly.GetAssembly(typeof(Grpc.Core.Channel));
var srcFolderPath = Path.GetDirectoryName(new Uri(grpcCoreAssembly.CodeBase).LocalPath);
CopyGrpcCSharpExtNativeDll(srcFolderPath);
}
public static void CopyGrpcCSharpExtNativeDll(string srcFolderPath)
{
var grpcCoreAssembly = Assembly.GetAssembly(typeof(Grpc.Core.Channel));
var grpcDllLocation = Path.GetDirectoryName(grpcCoreAssembly.Location);
if (grpcDllLocation == null)
return;
var targetFolderPath = Path.Combine(grpcDllLocation, "nativelibs");
if (Directory.Exists(targetFolderPath))
return;
srcFolderPath = Path.Combine(srcFolderPath, "nativelibs");
DirectoryCopy(srcFolderPath, targetFolderPath, true);
}
private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
{
if (string.IsNullOrEmpty(sourceDirName) || string.IsNullOrEmpty(destDirName))
{
throw new ArgumentNullException(
$"Directory paths cannot be empty. sourceDirName: {sourceDirName} | destDirName: {destDirName}");
}
var dir = new DirectoryInfo(sourceDirName);
if (!dir.Exists)
{
throw new DirectoryNotFoundException("Source directory does not exist or could not be found: " +
sourceDirName);
}
var dirs = dir.GetDirectories();
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
var files = dir.GetFiles();
foreach (var file in files)
{
string temppath = Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, false);
}
if (copySubDirs)
{
foreach (var subdir in dirs)
{
var temppath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, temppath, true);
}
}
}
}
I have a method whit the following logic:
I delete all files from input and output folders
user selects an initial picture
this pictures as being assigned to imageBox1
picture is being copied to the folder input
magic happens to picture and I put it to the folder output
new picture from output is beign assigned to imageBox2
Here is where problem starts. When users wants to repeat operation imagebox1 and imagebox2 do have pictures assigned to them. And the step #0 failswith error
The process cannot access the file '03933.tiff' because it is being used by another process.
What I was trying is :
private void CopyImage_Click(object sender, EventArgs e)
{
string currentPath = Directory.GetCurrentDirectory();
string pathInput = currentPath + "\\Input";
string pathOutput = currentPath + "\\Output";
if (pictureBoxInput.Image != null) {
pictureBoxInput.Image = null;
pictureBoxInput.Dispose();
}
if (pictureBoxOutput.Image != null) {
pictureBoxOutput.Image = null;
pictureBoxOutput.Dispose();
}
System.IO.DirectoryInfo di = new DirectoryInfo(pathInput + "\\");
foreach (FileInfo file in di.GetFiles())
{
file.Delete();
}
System.IO.DirectoryInfo dia = new DirectoryInfo(pathOutput + "\\");
foreach (FileInfo file in dia.GetFiles())
{
file.Delete();
}
But still having the same error when program tries to delete files.
I would suggest changing:
if (pictureBoxInput.Image != null) {
pictureBoxInput.Image = null;
pictureBoxInput.Dispose();
}
to:
if (pictureBoxInput.Image != null) {
var existingFile = pictureBoxInput.Image;
pictureBoxInput.Image = null;
existingFile?.Dispose();
}
and the same for pictureBoxOutput
The issue is that your existing code is disposing the wrong thing - you are disposing the PictureBox rather than the Image (and the Image is the thing that is holding the file lock).