T4 referenced assembly blocks build - t4

In Visual Studio 2010 I have the following project layout:
Solution
project A
class C
class D
project B
T4 template
The T4 template contains a assembly reference like this:
<## assembly name="$(SolutionDir)\A\bin\Debug\A.dll" #>
The template instantiates an instance of class C. When I run the T4 template the processor loads the project A's dll and correctly creates the output. The error arises when I want to change something in project A, say modify either class C or D.
Unable to copy file "obj\Debug\A.dll"
to "bin\Debug\A.dll". The process
cannot access the file
'bin\Debug\A.dll' because it is being
used by another process.
The only way I found to get rid of this error is to restart Visual Studio. Is there any other way to force the unloading of the A.dll assembly from VS?

Im using VS2010 SP1 and was still getting blocked during build after first build when running a custom T4 template during the POST-BUILD events which accessed instances of classes of the same project.
How I got it to work was to use Reflection to access classes from the Project dll.
I still got the blocking issue when loading the dll directly from the file.
NOTE: The trick was to load the .dll into memory as a byte array and then load the assembly from the raw byte array. DONT load from the file using the Assembly.LoadFrom
This code is from my T4 template file and is accessing a static class "Information" and calling a static Method "Version" to return a string value.
string assemblyPath = Path.Combine(projectPath, #"bin\SampleProject.dll");
byte[] data;
using (var fs = File.OpenRead(assemblyPath))
{
data = new byte[fs.Length];
fs.Read(data, 0, Convert.ToInt32(fs.Length));
}
if (data == null || data.Length == 0)
{
throw new ApplicationException("Failed to load " + assemblyPath);
}
var asm = Assembly.Load(data);
appVersion = (string) asm.GetType("SampleProject.Information").GetField("Version").GetValue(null);

m0sa
This issue has been fixed in Visual Studio 2010 SP1.
If you're not able to use that, there is a VolatileAssembly directive add-on in the T4 Toolbox project on CodeBox (http://t4toolbox.codeplex.com/)

Related

C++ Windows Forms application icon exception

I want to set an icon for my Windows Form application. My actions step by step:
I created an 'icon.ico' (256x256) and put it into my project folder
In my 'Form1.h [Design]' I chose this file using Properties
This code appeared in 'Form1.h'
void InitializeComponent(void)
{ ...
this->Icon = (cli::safe_cast<System::Drawing::Icon^>(resources->GetObject(L"$this.Icon")));
... }
The object '$this.Icon' appeared in 'Form1.resx'
I rebuilt the whole project -> no errors
During execution the line 'this->Icon = ...' causes an exception: System.Resources.MissingManifestResourceException: 'Could not find any resources appropriate for the specified culture or the neutral culture. Make sure "WinForm.Form1.resources" was correctly embedded or linked into assembly "MyProject" at compile time, or that all the satellite assemblies required are loadable and fully signed.'
Here I found numerous advices, such as remove/add icon or set some custom properties for 'Form1.resx', but none of them works for me
Just like above, change line to:
this->Icon = gcnew System::Drawing::Icon(L"ICON_NAME.ico");
You might get error/exception while opening form creator but you shouldn't lose any data.
Been there, done that :)
Place the Icon you want to connect to your Form in the project directory.
Then replace the line above with the following:
this->Icon = gcnew System::Drawing::Icon(L"app.ico");
This should neutralize the bug that Microsoft has not fixed.
If you are using visual studio 2019 , you need to change the name of namespace in Form1 the same as your project name, i did it and it works
and make sure you change it in main :
[STAThread]
int main() {
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
Application::Run(gcnew your_namespace_name::Form1());
return 0;
}

Development in Visual Studio for AX 2012

I have few questions regarding development in Visual Studio C# project for AX 2012.
There is a tool that provides Application Explorer from where you can drag any AOT item (Table, Class) in your project.
I dragged CustTable from the Application Explorer into my project and I can see the proxy class generated for it and all the methods that were in the Table are visible but I am interested to fetch all the records like below
select CustTable
So If I create object of the proxy class in Visual Studio how I will get all the records, there is one possibility to write a method in AX and call in the Visual Studio.
Second question is, I have created a class library and added in the C Sharp project of AOT, how I can use in the X++ classes? Is there anyway to call it. Please provide me some links related to it.
You can do one of the following : (assuming you have 2012 R2 by now)
You can use the new Linq provider: For sample code on how to do this, you can see here : http://msdn.microsoft.com/en-us/library/jj677293.aspx
You can use the table proxy as you mention above but this is done by using the find method on the Custtable.
CustTable custtable = new CustTable();
custtable = CustTable.findByCompany(dataAreaId, accountNum);
You could also use the business connector which has been around for a while now. An example of this is found here : http://msdn.microsoft.com/en-us/library/cc197126.aspx (This lets you use things like : axRecord.ExecuteStmt("select * from %1"); )
You can do something like this:
CustTable c = new CustTable();
c.ExecuteStmt("select * from %1");
while (c.Found)
{
MessageBox.Show(c.Name);
c.Next();
}

"Could not obtain DTE from host" During T4 Transformation

I follow this post Get Visual Studio to run a T4 Template on every build, using the solution with Visual Studio SDK and Visual Studio 2010 Modeling and Visualization SDK installation.
...BUT I get an error that I cannot solve:
Error 2 Running transformation: System.ArgumentNullException: Value cannot be null.
Parameter name: Could not obtain DTE from host
at Microsoft.VisualStudio.TextTemplatingE035559D977B9B9858AB2036321BC47D.GeneratedTextTransformation.EntityFrameworkTemplateFileManager.VsEntityFrameworkTemplateFileManager..ctor(Object textTemplating)
at Microsoft.VisualStudio.TextTemplatingE035559D977B9B9858AB2036321BC47D.GeneratedTextTransformation.EntityFrameworkTemplateFileManager.Create(Object textTransformation)
at Microsoft.VisualStudio.TextTemplatingE035559D977B9B9858AB2036321BC47D.GeneratedTextTransformation.TransformText()
at Microsoft.VisualStudio.TextTemplating.TransformationRunner.RunTransformation(TemplateProcessingSession session, String source, ITextTemplatingEngineHost host, String& result). Line=0, Column=0 ApmWeb.Web.Client
Following the first part of my script...
<## template language="C#" debug="false" hostspecific="true"#>
<## include file="EF.Utility.CS.ttinclude"#>
<## output extension=".cs"#><#
CodeGenerationTools code = new CodeGenerationTools(this);
MetadataLoader loader = new MetadataLoader(this);
CodeRegion region = new CodeRegion(this, 1);
MetadataTools ef = new MetadataTools(this);
string inputFile = #"../../ApmWeb.Infrastructure.Data/Model/ApmWebModel.edmx";
MetadataWorkspace metadataWorkspace = null;
bool allMetadataLoaded =loader.TryLoadAllMetadata(inputFile, out metadataWorkspace);
EdmItemCollection ItemCollection =
(EdmItemCollection)metadataWorkspace.GetItemCollection(DataSpace.CSpace);
string namespaceName = code.VsNamespaceSuggestion();
EntityFrameworkTemplateFileManager fileManager =
EntityFrameworkTemplateFileManager.Create(this);
UPDATE
I found that the problem is into "EF.Utility.CS.ttinclude" in this point...
dte = (EnvDTE.DTE) hostServiceProvider.GetService(typeof(EnvDTE.DTE));
if (dte == null)
{
throw new ArgumentNullException("Could not obtain DTE from host");
}
My idea is that you can’t get the DTE object when running the transformation outside the VS Host. This error occurs, for example when running the transformation within a Team Build (the MSBuild Host does not “know” the DTE object). In effect it works using "run custom tool" from VS but configuring the autamatic T4 build as I told in previous post, it doesn't work.
So how can solve? Is it a bug of EF.Utility.CS.ttinclude?
UPDATE
Removing interaction with VS using DTE (define PREPROCESSED_TEMPLATE in EF.Utility.CS.ttinclude) all works, but I loose e.g. capability to add generated file to my project... Is there an other way to put working it?
As you've discovered, you're not going to have access to the DTE when transforming at build time.
One approach to dealing with the generated code not appearing in your project is to include it with a wildcard e.g.
As long as you use a standard output naming convention this should give you a reasonable experience. You can also use the build targets to redirect the generated output to a specific folder and then use a simpler wildcard to include everything in the folder.
You do have to watch out that manual tweaking in the IDE will remove this wildcard and replace it with a point in time outcome of its evaluation.

How Can I Add an "ATL Simple Object" to Old ATL DLL Project Upgraded to VS 2010?

We have a DLL project which has existed for a long time (maybe as far back as Visual Studio 6) which has been updated for each new version of VS. The project contains a number COM classes implemented using ATL.
After upgrade to VS 2010, the project still builds fine. However, if I try to right-click the project and choose Add -> Class... -> ATL Simple Object, I get an error box that says this:
ATL classes can only be added to MFC EXE and MFC Regular DLL projects or projects with full ATL support.
This worked in VS 2008.
When I look at the project properties, Use of MFC was set to Use Standard Windows Libraries and Use of ATL was set to Not Using ATL. I changed these to Use MFC in a Shared DLL and Dynamic Link to ATL respectively, but still get the same error.
I know how to add new ATL objects without using the wizard, and I could try to recreate the project from scratch using VS 2010 to make it happy. But does anyone know of any easy way to get VS to allow me to use the ATL Simple Object wizard with a project that it doesn't recognize as a project "with full ATL support"?
Check this thread out.
It seems that adding this fragment info your ATL C++ code make it work. You don't need to actually build the project, just remove this stuff away after you are done with the wizard (provided that solution works for you).
// Added fake code begins here
class CAppModule :
public CComModule
{
};
// Added fake code ends here, below is regular ATL project stuff
CAppModule _Module;
This is where it all comes from, in $(VisualStudio)\VC\VCWizards\1033\common.js:
/******************************************************************************
Description: Returns a boolean indicating whether project is ATL-based.
oProj: Project object
******************************************************************************/
function IsATLProject(oProj)
{
try
{
var oCM = oProj.CodeModel;
oCM.Synchronize();
// look for global variable derived from CAtlModuleT
var oVariables = oCM.Variables;
for (var nCntr = 1; nCntr <= oVariables.Count; nCntr++)
{
var oVariable = oVariables(nCntr);
var strTypeString = oVariable.TypeString;
if (strTypeString == "ATL::CComModule" || strTypeString == "ATL::CAutoThreadModule")
{
return true;
}
Same problem here, but the project source already had CComModule _Module;
Fixed it, based on the IsATLProject script shown above, by changing it to
**ATL::**CComModule _Module;

"Run Custom Tool" for resx files in MVC2 project (from an external application/script)

I am trying to get the localization for my MVC project working with our existing infrastructure for editing string resources. We store all our resource string in database tables and have a front end web UI to edit them with, and an export application which generated the .resx files. This all works great, but I am having a little difficulty with a new project using MVC2 and VS2010.
I have asked another question on this, the answer to which almost got me there, but not quite.
I have now changed the resources to be in a Resources folder (instead of App_GlobalResources), as recommended by a number of people. And have the following settings against my .resx files ...
Build Action = Embedded Resource
Copy to Output Directory = Do not copy
Custom Tool = PublicResXFileCodeGenerator
Custom Tool Namespace = Resources
File Name = MyApp.resx
I have changed my export application to run the resgen.exe tool with the following parameters ...
string args = string.Format("/publicClass \"{0}\" /str:cs,Resources,{1},\"{2}\"", resourceFile, Path.GetFileNameWithoutExtension(resourceFile), csFilename);
... which generates an almost identical .designer.cs file as I get when I add the .resx file to my project initially. The only difference is the
The generated .designer.cs file differs slightly from the file I get when I run the resgen.exe tool from within my export application.
This is the code generated by VS2010 when I first add the .resx file to my Resources folder ...
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Resources.MyApp", typeof(MyApp).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
... the difference when I run the resgen.exe tool is that is prefixs MyCompany.MyApp to the namespace in the constructor to ResourceManager
new global::System.Resources.ResourceManager("MyCompany.MyApp.Resources.MyApp", typeof(MyApp).Assembly);
Now, this to me seems to be a bug in the resgen.exe tool, because I've told it that the Namespace for my resources is Resources, not MyCompany.MyApp.Resources.
So, is there a fix/work-around for this problem?
The only thing I can think to do at the moment is to post-process the generated .designer.cs file with powershell and fix it!
Finally, I have solved the problem.
I decided to simplify things a bit by breaking my resources out in to a new assembly called Resources. I then added my resx files and set the properties for them as below ...
Build Action = Embedded Resource
Copy to Output Directory = Do not copy
Custom Tool = PublicResXFileCodeGenerator
Custom Tool Namespace = Resources
File Name = MyApp.resx
I then changed my export application to run ...
resgen MyApp.resx /str:c#,Resources,MyApp,MyApp.designer.cs /publicClass
... and to delete *.resources from the folder (created by the resgen.exe utility, but not needed)
This got rid of the prefix on the constructor to ResourceManager, and then i just added a reference to my new Resources assembly to my web application.
I've run a few tests to make sure all is good, including going in to the .designer.cs file and deleting one of the properties to cause a compiler error. Then re-ran my export app, and everything worked again.
So, I am a happy bunny!

Resources