AXForum  
Вернуться   AXForum > Microsoft Dynamics CRM > Dynamics CRM: Blogs
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 09.12.2010, 21:27   #1  
Blog bot is offline
Blog bot
Участник
 
25,643 / 848 (80) +++++++
Регистрация: 28.10.2006
With NAV 2009 it has been made available to the users a messaging system based on Notes / MyNotes page parts. Note records are stored as BLOBs inside table 2000000068 Record Link. It is known that you cannot handle Notes using normal C/AL code and, in particular, correctly stream in and out the content of those BLOB fields.



In this blog you will find the source code in order to implement a COM Stream Wrapper object to write and read Notes. You may use this COM object to generate and handle Notes when needed without being bound to Notes and MyNotes system part. This object may give you much more flexibility in your RTC code development.

NOTE: the Stream Wrapper is working correctly (writing) only when code is executed in a RTC based environment. It will give unpredictable and wrong results if executed using Classic Client.

If you want to know more about Notes you can refer to MSDN link:

Touring the RoleTailored Client Pages http://msdn.microsoft.com/en-us/library/dd301400.aspx

My ingredients:
  • NAV 2009 SP1 (with latest HF applied)
  • Visual Studio 2010 Professional
  • VS Command Prompt 2010 (from SDK)
  • Windows 7 Enterprise
Develop the COM StreamWrapper.dll in Visual Studio

A. Create a New Class Project
  1. Open Visual Studio (in this example I am using Visual Studio 2010) with elevated privileges (Run As Administrator)
  2. Create a New Project (CTRL+SHIFT+N) with these parameters
    • Visual C# - Windows
    • Class library
    • .NET Framework 3.5
    • Name: StreamWrp
    • Location: C:TMP (or whatever location you like)
    • Solution Name: StreamWrp
    • Create directory for solution
B. Create a Strong Name Key (SNK) and set correct Properties for the Class project
  1. Go to Project > Properties (StreamWrp Properties...)
  2. From the Project Properties form go to "Application*" tab
  3. Enable on Resources, the "Icon and Manifest" option
  4. Click on "Assembly Information" button
  5. In the "Assembly Information" form use the following GUID (or create brand new one):
    • 74f87d09-198a-4d81-a056-53271f21d4dd
  6. In the "Assembly Information" form check "Make assembly COM-Visible" and click OK
  7. From the Project Properties form go to the "Build" tab
  8. In the "General" section tick "Define DEBUG content", "Define TRACE content" and "Allow unsafe code"
  9. From the Project Properties form go to the "Signing" tab
  10. Tick "Sign the assembly"
  11. Create a new Strong Name Key (SNK) e.g. SWtest.snk
C. Develop (add code to) your StreamWrp project
  1. Add References (replace the existing ones) to the following Namespaces
    • System
    • System.Data
    • System.XML
  2. Locate your Class1.cs file in the Solution Explorer
  3. Right click > View Designer (Shift+F7)
  4. Replace the C# code automatically written with the one written below
// Copyright © Microsoft Corporation. All Rights Reserved.

// This code released under the terms of the

// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System;

using System.IO;

using System.Collections.Generic;

using System.Text;

using System.Runtime.InteropServices;

using System.Runtime.InteropServices.ComTypes;



namespace StreamWrp

{

[ComVisible(true)]

[Guid("2F870D88-FEA5-4F27-81FB-6775D7436E52")]

public interface IStreamHelper

{

string Text

{

get;

set;

}

int Transform(int encodeRead, int encodeWrite, IStream reader, IStream writter);

}

[ClassInterface(ClassInterfaceType.None)]

[Guid("B4E5F8F4-5225-4B3A-998A-B82A8A7C6B8E")]

public class StreamHelper : IStreamHelper

{

public string Text

{

get

{

throw new Exception("The method or operation is not implemented.");

}

set

{

throw new Exception("The method or operation is not implemented.");

}

}

public int Transform(int encodeRead, int encodeWrite, IStream reader, IStream writter)

{

byte[] pv = new byte[4098];

int read = 0;

unsafe

{

IntPtr pcbRead = new IntPtr(&read);

reader.Read(pv, pv.Length, pcbRead);

}

MemoryStream innerStream = new MemoryStream(pv, 0, read);

string note = String.Empty;

if (innerStream.Length != 0)

{

//Select InS encoding and ReadChars Ins

Encoding inEncode;

if (encodeRead != 0)

{

inEncode = Encoding.GetEncoding(encodeRead);

using (BinaryReader innerreader = new BinaryReader(innerStream, inEncode))

{

note = new string(innerreader.ReadChars((int)innerStream.Length));

innerreader.Close();

}

}

else

{

using (BinaryReader innerreader = new BinaryReader(innerStream))

{

note = new string(innerreader.ReadChars((int)innerStream.Length));

innerreader.Close();

}

}

MemoryStream stream2 = new MemoryStream();

//Select OutS Encoding and Write OutS

Encoding outEncode;

if (encodeWrite != 0)

{

outEncode = Encoding.GetEncoding(encodeWrite);

using (BinaryWriter writer = new BinaryWriter(stream2, outEncode))

{

writer.Write((string)note);

writer.Close();

pv = stream2.ToArray();

}

}

else

{

using (BinaryWriter writer = new BinaryWriter(stream2))

{

writer.Write((string)note);

writer.Close();

pv = stream2.ToArray();

}

}

unsafe

{

IntPtr pcbWrite = new IntPtr(&read);

writter.Write(pv, pv.Length, pcbWrite);

}

}

return read;

}

}

}



D. Strong sign and build your COM object
  1. Now it is all set up, you are ready to build your StreamWrapper COM object. In the main menu, go to "Build" > "Build StreamWrp F6" (this is automatically strong signed as per properties setting).
  2. NOTE : a WARNING message may arise
Warning 1 Type library exporter warning processing 'StreamWrp.IStreamHelper.Transform(reader), StreamWrp'. Warning: Type library exporter could not find the type library for 'System.Runtime.InteropServices.ComTypes.IStream'. IUnknown was substituted for the interface. StreamWrp

This is just a Warning about a substitution from IStream to IUnknown. There is no problem with this warning message. The compilation is successful.



E. Place DLLs into a folder and Register them
  1. Locate/Copypaste StreamWrp.dll and StreamWrp.tlb (should be in your StreamWrpStreamWrpbinDebug folder) in the Add-In folder of a machine where Role Tailored Client has been installed. (typically C:Program FilesMicrosoft Dynamics NAV60RoleTailored ClientAdd-ins)
  2. Launch the Visual Studio Command Prompt (VSCP) with elevated privilege (Run As Administrator).
  3. In the VSCP, navigate through the location where you have located the dlls. (typically C:Program FilesMicrosoft Dynamics NAV60RoleTailored ClientAdd-ins)
  4. Once you are located in the right directory type:
regasm /tlb:StreamWrp StreamWrp.dll /codebase

(hit return)

NOTE: there can be some warning messages

(type)

gacutil /I StreamWrp.dll

(hit return)



Develop the C/AL code

A. Develop the C/AL code to WRITE and READ Notes in RTC environments

How this COM Wrapper works? It accepts a Stream and returns a modified Stream. Nothing more.

It needs to be feed up with 2 encoding values depending if the Wrapper is used to write or read Notes.

A useful example of encoding (overall if there are special characters that need to be handled, e.g. double S, umlaut, etc.) can be found at this link:

http://msdn.microsoft.com/en-us/libr...scodepage.aspx

In this example, I am using a DEU standard database, therefore I am using IBM437 CodePage to correctly encode/decode the stream (note that IBM437 is also part of the Windows CodePage 1252).

The 2 following Codeunits attached in TXT format are used to Write and Read Notes.

NOTE: in order to let this example works you must have, at least, 1 note created from RTC (it merely use a copy from the last record, just as example).

This is the C/AL code snippet to WRITE Notes using RTC

...

// Copyright © Microsoft Corporation. All Rights Reserved.

// This code released under the terms of the

// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

IF ISSERVICETIER THEN BEGIN

CLEAR(NoteText);

// Add special chars

NoteText.ADDTEXT(STRSUBSTNO(Text1000000001,USERID,TODAY,TIME) + ' - ìèòàù - Österreich - ');

// Browse country table and create the Note by pasting Code and Name into the NoteText

CountryRec.RESET;

IF CountryRec.FINDFIRST THEN REPEAT

NoteText.ADDTEXT(' ** Country ' + FORMAT(CountryRec.Code)+ ' - ' + FORMAT(CountryRec.Name));

UNTIL CountryRec.NEXT = 0;

// Find the last Record Link to retrieve the ID

RecordLink.RESET;

RecordLink.FINDLAST;

LinkID := RecordLink."Link ID";

// Create ID+1 Record Link with empty Note (copy the link above)

LinkID := LinkID + 1;

RecordLink2.INIT;

RecordLink2."Link ID" := LinkID;

RecordLink2."Record ID" := RecordLink."Record ID";

RecordLink2.URL1 :=RecordLink.URL1;

RecordLink2.Type := RecordLink2.Type :: Note;

RecordLink2.Created := CURRENTDATETIME;

RecordLink2."User ID" := USERID;

RecordLink2.Company := COMPANYNAME;

RecordLink2.Notify := TRUE;

// Stream the NoteText inside the note

RecordLink2.CALCFIELDS(Note);

RecordLink2.Note.CREATEOUTSTREAM(OutS);

NoteText.WRITE(OutS);



RecordLink2."To User ID" := USERID;

RecordLink2.INSERT;



// Find the record inserted in order to 'adjust' it with the StreamWrapper

RecordLink2.INIT;

RecordLink2."Link ID" := LinkID;

RecordLink2.FIND('=');



RecordLink2.CALCFIELDS(Note);

RecordLink2.Note.CREATEINSTREAM(InS);

RecordLink2.Note.CREATEOUTSTREAM(OutS);

// Let the COM StreamWrapper transform the Blob correctly

EncodeIn := 437; //CodePage IBM437

EncodeOut := 0; //No CodePage in output

IF ISCLEAR(Transform) THEN

CREATE(Transform);

InSVar := InS;

OutSVar := OutS;

Transform.Transform(EncodeIn, EncodeOut, InSVar, OutSVar);



RecordLink2.MODIFY();

END;

MESSAGE('WRITE : DONE');

...

And this is the C/AL code snippet to READ Notes using RTC

...

IF ISSERVICETIER THEN BEGIN



CLEAR(TempBlobRec);

CLEAR(NoteText);



// Find the right Record Link

RecordLink.RESET;

RecordLink.FINDLAST;



IF RecordLink.Note.HASVALUE THEN BEGIN

RecordLink.CALCFIELDS(Note);

RecordLink.Note.CREATEINSTREAM(InS); //Note --> InS



// Init a Temp Blob

IF TempBlobRec.GET(10000) THEN

TempBlobRec.DELETE;



TempBlobRec.INIT;

TempBlobRec."Primay Key" := 10000;

TempBlobRec.INSERT;



// Stream the 'modified back' Note onto this Blob field

TempBlobRec.GET(10000);

TempBlobRec.CALCFIELDS(Blob);

TempBlobRec.Blob.CREATEOUTSTREAM(OutS);



// Let the COM StreamWrapper transform the Blob correctly

EncodeIn := 0; // Read raw data from BLOB

EncodeOut := 437; // Use CodePage IBM437 in output



IF ISCLEAR(Transform) THEN

CREATE(Transform);

InSVar := InS;

OutSVar := OutS;

Transform.Transform(EncodeIn, EncodeOut, InSVar, OutSVar);



TempBlobRec.MODIFY;

// Get the modified Blob rec and read it

TempBlobRec.GET(10000);

TempBlobRec.CALCFIELDS(Blob);

TempBlobRec.Blob.CREATEINSTREAM(InS2);



// Algorithm to READ the Blob output

IsFirstTxtLine := TRUE;

WHILE NOT (InS2.EOS()) DO BEGIN



Int:= InS2.READ(Txt);

IF Int <> 0 THEN BEGIN



IF IsFirstTxtLine THEN BEGIN

LengthStr := STRLEN(Txt);

CASE LengthStr OF

1..126 : Txt := COPYSTR(Txt,3,STRLEN(Txt));

127 : Txt := COPYSTR(Txt,4,STRLEN(Txt));

ELSE

Txt := COPYSTR(Txt,5,STRLEN(Txt));

END;

IsFirstTxtLine := FALSE;

END;



MESSAGE(Txt);

END;



CLEAR(Txt);

CLEAR(Int);



END;

END;

END;

MESSAGE('READ - DONE');

...

These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use.

Duilio Tacconi (dtacconi)

Microsoft Dynamics Italy

Microsoft Customer Service and Support (CSS) EMEA

A special thanks to Jorge Alberto Torres - DK-MBS NAV Development



Источник: http://feedproxy.google.com/~r/Micro...m-wrapper.aspx
__________________
Расскажите о новых и интересных блогах по Microsoft Dynamics, напишите личное сообщение администратору.
 


Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 23:31.