| Fred's profileFred ShenBlogLists | Help |
|
Fred ShenDynamics AX Development April 09 X++ code to remove identical copyOur client asked for a job to remove the identical copy from VAR layer.
For some unknown reason, some AOT objects are touched in VAR layer but actually are identical copy. When the developer compared the VAR layer object with the one in lower layer (BUS, SYS etc.), AX showed it was an identical copy.
Here is the example on how you can remove the identical copy in X++ code:
static void FindAndDeleteIdenticalObjects(Args _args)
{ SysTreeNode comparable1, comparable2; TreeNode curLevelTreeNode, upperLevelTreeNode; UtilIdElements utilElements, joinUtilElements; ; while select UtilElements where UtilElements.utilLevel == UtilEntryLevel::var && ( UtilElements.recordType == UtilElementType::Form || Utilelements.recordType == UtilElementType::Report || Utilelements.recordType == UtilElementType::Table || Utilelements.recordType == UtilElementType::Class || Utilelements.recordType == UtilElementType::Enum || Utilelements.recordType == UtilElementType::ExtendedType ) { //Should use join if for a normal table, but not applicable for UtilElements
//Performance hit if use exists join
select firstonly recid from joinUtilElements where joinUtilElements.utilLevel != UtilElements.utilLevel && joinUtilElements.name == UtilElements.name && joinUtilElements.recordType == UtilElements.recordType; if (joinUtilElements.RecId)
{ //Thanks for Jim Shepherd here
curLevelTreeNode = SysTreeNode::findNodeInLayer(UtilElements.recordType, UtilElements.name, UtilElements.parentId, UtilElements.utilLevel); upperLevelTreeNode = SysTreeNode::getLayeredNode(curLevelTreenode, 1);
comparable1 = SysTreeNode::newTreeNode(curLevelTreeNode);
comparable2 = SysTreeNode::newTreeNode(upperLevelTreeNode); if (SysCompare::silentCompare(comparable1, comparable2)) { info(strFmt("Element name: %1, Element type: %2", UtilElements.name, enum2str(UtilElements.recordType))); //Remove the node curLevelTreeNode.AOTdelete(); } } } } September 04 New server-based batch framework in AX 2009Microsoft Dynamics AX 2009 introduces a new batch framework that supports server-based batches without the need for a client. All new batch jobs in Microsoft Dynamics AX 2009 use the new batch framework. Most existing batch jobs from previous releases are being migrated to the new framework. Client-side batches are supported in Microsoft Dynamics AX 2009 but are not recommended.
From AX 2009, we don't need to run a client to run scheduled jobs, if you specify that the batch job runs on server. The batch job runs on server by default unless the developer overrides the runImpersonated method and make it return false. The old client-based batch processing is still in AX 2009 for backward compatibility and will be removed in future versions. The old client-based batch system, that was based on a dedicated client, cannot be replaced in some situations. For example, due to some technical problems that the compiler cannot be run on the server tier, which means the task to run a scheduled compilation or cross-reference update must be run on client-tier. August 26 Add a Dynamics AX user to be a memebr of Sharepoint site groupIn AX 4.0, it is allowed to link an AX user to a particular Sharepoint site group from main menu -> Administration -> Users -> User relations button -> Web sites tab. Unfortunately, this is removed from AX 2009.
However, we can still add this feature back if we like by using X++.
The example below show how easy can add an AX user to Sharepoint site owner groups by using X++ and CLRInterop.
Before you run this job, please add Microsoft.Sharepoint.dll (WSS 3.0) as a reference on AOT if it is not registered in GAC.
You can find this dll in C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI on the server that Enterprise Portal resides.
static void AddAXUserToSharepointGroup(Args _args)
{ Microsoft.SharePoint.SPWeb spWeb; Microsoft.SharePoint.SPSite spSite; Microsoft.SharePoint.SPGroupCollection spGroupCollection; Microsoft.SharePoint.SPGroup spGroup; Microsoft.SharePoint.SPUserCollection spUserCollection; Microsoft.SharePoint.SPUser spUser; EPWebSiteParameters epWebSiteParameters; UserInfo userInfo; SysUserInfo sysUserInfo; str loginName; System.Exception ex; str siteGroupName; ; try { //Sharepoint site registered in AX2009 select firstonly epWebSiteParameters; select firstonly userInfo where userInfo.id == curUserId(); select firstonly sysUserInfo where sysUserInfo.Id == curUserId(); loginName = userInfo.networkDomain + @"\" + userInfo.networkAlias;
spSite = new Microsoft.SharePoint.SPSite(epWebSiteParameters.InternalUrl);
spWeb = spSite.get_RootWeb(); //Create a user in Sharepoint
spUserCollection = spWeb.get_SiteUsers(); spUserCollection.Add(loginName, sysUserInfo.Email, userInfo.name, ""); //Add the user to a site owner group
spUser = spUserCollection.get_Item(loginName); spGroupCollection = spWeb.get_SiteGroups(); siteGroupName = CLRInterop::getAnyTypeForObject(spWeb.get_Title()) + " Owners"; //Or Visitors, Members spGroup = spGroupCollection.get_Item(siteGroupName); spGroup.AddUser(spUser); spGroup.Update(); } catch (exception::CLRError) { ex = CLRinterop::getLastException(); if (ex) { info(ex.ToString()); } } catch (exception::Internal) { ex = clrinterop::getLastException(); if (ex) { info(ex.ToString()); } } }
December 08 Failed to create COM objects on AX 4 AOSYou may come across this issue when attempt to initialize a COM object on AX 4 AOS server side:
static server void ActivateCOMOnAOS()
{
#define.Word('Word.Application')
COM com;
InteropPermission permission = new InteropPermission(InteropKind::ComInterop);
;
permission.assert();
//BP deviation documented
com = new COM(#Word);
CodeAccessPermission::revertAssert();
}
And an error message will appear:
COM object of class 'Word.Application' could not be created. Ensure that the object has been properly registered on computer 'ComputerName'.
It is because by default, Microsoft Word as a COM object can not be launched by the user NT AUTHORITY\NETWORK SERVICE.
The way to resolve this issue is to modify the Activation permission for Word Application using the Component Services administrative tool.
Configure DCOM (Windows 2003)
August 16 Consuming a Web Service in Dynamics AX 4This will tell you how to use Common Language Runtime Interoperability feature in Dynamics AX 4 to reference a web service. There is a pretty good discussion about this on Microsoft MBS community by Dilip and Mike Frank. To continue, at least you need to have Dot Net Framework SDK 2.0. (Not Visual Studio .Net) We will use the language translation service on www.stanski.com as the referenced web service. Procedure: Open a Microsoft .NET Framework command prompt. Click Start, point to All Programs, point to Microsoft .NET Framework SDK 2.0, and then click SDK Command Prompt. At the command prompt, run the following command: Then we need to edit TranslationService.cs file to add namespace for it. Compile the cs file to dll file. Type this in the command prompt This will generate the TranslationService.dll. Start Microsoft Dynamics AX 4.0 Create a new job named TestWebService strLanguage = 'en_de'; Run the job, you will get the result “Test-Netz-Service”.
July 20 RefRecID in Dynamics AX 4Dynamics AX 4.0 will generate unique RecIds per table, whereas Axapta 3.0 generates unique RecIds per company account.
This may have a great impact on the use of EDT RefRecId in AX development. In Axapta 3.0, we can directly use refRecId for table fields, because recId is unique per company account. Well, in AX 4, it is not the case anymore, how can you reference the recId within the same company account? For example, recId 5637144576 can exist in Address table, AddressCountryRegion table and AddressCounty table.
As a result, in AX 4, do not use the RefRecID data types directly for table fields. The way we use RefRecId data types is create a new EDT derived from EDT RefRecId, and define a relation for it. Then use the new created EDT for table fields. You may find VendTransOpen table as a sample. The table field RefRecId in VendTransOpen is derived from EDT VendTransRefRecId which extends EDT RefRecId. And a relationship is defined on VendTransRefRecId, which is "VendTransRefRecId == VendTrans.RecId". Since AX 4.0 will generate unique RecIds per table, and by changing the RecID from a 32-bit to a 64-bit integer, the number of RecIDs available is increased to 2-to-the-64, AX 4.0 does not include SysRecIdRepair utility. July 13 'Not Like' in Dynamics AXIn X++, we can use Like '*someIdentifier' to implement the Like keyword.
e.g. select firstonly purchTable
where purchTable.purchId like '00007*'; However if you want to use 'Not Like' in X++ SQL statement, you have three options:
The first option, using '!' as 'not', e.g. select firstonly purchTable
where !(purchTable.purchId like '00007*'); The second option, using notExists join
e.g. PurchTable purchTable, refPurchTable; ; select firstonly purchTable
notExists join refPurchTable where purchTable.purchId == '00007*'; Please make sure that you do put purchTable.purchId in condition statement, otherwise the SQL statement will retrieve an empty result set. The last option, using Query
e.g. Query query = new Query(); QueryRun queryRun; ; query.addDataSource(tableNum(PurchTable)).addRange(fieldNum(PurchTable, PurchId)).value('!00007*'); queryRun = new QueryRun(query); if(queryRun.next())
{ purchTable = queryRun.get(tableNum(PurchTable)); print purchTable.PurchId; pause; } Using NotExists join seems more complicated than the first option, but actually there is no performance difference between them.
July 04 Cache size for recId allocationIn Dynamics AX, recId is assigned according to the nextVal (ID -1, name SEQNO) of SystemSequence table. But the next value of RecId is not always retrieved from the table, and it is cached in client machine's memory. In AX3.0, the default cache size is 25.
Developers can change the default cache size using SystemSequence class: In the startupPost method of Application class, you can add the following code: SystemSequence SystemSequence;
… SystemSequence = new SystemSequence();
SystemSequence.setCacheSize(30); As a result, recIDs are drawn in sets of 30. That also means that the next value of SystemSequence table will be increased by 30 each time.
In AX 4.0, recIds will be generated unique per table instead of per company. So for each table, there will be a nextVal (ID -1, name SEQNO) in SystemSequence table. The cache size for recId allocation is increased to 250. And AX 4 does not allow changing cache size for recId allocation anymore. July 02 Undefined nodes in System Documentation after applying KR1I found that if using en-gb or de-at language after applying Kernel Roll Up 1, it will end up with Undefined nodes in System documentation. At the same time, on the property sheet of AOT, you may also find some object property displayed as *undefined* as well. What you need to do is edit your ktd file, like axsysen-gb.ktd, and locate line 1393, remove the blank line between Apostrophe(') and 1245. Everything should be back to normal. That is because ktd file contains the help text for kernel-defined method and property. The blank line makes AX unable to translate the relevant help texts. June 21 Date data type in Query Range Value ExpressionQuery range value expressions can be used in any query, where you need to express a range that is more complex than that made possible with the usual dot-dot notation. Today I just want to investigate more about the date data type in Query Range Value Expression.
dayInt = dayofMth(transDate); //dateInt should be integer type value rather than real type value dateInt = (dayInt-1)*Power(2,16) + (monthInt-1)*Power(2,8) + (yearInt-1900); queryBuildRange.value(strFmt('(TransDate < %1)', dateInt));
(In AX 3.0, max date is 31\12\2153, and 31\12\2154 in AX 4.0) Because AX can only hold dates for up to Power(2, 8), which is 256 years (1900 to 2155). June 01 Change the combobox options in RunbaseBatch classRunbaseBatch class supplies some features, including batch processing, pack/unpack and progress bar etc. On the other hand, we get this request frequently, usually to modify the properties of dialog control in runtime. For example, we add a combobox control on the dialog, but the options of combobox can't be predefined. Well, the combobox can be very conveniently filled with field lists if you are using a form, while the combobox's selection lists in RunbaseBatch is determined by Enum values ( dialog.addField(TypeId(someEnum) ). How can we accomplish this?
First option, change the eunm's values dynamically? Oh, terrible, this means that Axapta needs to add, edit and save AOT node, then synchronize in run time. Second option, use Form instead of RunbaseBatch class, if you want this Form to be savable and batchable, you need to manually to add some codes on it. Well, it is no point to do that if there is any other work around. There is a third option, and I believe this should do the trick. Let's start with a simple RunBaseBatch class and a simple scenario, dynamically adding printers' name to the combobox. Define a BaseEnum called TestRunBaseDialog (ensure that the style property is set to combo box), and create an element for it which is called TestComboboxElement. Then we can set the TestComboboxElement's label as "Select a printer". Now we can create the RunbaseBatch class from scratch. Declare the class
class TestAddComboOptionsInRunbase extends runbasebatch { int printerName; DialogField dialogPrinter; FormComboboxControl controlCombobox; #define.CurrentVersion(1)
#localmacro.CurrentList
printerName #endmacro } Pack the value
public container pack() { return [#CurrentVersion, #CurrentList]; } Unpack the value
public boolean unpack(container packedClass) { boolean _ret; Integer _version = runbase::getVersion(packedClass); switch (_version)
{ case #CurrentVersion: [_version, #CurrentList] = packedClass; break; default: _ret = false; } return _ret; } Design the dialog, we need to activate the dialogSelectCtrl method. And please notice that, there should be some other dialog control to be added before dialogPrinter. The reason is that after the Dialog form has been built, the selected control can not be the dialogPrinter, otherwise, we can't implement the dialogSelectCtrl method when we look up the options in dialogPrinter combobox. So we add a Text before adding combobox.
protected Object dialog(DialogRunbase _dialog, boolean _forceOnClient) { DialogRunBase dialog; ; controlCombobox = new FormComboboxControl();
dialog = super(_dialog, _forceOnClient); dialog.caption("Dialog for printer option"); dialog.addText("Choose Printer"); dialogPrinter = dialog.addField(typeId(TestRunBaseDialog)); dialog.allowUpdateOnSelectCtrl(true); return dialog; } Okey, we can define how to change the selection list in the combobox now.
public void dialogSelectCtrl() { controlCombobox = dialogPrinter.fieldControl(); controlCombobox.clear(); controlCombobox.add("Printer One"); controlCombobox.add("Printer Two"); controlCombobox.add("Printer three"); //… more printers here } Process your business logic in run()
void run() { ; switch (printerName)
{ case 0: info ("You are choosing printer one."); break; case 1: info ("You are choosing printer two."); break; case 2: info ("You are choosing printer three."); break; } //Put your logic here
} Finally, put the codes to Main() static void main(Args _args) { TestAddComboOptionsInRunbase testRunBase = new TestAddComboOptionsInRunbase (); ; if (testRunBase.prompt())
{ testRunBase.run(); } } The reason why we use dialogSelectCtrl() is that the dialog control in RunbaseBatch class is not built before the prompt method, the dialogPrinter is still the object of FormBuildControl. Only FormComboboxControl object can add and change the selection list. After Axapta implement the runbaseBatch.prompt(), dialogPrinter has become the object of FormComboboxControl. So in the dialogSelectCtrl(), we can modify the selection list of dialogPrinter combobox. May 26 Limited sessions in AxaptaSome Axapta system administrator may feel it is really annoying that Axapta allows the user to create multiple Axapta sessions and log in as the same user. If you want to give the user notification prior to logging in as the same User ID, here comes the solution. currentUserId = curuserid(); if (userInfo && (currentUserId == session.userId())) if (num > 1) Please notice that, if you modify the startupPost method of Application class, that works only in 2-tier environment. For both 2-tier and 3-tier environment, it is recommended to modify the startupPost method of Info class. May 17 Create a new method in runtimeSome one may need to use codes to create or edit a method in Axapta.
Here is an example to show how to create a lookup method for a form's field in runtime. static void CreateFieldMethod(Args _args) { TreeNode tn1,tnAddr, methodsNode; MemberFunction memberFunction; str source; ; //Thanks for Max Belugin's comments,
//it is really good to use Verbatim String as well.
//The reason why I use escape characters here is
//because this line of code is copied from standard Axapta application :)
tn1 = infolog.findNode( "\\Forms\\Address\\Data Sources\\Address\\Fields\\AddrRecId");
tnAddr = infolog.findNode( "\\Forms\\Address" ); methodsNode = tn1.AOTfindChild( 'Methods' ); methodsNode.AOTadd('lookup'); memberFunction = methodsNode.AOTfindChild( 'lookup' ); source = @"public void lookup(FormControl _formControl, str _filterStr) { super(_formControl, _filterStr); }" ; memberFunction.AOTsetSource(source, false);
memberFunction.AOTsave(); methodsNode.AOTsave(); tnAddr.AOTcompile(); } March 23 Convert Axapta date type value to datetime type value in SQL ServerIt is known that, in Axapta, date data type only contains values of day, month and year whereas in SQL Server, datetime data type contains values of second, minutes and hour as well. So if you want to retrieve values from SQL Server using ODBCConnection, and you need to specify the condition on some date type comlumn, how can you get it done?
Here comes the code to show you how to convert Axapta’s date data type value to datetime value. It is an example to get a voucher value from LedgerTrans table in a given date.
Hope it helps.
March 16 Read and alter registry settings in AxaptaHere is a sample code of increasing max. open cursors during run-time. But, please note that its purpose is only to show you how to read and write registry. If you encounter any open cursors problem, it is recommended to optimize the SQL statement rather than changing the setting for maximum open cursors.
static void IncreaseMaxOpenCursors(Args _args) { #winapi container regRet;
int readReg; int writeReg; str keyValue, keyPath, configName; int maxOpenCursors; ; //Specify your Axapta configuration utility name here
configName = "LocalMachine"; //New maximum open cursor, default is 90 maxOpenCursors = 120; keyPath = @"SOFTWARE\Navision\Axapta\3.0\" + configName; readReg = WinAPI::regOpenKey( #HKEY_CURRENT_USER, keyPath, #KEY_READ);
if (readReg) { regRet = WinAPI::regGetValue(readReg, 'opencursors'); keyValue = conpeek(regRet,1); info(keyValue); if (str2int(keyValue) < maxOpenCursors) { writeReg = WinAPI::regOpenKey(#HKEY_CURRENT_USER, keyPath, #KEY_WRITE); if (writeReg) { WinAPI::regSetValueEx(writeReg, 'opencursors', #REG_SZ , maxOpenCursors); WinAPI::regCloseKey(writeReg); } Info("Max open cursors: " + int2str(maxOpenCursors)); } WinAPI::regCloseKey(readReg); } } Axapta build numberIn Axapta, choose the option About Microsoft Business Solution-Axapta in the Help pull-down menu, you can see the Axapta build number information, e.g. Microsoft Business Solution-Axapta 3.0 Build # 1951.6710/514-320 SP4/OP023-196. What does it stands for? The first part 1951.6710 is the kernel build number. The second part 514-320 SP4 is the application build number. The last part OP023-196 is the localization build number. March 09 Tips on optimizing primary index in AxaptaPrimary index plays an important role in gaining optimum performance in Axapta. The Primary Index of a table is the main index that is used to uniquely identify records in it. No duplicated values are allowed in this index. When caching records, primary index is used as the caching key if it exists.
When you designing a table's primary index, follow these rules:
March 03 Development Features of Dynamics Ax (Axapta) 4.0Digested from Microsoft specification:
Common Language Runtime (CLR) Interoperability The CLR Interop feature allows X++ developers to add CLR assemblies to the AOT and write X++ code that interoperates with objects in these assemblies. This provides a number of benefits:
• Developer productivity It is more productive to support CLR assemblies than to require developers to create assemblies that they then wrap as COM components. • .NET support Providing an easy way for developers to use their CLR components in Microsoft Dynamics AX is a highly desirable feature. • ISV integration ISVs are encouraged to use .NET to write applications and to expose their application APIs using .NET technology such as XML Web services and remoting. X++ developers should be able to use these APIs directly from X++. Version control
Because the application layer framework is insufficient for this purpose, version control is a common request from partners to help them protect their intellectual investment in customizations . Microsoft Dynamics AX supports Microsoft Visual SourceSafe 6.0. However, some partners will want to support their own version control system. Extensibility hooks are provided and work with Version Control ID Server. Microsoft Dynamics AX Object IDs and Label IDs are issued. The IDs must be unique, and a central service should be used to coordinate issuing these IDs.
For general information about Microsoft Visual SourceSafe, see http://msdn.microsoft.com/vstudio/previous/ssafe/default.aspx
Debugger enhancements
In Microsoft Dynamics AX 4.0, the debugger is a stand-alone application and contains several new features for efficiently finding and fixing common problems in code, such as callstacks, breakpoints, and the ability to move the current execution point while executing code. Additionally, the user interface and shortcut keys follow the familiar design of Microsoft Visual Studio. Compiler optimization
The compiler redesign reduces compilation time by approximately forty percent. Data model reverse engineering using MorphX
Reverse engineering using MorphX enables partners to easily get detailed information about the structures and relationships of the Microsoft Dynamics AX business logic and data model. The reverse-engineering feature is a replacement of the existing Visual MorphXplorer used to visualize the Microsoft Dynamics AX data model by drawing Entity Relation Diagrams for tables and classes. The goal is to simplify collection, extract relationships, and integrate and view collections such as Microsoft Office Visio diagrams as unified modeling language (UML) diagrams. This feature will handle reverse engineering of both the data model and the object model.
By integrating the data-model and object-model evaluation with Microsoft Office Visio UML diagramming, Microsoft Dynamics AX gives partners a familiar out-of-the-box tool to use for true modeling and simplified deployment.
ImageGear library replaced with GDI+
Microsoft Dynamics AX now uses the Microsoft GDI+ graphics library instead of the Accusoft ImageGear graphics library. The GDI+ library is an application programming interface (API) that is exposed through a set of C++ classes. The GDI+ subsystem is a native component of the Microsoft Windows XP and Microsoft Windows Server 2003 operating systems and is available for 32-bit and 64-bit Microsoft Windows-based applications.
GDI+ allows application programmers to display information on a screen or printer without concern for the details of a particular display device. GDI+ insulates the application from the graphics hardware, and it is this insulation that allows developers to create device-independent applications. Print drilldown
The print framework allows users to preview report content before actually printing the report. The print preview concept has been extended from being view-only to support drilling down into the transaction hierarchies and related transactions. Print drilldown features include support based on Menu Item types (Output and Display), and multiple drilldown options on each report field.
Filtering function
Improved filtering of records in tables is accomplished through a new easy-to-use, embedded filter. Country consolidation
To meet the expectations of our partners and customers, country-specific features will be consolidated in Microsoft Dynamics AX as follows: • Western Europe, North America, and Asia Pacific regions Local features for the following countries are merged into the SYS layer or have a combined layer that covers these regions in one installation: Australia, Austria, Belgium, Canada, Denmark, Finland, France, Germany, Ireland, Italy, Malaysia, Mexico, Netherlands, New Zealand, Norway, Singapore, South Africa, Spain, Sweden, Switzerland, Thailand, United Kingdom, and United States. • Eastern Europe Local features for the following countries are consolidated in a separate layer: Czech Republic, Estonia, Hungary, Latvia, Lithuania, Poland, and Russia. • Other countries Local features for the following countries have stand-alone layers: Brazil, China, Iceland, India, Japan, and Turkey. The Microsoft Dynamics AX globalization team will strive to incorporate all new legal requirements into Microsoft Dynamics AX as time permits.
Consolidation of country-specific features reduces deployment and customization complexity. Pass complex data types to 3rd party DLLs in AxaptaIf you are using third-party dll files, you may encounter a problem that you need pass a complex data types to or from the dlls, for example, struct, array etc.
There is an example to show you how to pass struct data type to dlls. Below is the api of a given dll. /* C++ API – SampleDll.dll typedef struct { LPCTSTR lpszFontName; int nCharacterExtra; int nFontHigh; int nSpacing; int nAlign; LPCTSTR lpszTextString; } BCTEXTINFO, *LPBCTEXTINFO; BCENCODE_API DWORD WINAPI SampleDllMethod(LPBCTEXTINFO lpTextInfo); */ And we can use Binary class to store the string's address instead of including the string directly in the struct. Here is a sample code to show you how to pass a struct to dll.
client static int SampleMethod(str _name, int _chExtra, int _fontHeight, int _spacing, int _align, str _content) { int ret; Binary lpTextInfo = new Binary(24); // 6 * 4 = 24 Binary biName = new Binary(strlen(_name) + 1); Binary biContent = new Binary(strLen(_content) + 1); DLL _winApiDLL = new DLL('SampleDll.dll'); DLLFunction _SampleMethod = new DLLFunction(_winApiDLL,'SampleDllMethod'); ; _ SampleMethod.returns(ExtTypes:: DWord);
_ SampleMethod.arg( ExtTypes::Pointer, ExtTypes::Pointer); biName.string(0, _name);
biContent.string(0, _content); lpTopTextInfo.binary(0, biName);
lpTopTextInfo.dWord(4, _chExtra); lpTopTextInfo.dWord(8, _ fontHeight); lpTopTextInfo.dWord(12, _ spacing); lpTopTextInfo.dWord(16, _ align); lpTopTextInfo.binary(20, biContent); ret = _ SampleMethod.call(lpTextInfo); return ret; } March 02 Use resource files in AxaptaAxapta provides a very handy feature to allow developers to ship their solution with Axapta built-in image files. In Application Object Tree, you can find resources node. Select resources node and right click; select Create from File, specify the file location for the new resource file. After that you can use this resource file in Axapta without specifying an absolute file path in your hard disk.
Then let's see how to use this kind of files in Axapta. First, pick up the resource node from AOT; SysResource::getResourceNode(); Then generate a temporary file for this resource file;
SysResource::saveToTempFile() Finally specify the temporary file path for controls.
Here comes an example to show how to use a resource file as a background image of a given form.
{
ResourceNode resourceNode; FilePath imagename; ; resourceNode = SysResource::getResourceNode(resourcestr(ResourceName)); if (resourceNode) { resourceNode. AOTload(); imagename = SysResource::saveToTempFile(resourceNode); } else { throw Error("No file exists.") } element.design().imageName(imagename);
} |
||||
|
|