What I want is typed access to the contents of a file within a VS.NET solution.
I think a custom tool with corresponding custom tool namespace would be the easiest to do (do correct me if there is a simpler way of accomplishing the same thing!)
This would generate code like so:
Namespace CustomToolNamespaceInPropertiesComesHere
Public Module SomeName
Public Function GetFile() As IO.Stream
Return System.Reflection.Assembly.GetExecutingAssembly() _
.GetManifestResourceStream("RootNamespace.FileName.xml")
End Function
End Module
End Namespace
Basically it creates typed access to a file (An XML file with Build Action: Embedded Resource) within the "Custom Tool Namespace" as specified in the properties of the file.
I do not want to use a ResX as I want each XML file to appear seperately in the solution and have the XMLEditor as default editor (So XSD validation can be added if time permits writing one).
Unfortunately little information can be found about these custom tool namespaces. Every example so far also seems to refer to BaseCodeGeneratorWithSite of which the original URL has gone dead.
I'm also asking this in hopes of someone providing something easier to use/implement rather than the overkill of a new custom tool...
Related
Scenario:
My company has a legacy (read that as 32 bit) windows form application that will be around for quite some time in the future. This application uses an embedded web browser control that is supplied pages that are contained within the database that it maintains. It was built like this so we could extend/modify as needed. I say this so that I can validate that security is not a concern. Only the application and developers with the correct tools have access to the pages or database. The application is only available inside the office.
There are some processes that I need to accomplish using ActiveX objects that are embedded within the pages/application. One of the biggest and most annoying thing that happens is the ActiveX security warning when I got to create instances of things like “scripting.filesystemobject”. Example:
Set oFSO = CreateObject("Scripting.FileSystemObject")
My solution is to create a DLL that is installed locally on each machine that needs access to the extended functions, have the all the functions (whole DLL ??) marked as safe so that the web browser control does not present the security warning. I have been searching using google and came across very few examples, and all of which are in C# which is not my strongest language.
I’ve had to convert from C to Vb.Net visual basic to get what I have now. When I go to register my DLL, I get the following error message:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319>regasm
Z:\VBNet2017\APIInternal\APIInternal\bin\Debug\APIinternal.dll /tlb
Microsoft .NET Framework Assembly Registration Utility version 4.8.4084.0
for Microsoft .NET Framework version 4.8.4084.0
Copyright (C) Microsoft Corporation. All rights reserved.
Types registered successfully
RegAsm : error RA0000 : Type 'APIInternal.API.Accupay' has an invalid default COM
interface: 'APIInternal.API.Accupay'
UPDATE: Thank you Hans; the error is gone. I've also made some changes in the source code; I changed the ProgID to something that closely resembles where and what this is for. I'm still having issues in creating the object in VB Script.
This is the output from the current version of the code. This is the code, stripped down for clarity:
Option Strict On
Imports System.Runtime.InteropServices
Imports System.IO
Namespace API
Public Interface IAccupay
<DispId(1)>
Function GetFiles(ByVal Folder As String) As List(Of String)
End Interface
<Guid("8B4B5CEF-8B3A-49A1-9053-E909F82D9E73"),
ProgId("AddIn.Accupay"), ClassInterface(ClassInterfaceType.None),
ComDefaultInterface(GetType(IAccupay)), ComVisible(True)>
Public Class Accupay
Implements IAccupay
Private Function GetFiles(Folder As String) As List(Of String) Implements IAccupay.GetFiles
Return Directory.GetFiles(Folder).ToList
End Function
End Class
I have tried just about every combination of ProgID, Name space, Interface name and class name to get this error to go away without any luck. I do know there are other elements that need to be addressed or added, such as error trapping and, if I’m not mistaken, how to actually implement the ObjectSafetyOption which I still don’t know how to do.
I have been using the Guide at the bottom of this article:
Is it possible to mark an ActiveX object as safe so that IE settings need not be changed?, the second answer, but I haven’t had any success.
Please, can someone point me in the right direction, maybe show me what’s wrong with the code that I have and how to physically implement the ObjectSafteyOption that is needed for the web control. Links, additional reading, code examples or comments on how to get this fixed and working would really be appreciated.
Thank you for reading and any help you send my way, Fred
PS: If you need more information, or have a better solution, please don’t hesitate to reply or comment.
UPDATE:
With the code that I have now, I am able to access the DLL in VB.Net visual basic:
Imports System
Imports APIInternal.API
Module Program
Sub Main(args As String())
Dim API As New Accupay
Dim FileList = API.GetFiles("C:\Windows\")
For Each Item As String In FileList
Console.WriteLine(Item)
Next
End Sub
End Module
However, I still can't seem to get the correct calling for a VB Script/html page:
Set Test = CreateObject("Test.Accupay")
Which returns the VB Script error "ActiveX Component can't create object: Test.Accupay or any other iteration of the parts of the name that I tried. I think part of this is that I don't understand how the creation of the project leads to the creation of the object in a com base environment like VB Script.
Fred
The answer to this problem is two fold: You must target the correct platform (X86) AND use the 32 bit version of regasm. Once I realized this was the issue, I was able to create the DLL and use it's functions in the Web Browser control without the active X warning. One example is I can now open the default browser (in this case, NOT IE/EDGE) from a link within the WB Control and another is to get the contents of a folder for further processing within the WB page.
If I have a class library with an app.config file (I know it's not ideal, just bear with me for a moment) which has settings values created by using the projects Settings tab and accessed like this:
Public Shared Function GetMySetting(key As String) As String
Dim value As String = My.Settings.Item(key)
If value = String.Empty Then value = "Setting " & key & " not found."
Return value
End Function
I then retrieve the settings from an application like this:
sb.AppendLine("GetMySetting: " & Library.Settings.GetMySetting("SettingC"))
The settings from the app.config file of the library project are definitely not copied into the app.config file of the application but I can still retrieve the My.Settings from the libraries app.config.
So I added a GetConfigFileName function to the library:
Public Shared Function GetConfigFileName() As String
Return AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
End Function
and retrieved it in the application:
sb.AppendLine("Library Config File: " & Library.Settings.GetConfigFileName)
but that returns the application's config file.
How can I determine which .config file the library is reading from when it calls My.Settings...?
Or are they compiled into the DLL?
but that returns the application's config file. How can I determine
which .config file the library is reading from when it calls
My.Settings...?
By default, it will be always the main.exe.config.
Take a look at this for detailed answer
C# DLL config file for
more informations
You can use external config files. This article on MSDN
explains how.
EDIT
You're misunderstanding the situation, reread this line: The settings
from the app.config file of the library project are definitely not
copied into the app.config file of the application but I can sti retrieve the My.Settings from the libraries app.config.
You are correct. Your settings in the dll.config will not be copied automatically in the app.config.
Concerning the value that you are able to get from your dll, I am still looking for more official answer, but the answer seems to be:
the 'old' values (the ones you define at development time) are hard coded. If the
franework isn't able to access or open the config file it will use the defaults
instead. This will always happen if you use settings in a dll.
Take a look at this Settings.Default.<property> always returns default value instead of value in persistant storage (XML file)
Edited after reading comments.
I think I see what your after. The My.Settings will used the compiled values from your class libs settings as default values. I believe these are compiled in. You can reflect the source though to see if it is setting a defaultvalue attribute on them.
You can override these by setting the values in the main exe's application file. If the settings aren't in the exes file, then you will use the default ones you specified in your class libs.
You shouldn't care about the file name. Just assume the settings are either defaulted or were overridden. If you need to know if they were overridden, that's another issue.
I have a PPC2003 project in VS2005. I have added a resource file (SomeResources.resx) to the project. I can access the test string I have in the file by using My.Resources.SomeResources.MyTestString (I am using the default Custom Tool Name that VS provides).
When the Build Action property of the is set to Embedded Resource, the application references the MyTestString successfully.
But I do not want to embed the file, so that it's string values can be modified after it has been deployed/installed.
I, therefore, changed the Build Action to Content, so that the file gets copied out to the device for potential future manipulation. When I call MyTestString I get the following error:
MissingManifestResourceException Stack Trace: at System.Resources.ResourceManager.InternalGetResourceSet() at System.Resources.ResourceManager.InternalGetResourceSet() at System.Resources.ResourceManager.InternalGetResourceSet() at System.Resources.ResourceManager.GetString() at MyApp.My.Resources.SomeResources.get_MyTestString() at MyApp.fMain.fMain_Load() at System.Windows.Forms.Form.OnLoad() at System.Windows.Forms.Form._SetVisibleNotify() at System.Windows.Forms.Control.set_Visible() at System.Windows.Forms.Application.Run() at MyApp.fMain.Main()
As the file is not embedded, do I maybe need to manually load it first? If so, how? Any other ideas? Is it not possible to do what I'm after achieving and should I just create my own XML file/reader?
Resources (resx files) are specifically designed to be compiled into the application. If you want it to be an editable content file on the target, then you have to approach it differently and use something like an XML file and wrap that with accessors (akin to the Configuration namespace stuff in the full framework).
For a Windows 8 application in C#/XAML I need to access a specific ressource file. In WP7 I used resx file and now it seems that we need to use resw file. It's not a language resource file.
My file is called ConfigResources.resw, it just contains one key : "ConfigFile" and a value : a string.
How can I access it from my code? I tried this without any luck:
var storedConfigFile = Application.Current.Resources["ConfigResources"];
Then how can I edit the value of the key inside from my code?
Thank you
I created a project on CodePlex recently called ResW File Code Generator that simplifies using localized resources in code in windows store app project. It's a custom tool that automatically generates and updates a helper class similar to what ResX files used in the full version of .NET
According to here, you need to use the Windows.ApplicationModel.Resources.ResourceLoader and the Windows.ApplicationModel.Resources.Core namespace provide interaction with resw files.
It should look something like this:
var loader = new Windows.ApplicationModel.Resources.ResourceLoader();
var text = loader.GetString("Farewell");
Alternately, if you're creating a cross-platform library you could also do it using the System.Resources.ResourceManager:
Although the System.Resources.ResourceManager class is included in the
.NET for Windows Store apps, we do not recommend its use. Use
ResourceManager only in libraries that are developed as Portable Class
Library projects and that target multiple platforms.
Like this from here:
ResourceManager rm = new ResourceManager("Strings", typeof(Example).Assembly);
string timeString = rm.GetString("TimeHeader");
There is a sample that shows the different ways to read the resources in WinRT apps (i.e. from resw files).
my solution has multiple projects and in one of them I have the code to get the embedded resource (an xml file) from another project. All this works fine when all the projects are seperate. However when all the class libraries are embedded into a single dll, the code to get the resource file does not work i.e. it cannot get the emebedded resource.
I was wondering if the references to the emebedded resource get mixed up when they are combined together in a single dll??
I use the method Assembly.GetCallingAssembly().GetManifestResourceStream("namespace..filename");
I would not use Assembly.GetCallingAssembly(). I would use typeof(SomeClassNextToXmlFile).Assembly that way if you are calling the dll with the embedded resource from a exe file it won't go looking in the exe for the resource. Also you may want to try using Reflector and make sure the resource you are looking for is where you think it is.