I've created a connection using Microsoft Office 12.0 Access Database Engine OLE DB Provider as Excel Schema to loop through all the sheets in the Excel file as demonstrated in this question How to loop through Excel files and load them into a database using SSIS package?
And using Foreach ADO.NET Schema Rowset Enumerator to loop through the excel files.
Everything is working fine now, but after importing the data from Excel, I wanted to move that file to Archive folder. And tried using a File System Task, but I get the error as
[File System Task] Error: An error occurred with the following error message: "The process cannot access the file because it is being used by another process.".
And I also tried with script task from this link. But I was getting some error and couldn't solve the error as I've got zero knowledge on C#.
Below is the error I've got when I tried to move the files using a script task.
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
at Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTATaskScriptingEngine.ExecuteScript().
Update:
Here's my complete code with which I'm trying to move the files.
If I add a breakpoint at enum ScriptResults, I don't get that popup and the task gets completed successfully and the file is also been moved to archive, but if I don't add any breakpoint in the C# code, I get that pop and the file is not moved to archive.
#region Namespaces
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.IO;
#endregion
namespace ST_9fc6ad7db45c4a7bb49f303680f789ef
{
[Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
public void Main()
{
DirectoryInfo di = new DirectoryInfo(Dts.Variables["SplitSkill_FolderPath"].Value.ToString());
FileInfo[] fi = di.GetFiles("*.xlsx");
String filename = fi[0].Name;
string sourceFileName = filename;
string destinationFile = #"D:\Flipkart\Data\Split Skill\Archive\" + sourceFileName;
string sourceFile = #"D:\Flipkart\Data\Split Skill\" + sourceFileName;
if (File.Exists(destinationFile))
File.Delete(destinationFile);
// To move a file or folder to a new location:
System.IO.File.Move(sourceFile, destinationFile);
Dts.TaskResult = (int)ScriptResults.Success;
}
#region ScriptResults declaration
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
#endregion
}
}
As far as I understand, I think you have a task for looping through sheets and another for looping through files. So you probably have 2 tasks inside a foreach loop. Try making a copy of the file inside the foreach loop with a system task
for the executable
c:\windows\system32\cmd.exe
and for the arguments soemthing like
C COPY "C:\xxx\abc\\Destination_template.accdb" "C:\xxx\abc\\Destination_template.accdb"Destination_template - Kopie.accdb"
Then create a file system task which moves that copy to your archive.
This should do the trick (Maybe not the best approach but should work)
Related
I am trying to figure out on how to assign icon to a script file that just got created in Unity, but with no success so far.
I created this EditorWindow class that allows me to create a new c# class with some custom template.
After I created the file I save the asset like this
AssetDatabase.ImportAsset(filePath, ImportAssetOptions.ForceUpdate);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
After the script is created I want to also assign the custom icon automatically. Something like if you create a script named GameManager, unity automatically assigns custom icon for that script file.
I created AssetPostprocessor class that checks if the new asset is created under a specific path change the icon for that file.
The problem is that when I tried to test this Unity crashed for me. So I am running out of ideas a bit..
using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
public class Script_Importer : AssetPostprocessor
{
void OnPreprocessAsset()
{
if (assetPath.Contains("Scripts/CustomScripts/"))
{
AssetImporter asset = (AssetImporter)assetImporter;
var obj = AssetImporter.GetAtPath(assetPath) as UnityEngine.Object;
AssignLabel(obj);
}
}
void AssignLabel(UnityEngine.Object obj)
{
Texture2D tex = EditorGUIUtility.IconContent("Script_Icon").image as Texture2D;
Type editorGUIUtilityType = typeof(EditorGUIUtility);
BindingFlags bindingFlags = BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.NonPublic;
object[] args = new object[] { obj, tex };
editorGUIUtilityType.InvokeMember("SetIconForObject", bindingFlags, null, null, args);
}
}
In F# it's rather easy with predefined identifier __SOURCE_DIRECTORY__
https://stackoverflow.com/a/4861029/2583080
However this identifier does not work in C# scripting (csx files or C# Interactive).
> __SOURCE_DIRECTORY__
(1,1): error CS0103: The name '__SOURCE_DIRECTORY__' does not exist in the current context
Getting current directory in more traditional way will not work either.
Directory.GetCurrentDirectory()
Returns: C:\Users\$USER_NAME$\
new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath;
Returns: C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\CommonExtensions\Microsoft\ManagedLanguages\VBCSharp\InteractiveComponents\
In C# you can take advantage of caller information attributes (available since C# 5 / VS2012). Just declare a method like this:
string GetCurrentFileName([System.Runtime.CompilerServices.CallerFilePath] string fileName = null)
{
return fileName;
}
And call it without specifying the optional parameter:
string scriptPath = GetCurrentFileName(); // /path/to/your/script.csx
In csx, you are can add ExecutionContext as a parameter and access FunctionDirectory from it like so:
using System;
using Microsoft.Azure.WebJobs;
public static void Run(TimerInfo myTimer, ExecutionContext executionContext, ILogger log) {
var dir = executionContext.FunctionDirectory;
log.LogInformation($"Directory: {dir}");
}
ExecutionContext.FunctionDirectory will return the directory the contains the function's function.json file. It doesn't include the trailing .
At this time this seems to be the best documentation for ExecutionContext.
I am trying to find the answer to this question myself, and this was my previous answer.
In csx, the following helper method will return the directory "of the source file that contains the caller".
using System.IO;
...
public static string CallerDirectory([System.Runtime.CompilerServices.CallerFilePath] string fileName = null)
{
return Path.GetDirectoryName(fileName);
}
To call it, don't specify the fileName parameter.
var dir = CallerDirectory();
I have a project where I compile a lot of files in memory using Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider
My problem happened when I started to try to use wpf windows.
I am able to get the in-memory assembly to compile, but when I go to bring up the window I get:
System.Exception: The component 'Dynamic.DragonListForm' does not have
a resource identified by the URI
'/ScriptCode;component/wpf_ui/dragonlistform.xaml'.
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
NOTE: I compile by adding a list of all the .cs files in a particular folder
objCompileResults = objCodeCompiler.CompileAssemblyFromFile( objCompilerParameters, files.ToArray() );
I also add dll references needed to make it work.
NOTE: Thanks to Reed, I was able to get it working well enough for my needs by doing:
List<string> bamlFiles = Directory.GetFiles( directoryPath, "*.baml", SearchOption.AllDirectories ).ToList();
bamlFiles.ForEach( x => objCompilerParameters.EmbeddedResources.Add( x ) );
In my project this is good enough. I have a .NET app that I use for executing voice commands. In general, I have it so I can recompile assembly changes in memory as I change voice commands. I imagine some of this won't work with WPF but I am now able to use WPF windows in my in-memory assembly.
The problem is that WPF files aren't just C#, they're also the XAML, which then gets compiled in a separate MSBuild task into BAML resources and included as embedded resources.
If you wanted to support some version of this, you'd need to include all of the referenced xaml as resources. See this post for details on how to do that using CodeDom.
Once that was done, you'd have to also make sure that you're using a compatible mechanism for loading the types. The "normal" way C# compiles xaml/xaml.cs files won't work in your situation, as it requires the resources to be precompiled to baml. You'd have to effectively "rewrite" the code behind for the C# types to use a different mechanism of loading the XAML - typically this would be done by using XamlObjectReader and XamlObjectWriter to read the xaml contents and "write them" into the object during the InitializeComponent pass.
Another very helpful piece of information is given at: The component does not have a resource identified by the uri
From that I created an extension method that can be called like this:
// https://stackoverflow.com/questions/7646331/the-component-does-not-have-a-resource-identified-by-the-uri
this.LoadViewFromUri( #"/ScriptCode;component/wpf_ui/spywindowviewer.xaml" );
// InitializeComponent();
NOTE: I just use the uri that shows up in the error message, for example:
The component 'Dynamic.DragonListForm' does not have a resource identified by the URI '/ScriptCode;component/wpf_ui/dragonlistform.xaml'. at
The extension method:
using System;
using System.IO.Packaging;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Navigation;
namespace Extensions
{
public static class WpfWindowExtensions
{
// https://stackoverflow.com/questions/7646331/the-component-does-not-have-a-resource-identified-by-the-uri
public static void LoadViewFromUri( this Window window, string baseUri )
{
try
{
var resourceLocater = new Uri( baseUri, UriKind.Relative );
// log.Info( "Resource locator is: ")
var exprCa = ( PackagePart )typeof( Application ).GetMethod( "GetResourceOrContentPart", BindingFlags.NonPublic | BindingFlags.Static ).Invoke( null, new object[] { resourceLocater } );
var stream = exprCa.GetStream();
var uri = new Uri( ( Uri )typeof( BaseUriHelper ).GetProperty( "PackAppBaseUri", BindingFlags.Static | BindingFlags.NonPublic ).GetValue( null, null ), resourceLocater );
var parserContext = new ParserContext
{
BaseUri = uri
};
typeof( XamlReader ).GetMethod( "LoadBaml", BindingFlags.NonPublic | BindingFlags.Static ).Invoke( null, new object[] { stream, parserContext, window, true } );
}
catch( Exception )
{
//log
}
}
}
}
To start with, I am new to WixSharp. For several hours now I have been trying to specify a custom file, License.rtf, for my setup project like this:
project.LicenceFile = "License.rtf";
But I keep getting this error:
C# Script execution engine. Version 3.9.4.1.
Copyright (C) 2004-2014 Oleg Shilo.
Error: Specified file could not be executed.
System.Xml.XmlException: The prefix '' cannot be redefined from 'http://schemas. microsoft.com/wix/2006/wi' to '' within the same start element tag.
at System.Xml.XmlWellFormedWriter.PushNamespaceExplicit(String prefix, String ns)
at System.Xml.XmlWellFormedWriter.WriteEndAttribute()
at System.Xml.Linq.ElementWriter.WriteStartElement(XElement e)
at System.Xml.Linq.ElementWriter.WriteElement(XElement e)
at System.Xml.Linq.XElement.WriteTo(XmlWriter writer)
at System.Xml.Linq.XContainer.WriteContentTo(XmlWriter writer)
at System.Xml.Linq.XDocument.WriteTo(XmlWriter writer)
at System.Xml.Linq.XDocument.Save(TextWriter textWriter, SaveOptions options)
at WixSharp.Compiler.BuildWxs(Project project, String path, OutputType type)
at WixSharp.Compiler.BuildWxs(Project project, OutputType type)
at WixSharp.Compiler.Build(Project project, String path, OutputType type)
at WixSharp.Compiler.Build(Project project, OutputType type)
at Script.Main(String[] args)
Please can someone tell me what I am doing wrong. Here is my setup.cs code:
//css_dir ..\..\;
//css_ref Wix_bin\SDK\Microsoft.Deployment.WindowsInstaller.dll;
//css_ref System.Core.dll;
using System;
using System.Xml;
using System.Xml.Linq;
using System.Linq;
using System.Windows.Forms;
using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Win32;
using WixSharp;
using WixSharp.CommonTasks;
class Script
{
static public void Main(string[] args)
{
var project =
new Project("myproduct",
new Dir(#"%ProgramFiles%\My Company\myproduct", new DirFiles(#"Files\*.*"),
new Dir("DataModel", new DirFiles(#"Files\Data\*.*"),new Dir("Music", new DirFiles(#"Files\Data\Music\*.*")),new Dir("CardPack", new DirFiles(#"Files\Data\CardPack\*.*")),new Dir("CardSingle", new DirFiles(#"Files\Data\CardSingle\*.*"))),
new ExeFileShortcut("Uninstall MyProduct", "[System64Folder]msiexec.exe", "/x [ProductCode]")),
new Dir(#"%AppDataFolder%\myproduct", new File(#"Files\Config\Configure.json"), new Dir("Folder1", new DirFiles(#"Files\Folder2\*.*"))));
project.LicenceFile = "License.rtf";
project.UI = WUI.WixUI_Minimal;
project.GUID = new Guid();
project.ResolveWildCards();
var exeFile = project.AllFiles.Single(f=>f.Name.EndsWith("myproduct.exe"));
exeFile.Shortcuts = new[] {
new FileShortcut("myproduct.exe", "INSTALLDIR"),
new FileShortcut("myproduct.exe", #"%Desktop%")
};
Compiler.BuildMsi(project);
}
}
Thanks in advance.
Not sure if you found an answer to your question, but Orca is an MSI Table editor that is included in the Windows SDK.
For Windows 7 and .NET 3.5 SP1 - https://www.microsoft.com/en-us/download/confirmation.aspx?id=3138
Once installed, navigate to C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin
and execute the orca.msi. You will then run your Wix# project to generate the msi file. Open the msi file with Orca and navigate to the Binary table. Double click on the data column for WixSharp_LicenseFile and you will be given an option to read or write to a file. If you want to see the contents, select a file name (.rtf format) and write to file. Make any changes you wish, or replace that file, and then use it to read into that binary data row. Once you have read it into the msi table, save the msi file and close.
I am new to WixSharp myself, so I have not found another way (yet!), but this worked for me.
Good luck!
I have a dotnet script which is for encryption and decryption. I have to pass the parameters for the setvalues function in installshield. How can I achieve this? Dotnet code is as follows. I have the assembly (.dll) file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Security;
using System.Xml;
using System.Collections.Specialized;
namespace EncryptionDecryption
{
public class EncrptionHelper
{
#region Member variables
static byte[] entropy = { 0, 8, 2, 3, 5 };
#endregion
#region Public Methods
public static void SetValue(string configFilePathName, string appSettingKey, string appSettingValue)
{
appSettingValue = EncryptString(ToSecureString(appSettingValue));
SetSetting(appSettingKey, appSettingValue, configFilePathName);
}
public static string GetValue(string configFilePathName, string appSettingKey)
{
string value = GetSetting(appSettingKey, configFilePathName);
value = ToInsecureString( DecryptString(value));
return value;
}
#endregion
#region Private Methods
private static bool SetSetting(string Key, string Value, string configFilePath)
{
bool result = false;
try
{
// System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(configFilePath);
// config.AppSettings.File = configFilePath;
// config.AppSettings.Settings[Key].Value = Value;
// config.Save(ConfigurationSaveMode.Modified);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(configFilePath);
xmlDoc.SelectSingleNode("//appSettings/add[#key='" + Key +"']").Attributes["value"].Value = Value;
xmlDoc.Save(configFilePath);
ConfigurationManager.RefreshSection("appSettings");
result = true;
}
finally
{ }
return result;
}
private static string GetSetting(string Key, string configFilePath)
{
string result = null;
try
{
XmlDocument appSettingsDoc = new XmlDocument();
appSettingsDoc.Load(configFilePath);
XmlNode node = appSettingsDoc.SelectSingleNode("//appSettings");
XmlElement value = (XmlElement)node.SelectSingleNode(string.Format("//add[#key='" + Key + "']"));
result = (value.GetAttribute("value").ToString());
}
finally
{ }
return result;
}
private static SecureString ToSecureString(string input)
{
SecureString secure = new SecureString();
foreach (char c in input)
{
secure.AppendChar(c);
}
secure.MakeReadOnly();
return secure;
}
private static string ToInsecureString(SecureString input)
{
string returnValue = string.Empty;
IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(input);
try
{
returnValue = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr);
}
finally
{
System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
}
return returnValue;
}
private static string EncryptString(System.Security.SecureString input)
{
byte[] encryptedData = System.Security.Cryptography.ProtectedData.Protect(
System.Text.Encoding.Unicode.GetBytes(ToInsecureString(input)), entropy, System.Security.Cryptography.DataProtectionScope.CurrentUser);
return Convert.ToBase64String(encryptedData);
}
private static SecureString DecryptString(string encryptedData)
{
try
{
byte[] decryptedData = System.Security.Cryptography.ProtectedData.Unprotect(
Convert.FromBase64String(encryptedData),
entropy,
System.Security.Cryptography.DataProtectionScope.CurrentUser);
return ToSecureString(System.Text.Encoding.Unicode.GetString(decryptedData));
}
catch
{
return new SecureString();
}
}
#endregion
}
}
Update: Action start 14:31:36: Encryption.
MSI (c) (84:40) [14:31:36:525]: Invoking remote custom action. DLL: C:\Users\<username>\AppData\Local\Temp\MSIE259.tmp, Entrypoint: m1
InstallShield: Attempting to load through CLR 4 APIs...
InstallShield: Getting meta host...
InstallShield: Enumerating available runtimes...
InstallShield: Highest available runtime: v4.0.30319
InstallShield: Trying to use highest runtime...
InstallShield: Using highest version runtime...
InstallShield: Loading assembly Security.Encryption from resource 4097
InstallShield: Calling method with parameters [(System.String)C:\Program Files (x86)\<Installdir>\<configfilename>.config, (System.String)VWFPassword, (System.String)]
InstallShield: Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Program Files (x86)\<Installdir>\<configfilename>.config'.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize)
at System.Xml.XmlDownloadManager.GetStream(Uri uri, ICredentials credentials, IWebProxy proxy, RequestCachePolicy cachePolicy)
at System.Xml.XmlUrlResolver.GetEntity(Uri absoluteUri, String role, Type ofObjectToReturn)
at System.Xml.XmlTextReaderImpl.OpenUrlDelegate(Object xmlResolver)
at System.Threading.CompressedStack.runTryCode(Object userData)
at
System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.CompressedStack.Run(CompressedStack compressedStack, ContextCallback callback, Object state)
at System.Xml.XmlTextReaderImpl.OpenUrl()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)
at System.Xml.XmlDocument.Load(XmlReader reader)
at System.Xml.XmlDocument.Load(String filename)
at Security.Encryption.EncrptionHelper.SetSetting(String appSettingKey, String appsettingValue, String configFilePathName)
at Security.Encryption.EncrptionHelper.SetValue(String configFilePathName, String appSettingKey, String appSettingValue)
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
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 InstallShield.ClrHelper.CustomActionHelper.CallMethod(EntryPointInfo info)
at InstallShield.ClrHelper.CustomActionHelper.RunAction(UInt32 installHandle, Int32 entryNumber, Int64 instanceHandle)
InstallShield: Managed code threw an unhandled exception.
This is the error I receive after doing all that is mentioned in the screenshots below and doing some R&D. The directory mentioned "C:\Program Files (x86)\\.config" exists when the encryption custiom action is being called but it throws an exception.
Yes, it can be done with following steps:
1- write your required functionality in c# installer class (make sure your are using installer class)
2- Compile and add your dll into installshield (recomended create a separate component for this dll)
3- Select component view -> select above component and go to .Net settings section, set the ".Net Installer class" to true. Set the ".net installer class parameters"
Parameters are passed as key/value pair e.g
/targetDirectory="[INSTALLDIR]\"
All steps are same, just added screenshots.
Create a dll with an installer class and your encrypt/decrypt class.
Add dll and config file to component(above mentioned), if config file is already added to some other component then its fine. no need to add again.
I have added and retrieved INSTALLDIR variable as argument which is predefined. if you want to receive some input from user (from some custom textboxes) then you will need to define your own variables to store and pass values as arguments.
Creating dll with installer class and your requred logic for other task
Creating component and adding files
Mark the dll as installer class and pass arguments
Here goes installer class:
using System;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.ComponentModel;
using System.Configuration.Install;
using System.Collections.Generic;
namespace EncryptionDecryption
{
[RunInstaller(true)]
public class InstallerClassDemo : Installer
{
private string installationDirectory=string.Empty;
private string testString=string.Empty ;
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
try
{
//For testing purpose only.. work only in debug mode when pdb files are deployed as well.
//Debugger.Break();
installationDirectory = Context.Parameters["INSTALLDIR"];
//I believe, the config file must be located in the installation directory if so, then use the following way to compute path
string configFilePath = Path.Combine(installationDirectory, "myConfigFile.config");
EncrptionHelper.SetValue(configFilePath, "testKey", "testValue");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
protected override void OnCommitted(System.Collections.IDictionary savedState)
{
base.OnCommitted(savedState);
}
public override void Uninstall(System.Collections.IDictionary savedState)
{
base.Uninstall(savedState);
}
}
}
I think installshield cannot (or need extra work) for read your assemblies, but you can run simple console application which consume your assemblies from installscript and passing parameter from installshield.
Create simple console application
Include console application on Support Files
Copy to installation folder or assemblies location, so console application can access your assemblies
Launch from installscript using launchappandwait
If consoleapp.exe not use anymore, just delete it.