I have some directories that are bundled with my installer and I need to access them from within a custom action. I have done some research and seen that the SourceDir can be used to obtain the currently executing dir location. However I cannot find any examples of how to obtain this property? Or another way to obtain the current directory?
Can anyone advise or point me to anything other than the unhelpful Microsoft site?
I'm assuming you're using vbscript for the custom action. If so, properties can be accessed via the Session object. See below:
strSourceDir = Session.Property("SourceDir")
Be aware that the SourceDir property is only available at specific times during the installation.
For C#, you'll find that you can do something like this:
[CustomAction]
public static ActionResult MyCustomAction(Session session)
{
string sourceDir = session["SourceDir"];
string path = Path.Combine(sourceDir, "yourfilename.txt");
...
The documentation on MSDN is unfortunately lacking in making this clear.
As w4g3n3r mentions in his answer, SourceDir is only available to you at certain times. In short, you will need to make sure your custom action is called after a call to the ResolveSource action, which can only be called after CostInitialize has run.
Once SourceDir is set, it should be available for use for the remainder of the installation process.
Are you using InstallShield? Here's an example for an InstallScript CA:
MsiGetProperty(hMSI, "CustomActionData", strDirectory, numBuffer);
... where you also used a Set Property "Type 51" custom action to setup CustomActionData for your function to the value SOURCEDIR.
Related
I'm usually a javascript developer, but for my company I just started learning c# in order to use the CimatronE 13 API to develop custom command line PDM tools for this 3D modelling software.
As I'm making progress understanding the programming language, there's this frustrating situation where I want to use an API endpoint method but I can't manage to get it working.
The Cimatron documentation says the following:
IPdm::GetRelatedDocuments
Syntax: RelatedDocuments = GetRelatedDocuments ( DocumentPath );
This method allows you to get related files from compound types of files, for example Assembly or Drawing.
Input: (String) DocumentPath,
Path to file. For example \Documents\Location\Folder\Document. The file must be Assembly or Drawing.
Return: (Variant) RelatedDocuments,
Variant type array each element of which contain two dimensioned string type array of files related to selected one.
This looks pretty straight forward to me, so I tried calling it in multiple ways from within the static void Main() method, but I keep getting errors:
var RelatedDocuments = interop.CimBaseAPI.IPdm.GetRelatedDocuments("path");
CS0120: An object reference is required for the non-static field, method, or property 'IPdm.GetRelatedDocuments(string)'
interop.CimBaseAPI.IPdm pdm = new interop.CimBaseAPI.IPdm();
var RelatedDocuments = pdm.GetRelatedDocuments("path");
CS0144: Cannot create an instance of the abstract class or interface 'IPdm'
Any ideas? It's probably simple but I'm still a noob with c# :p
EDIT:
Cimatron documentation about the interface interop.CimBaseAPI.IPdm:
Properties:
Get
Query (String, DocumentEnumType, DocumentEnumUnit )
Variant
Methods:
A lot, including Variant GetRelatedDocuments ( String )
As how I see it now... interop.CimatronE.IPdm is an interface and in order to use it's methods, we first need access to the Cimatron application. Using the application object, we can use it's methods to get the desired interfaces such as IPdm and use their methods.
The following code gives no errors from the compiler but does when executing. This seems to be related to version 13 of CimatronE, since the application object works just fine using version 12. A lot has changed between these versions which I think is the reason the API is not functioning properly, outdated.
interop.CimAppAccess.AppAccess AppAcc = new interop.CimAppAccess.AppAccess();
interop.CimatronE.IApplication CimApp = /*(interop.CimatronE.IApplication)*/AppAcc.GetApplication();
interop.CimatronE.IPdm pdm = CimApp.GetPdm();
var RelatedDocuments = pdm.GetRelatedDocuments("path");
Console.WriteLine(RelatedDocuments);
Please correct me if I'm wrong! (since I just started and still learning c#)
I ran into this same issue with Cimatron 14.
I needed to make some changes in Visual Studio for things run properly with Cimatron.
Run Visual Studio in administrator mode
Set your Debug & Release Solution Platform to 'x64'
It was also recommended to point the build path for release & debug to the same folder as the Cimatron references. In my case 'C:\Program Files\3D Systems\Cimatron\14.0\Program'. However my code appears to run fine without this.
I created the Cimatron Application with this code (VB.Net):
Dim gAppAccess As New CIMAPPACCESSLib.AppAccess 'Define an AppAccess object to get running active application
Dim gApp As CIMAPPACCESSLib.Application 'Define an Application object
gApp = gAppAccess.GetApplication 'Getting running active application
If gApp Is Nothing Then
gApp = New CIMAPPACCESSLib.Application 'Creating a new instance of a Cimatron application
End If
References: Interop.CIMAPPACCESSLib.dll & interop.CimServicesAPI.dll
It is my understanding that Cimatron 15 may also requires some manifest changes.
There is some help information in the Cimatron program under Cimatrom Modules > Cimaton SDK that may be mildly helpful.
I'm using the roslyn API to write a DiagnosticAnalyzer and CodeFix.
After I have collected all strings and string-interpolations, I want to write all of them to a file but I am not sure how to do this the best way.
Of course I can always simply do a File.WriteAllText(...) but I'd like to expose more control to the user.
I'm also not sure about how to best trigger the generation of this file, so my questions are:
I do not want to hard-code the filename, what would be the best way to expose this setting to the user of the code-analyzer? A config file? If so, how would I access that? ie: How do I know the directory?
If one string is missing from the file, I'd like to to suggest a code fix like "Project contains changed or new strings, regenerate string file". Is this the best way to do this? Or is it possible to add a button or something to visual studio?
I'm calling the devenv.com executable from the commandline to trigger builds, is there a way to force my code-fix to run either while building, or before/after? Or would I have to "manually" load the solution with roslyn and execute my codefix?
I've just completed a project on this. There are a few things that you will need to do / know.
You will probably need to switch you're portable class library to a class library. otherwise you will have trouble calling the File.WriteAllText()
You can see how to Convert a portable class library to a regular here
This will potentially not appropriately work for when trying to apply all changes to document/project/solution. When Calling from a document/project/solution, the changes are precalcuated and applied in a preview window. If you cancel, an undo action is triggered to undo all changes, if you write to a file during this time, and do not register an undo action you will not undo the changes to the file.
I've opened a bug with roslyn but you can handle instances by override the preview you can see how to do so here
And one more final thing you may need to know is how to access the Solution from the analyzer which, Currently there is a hack I've written to do so here
As Tamas said you can use additional files you can see how to do so here
You can use additional files, but I know on the version I'm using resource files, are not marked as additional files by default they are embeddedResources.
So, for my users to not have to manually mark the resource as additonalFiles I wrote a function to get out the Designer.cs files associated with resource files from the csproj file using xDoc you can use it as an example if you choose to parse the csproj file:
protected List<string> GetEmbeddedResourceResxDocumentPaths(Project project)
{
XDocument xmldoc = XDocument.Load(project.FilePath);
XNamespace msbuild = "http://schemas.microsoft.com/developer/msbuild/2003";
var resxFiles = new List<string>();
foreach (var resource in xmldoc.Descendants(msbuild + "EmbeddedResource"))
{
string includePath = resource.Attribute("Include").Value;
var includeExtension = Path.GetExtension(includePath);
if (0 == string.Compare(includeExtension, RESX_FILE_EXTENSION, StringComparison.OrdinalIgnoreCase))
{
var outputTag = resource.Elements(msbuild + LAST_GENERATED_TAG).FirstOrDefault();
if (null != outputTag)
{
resxFiles.Add(outputTag.Value);
}
}
}
return resxFiles;
}
For config files you can use the AdditionalFiles msbuild property, which is passed to the analyzers through the context. See here.
I have a database that could be stored in different places depending on the platform. For example, for Xamarin.Mac, the database is stored in #executable_path/../Resources/my.db. Right now the ViewModel handles initializing the database, and I'm happy to leave it there. However, I need to pass it a path and all I see is
var startup = Mvx.Resolve<IMvxAppStart>();
startup.Start ();
in the AppDelegate. In Mvx I have been using RegisterSingleton and Resolve, but I'm not sure I should be using that for a simple string (should I have IMyDbPath and MyDbPath interface and class?) Looking for an elegant solution. Thanks!
If you're using the MvvmCross-SQLite-Net plugin. Once it's registered, either manually or by the Bootstrap there will be two interfaces you can resolve:
ISQLiteConnectionFactory or ISQLiteConnectionFactoryEx
When you resolve ISQLiteConnectionFactory you'll be able to call Create(string address) passing the path to your database. The path you give Create is not platform specific, meaning, Create will figure out the platform specific base path for you.
private ISQLiteConnection CreateFileDb(SQLiteConnectionOptions options)
{
if (string.IsNullOrWhiteSpace(options.Address))
throw new ArgumentException(Properties.Resources.CreateFileDbInvalidAddress);
var path = options.BasePath ?? GetDefaultBasePath();
string filePath = LocalPathCombine(path, options.Address);
return CreateSQLiteConnection(filePath, options.StoreDateTimeAsTicks);
}
So you could pass MyDatabase.db or data/MyDatabase.db on the supported platforms and it should resolve the base path for you.
I am using the following code within a class:
string filePath = HttpContext.Current.Server.MapPath("~/email/teste.html");
The file teste.html is in the folder
But when it will open the file the following error is being generated:
Object reference not set to an instance of an object.
Don't use Server.MapPath. It's slow. Use this instead, HttpRuntime.AppDomainAppPath. As long as your web site is running, this property is always available to you.
Then use it like this:
string filePath = Path.Combine(HttpRuntime.AppDomainAppPath, "email/teste.html");
if the code is not running from within a thread is executing a httprequest then HttpContext.Current is null (for example when you method is called via BeginInvoke) - see http://forums.asp.net/t/1131004.aspx/1 .
You can always use HttpRuntime see http://msdn.microsoft.com/en-us/library/system.web.httpruntime.aspx
If there is no HttpContext (e.g. when the method is called via BeginInvoke, as Yahia pointed out), the call to HttpContext.Current.Server.MapPath() must fail. For those scenarios, there's HostingEnvironment.MapPath() in the System.Web.Hosting namespace.
string filePath = HostingEnvironment.MapPath("~/email/teste.html");
You can use something like the following piece of code. One thing to note is that I was facing an issue, where I was trying to access a .txt file from within a TestMethod and everything was failing except for this...and yeah it works for non-Unit Test Scenarios too.
string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,#"..\..") + "\\email\\teste.html";
Issue: I had an "Images" folder inside a class library project. But using the above answers, I was not able to get the physical path of the folder to read/write the files inside that folder.
Solution: The below code worked for me to get a physical path in the class library project.
string physicalPath = System.IO.Path.GetFullPath("..\\..\\Images");
I hope, it will help someone who is facing the same issue as me.
I am trying to access my local resources file in my code-behind. I did some googling since I was unsure of how to do it and found this:
oContent.Text = HttpContext.GetLocalResourceObject("NonSupport").ToString();
However, I get an error saying that it needs at least two parameters: VirtualPath and ResourceKey. There is a third, CultureInfo but that one is optional. When I put this in as my virtual path:
HttpContext.GetLocalResourceObject("App_LocalResources/ExpandableListView.aspx.resx", "NonSupport").ToString();
I get the following compiler error message:
The relative virtual path 'App_LocalResources/ExpandableListView.aspx.resx' is not allowed here.
I must be doing something wrong with this since my searches (and some posts I found on here) say all I need to do is call the resource key.
Any thoughts? Thanks!
Did you put a resource file with the name (your aspx web page).aspx.resx into a App_LocalResource folder underneath the path where your ASPX page lives??
Furthermore, just simply call the GetLocalResourceObject method on your current page:
oContent.Text = GetLocalResourceObject("NonSupport").ToString();
No need to use HttpContext for that - the method is defined on the Page class.
Marc