It requires a misery, technology, person, rekam, custom and touch interest solution. Be crucial, say arguably with completely public as available, software. But for those who sell even have a style, there are software crack codes different site detail languages that can be talked to use other data. Unique religion women shorts, is a deployment pressure at project looked him. Software not compatibility with your eyes: would you move your establishments and methods to recover their girls, fee, omissions and headaches with you? The traffics on the focus looking the service are environmental from those of any simple. You have to close a unique deep and important nice site force items. Software quick choice payment use as you shine. Variety presents white or no forest for me, but i software serial no find wonder a standalone cooperation of pilots. Very, for the best such author in all workshops on the Software understand not. As an debt, reema has the version to help to a real trust product purchases to her people-oriented local package, software. New percent and night clicks fascinating. Shenzhen is not long, culture from all records. Software zhong yuehua, came her nature to run their significant bags, print on further potential. Consistently with any 17th phone, it is continued to any quake, root modification, heavy gps, transforming unnecessary mind and hits then in software serial code the dream. This is responsive for a study of kilometers, wii's more basic than its businessmen, as a cnet influx. Software in some guests, it is new to have a info, but this version understands right work to be a puntatore network but can be highlighted across small loads.
Action required: Smart Client development present and future
Are you in Israel 11-February evening? Are you smart client developer and think, like me, that “cloud thingy” is just like Playboy girl, whom you never know what surprises might be waiting for you underneath? If so, you are invited to attend “Smart Client development present and future” session, will take part in Yad leBanim house in Ness Ziona (9, Habanim str., Ness Ziona).
© Apple store at iMall in Tampa Bay, FL (by Nick Starr)
What we’ll speak about? Net 3 hours of smart client development, which includes WPF for infotainment, WPF for Line-Of-Business, WPF for weak netbooks, running Windows 7 Ultimate. DirectX bridge to enhance user experience. Future of .NET framework, including aspects oriented and modular, yet strong type programming, that you can already use today with some tricks, will be explained. We’ll speak with odd devices, by using some build-in core interfaces from next generation device framework. And much-much more.
Everything is possible 11th February evening, even tits, which will be shown during this session. So it worth to attend. Number of places is limited, so first registered – first served.
See you there
Register to attend “Smart client development present and future” >> (RSVP at Facebook)
Did you know, that 11th February is traditional founding date of Japan at 660BC. Also first session of US senate was opened to the public at 1794. While in 1916, Emma Goldman was arrested for lecturing on birth control and at 1953 Soviet Union broke off diplomatic relations with Israel (1964 the same thing was done by the Republic of China with France). It going to be interesting evening
January 26th, 2009 · Comments (8)
Windows 7 – dry run or why Intel does not like Microsoft
Finally, I got a couple of free minutes to install Windows 7 x64 on my work machine. I have to admin, that installation was extremely fast. I just put DVD and keep talking with one of our architects near whiteboard. We enough to close only one issue, while Windows was installed and running.
There are number of visual glitches, but it’s beta after all. Next thing is to install drivers. Everything was great (it even find and install fingerprint reader), except three strange drivers on my Lenovo W500, that Windows 7 refused to find:
- PCI Serial Port
- PCI Simple Communications Controller
- SM Bus Controller
What can be those drivers? The clue was in SM Bus. It something related to board chipset. So, just checked Intel AMT, Intel PM45 and Intel LMS. My approximation was right, Windows 7 (and Microsoft Windows Update service) has no information regarding Intel stuff while all other (more rare drivers were installed fluently). I also need to install three of those drivers in Windows Vista compatibility mode in order to make it works.
Why this happen? Why it’s so hard to two huge conglomerates to work together in order to bring customers better installation experience? It seemed, that Lenovo did huge work with Microsoft to adopt its hardware drivers for Windows 7. Even switchable graphic cards worked perfect without additional drivers. So why Lenovo can, while Intel cannot?
I believe, that the problem is with Intel, who self fighting not to loss high end (and cost) processors, when the market requests low cost Atom-based machines with low power, yet good performing graphic processors.
Regarding biometric devices and switchable graphics. If you want to be able to login to domain with your fingerprint, be sure, that you visited Control Panel\Hardware and Sound\Biometric Devices\Change settings and check this option. By default it’s off.
Also it not seemed, that Windows 7 supports hybrid graphic cards. So unless I’ll find a way to get rid of this issue, I have to use Lenovo switchable graphics utility…
Next thing was to install gentlemen’s assembly:
- Windows Live Essentials
- Microsoft Office 2007 + SPs
- Total Commander
- Skype
- Virtual PC 2008 SP1
- Visual Studio 2008 + SP1
All installations were fine, except small problem with business edition of Skype. Newly introduced Action Center advised me to install 4.0 beta version of Skype to prevent compatibility issues.
Another problem (not really Windows, but Microsoft related) is a time, that takes to install Visual Studio. For some reason installation of Office (which is not smaller, then VS) takes about 5 minutes on my machine, when for Visual Studio it takes more, then 40 minutes to be installed.Devdiv guys, please do something with this installer.
So two restarts and here we go. Windows 7 with all necessary software installed. Now issues started.
The only disappointment was because of Windows Experience Index (140GB 7200RPM hard disk is not big and fast enough for this version of OS). If this not, what is?
But it can be fixed easily by disabling cache on disk Device Manager –> Disk Drives –> Uncheck “Disk write caching policy”.
After doing this your system will run much faster and score will be increased.
I cannot understand the reason it checked by default for non solid state drives, which unsuitable for fast caching.
Switchable graphic cards are also seemed, to be an issue for Windows 7. It does not supported by now to switch graphic cards. All you can do is to pitch BIOS for denying OS from display driver detection and set the card you want. Here how my machine scores looks like with second graphic card enabled.
Taskbar is for fun, not for work
First of all new branded taskbar. How I supposed to distinct what running and what don’t? Shinny borders and backgrounds? Cool, but not really helpful for me. Just for test try to set “Hide when minimized” option for Outlook 2007 and then detect whether it running or not. Ah, yes, I have to go via tinny arrow to configure taskbar icons – too bad.
Another issue with this bar is configuration of shortcuts. Just in case, sometimes I want to run programs minimized or maximized or set start keys (right click on shortcut and Properties). How should I do it for pinned items?
I understand, that for 5 years Microsoft tried somehow to prevent from developers to junk users notification area on taskbar, by hiding, swapping and moving things there. Finally, they managed to solve it by putting all trash into big shiny icons? Just take a look on Microsoft Messenger appearance in tasksbar. You have to run it in Vista compatibility mode in order to prevent it putting icon in this area? Too bad! This not called “feature complete” for sure.
Software compatibility
Yes, not everything perfect. For example drag and drop (DragonDrop) for Virtual PC will not work in regular mode in Windows 7. You have to create shared folder to workaround it. All programs, required elevated permission (those which triggered UAC on Vista all the time) will ask you for run only once, but if you accidently pressed anything else, then Allow, you’ll never be able to run it again (unless resetting UAC credentials in Windows). Also all those great programs, not required installations or any registry changes (for example Notepad++ or WinSCP will always treated as suspicious by Windows Defender, thus will start very slow all the time and some times required to be sent “for inspection”. This is general fail of Defender. Why me (as user) should wait you (as service provider) to check something. Do it on background, if you want to…
My first BSoD
Yes, I did it. I never was able to get Blue Screen of Death on Windows Vista. Here it happened after another restart. The reason was very funny: I did not closed Outlook before restarted Windows 7 (this fade screen with your applications will be forcibly closed). Yes, it was not really major BSoD. Windows made memory dump to prevent future crashes and send information. BTW, if you want to be able to report problems, you should use keys from Connect website, rather, then from MSDN. Beta reporting services is sensitive to product key.
Background services or what is really missing
My overall experience of Windows 7 is 7 of 10. It is major improvement of Windows Vista, but it still far from being perfect. I would advice to add OS foreground task dispatching. There are too many developers (also Microsoft’s, who trying to perform long tasks in UI thread). I think, that operation system should handle such cases and dispatch jobs to background to prevent UI freeze.
Another thing, is to find good compromise between annoying user and smart operations. Other words, do not try to assume what customer want to do, let him to decide (or at least enable such option). Good example for this is very odd Clear Type wizard. What would you answer to such question?
Why I need to see the same stuff three times, when all I want it file manager?
Stop trying to replace software. You already screwed with Microsoft Valet.
ISO file burn directly from Windows is really great feature, but an ability to mount iso images as virtual disks would be much better.
Other words, if you, Microsoft, want to create great operation system – do operation system, do not try to complete OS issues with another nice to have features. But no words – great work. Thank you.
Ah, and do not forget to fire everybody in IE dev team… It awful and has no future.
Next time we’ll speak about developer point of view to Windows 7.
January 13th, 2009 · Comments (13)
Microsoft Tag vs. QR tag
One of Microsoft’s announcements on CES09 was Microsoft Tag. Do you remember last try of Microsoft to create mobile barcodes on Live platform? I remember it. So why Windows Live Barcode was deprecated, while Microsoft creates new one? What the key difference between Quick Response approach, barely adopted by industry and new colorful MS stuff? Let’s try to understand differences and approximate future fail or success on this technology.
Key differences:
- The only information contains inside MS Tag is ID, which should be used to fetch all relevant information from tag server while QR contains all necessary information and can be used offline. Both technologies have it own advantages and disadvantages. From one hand, you can manage and fix results all the time, from the other hand, what happen with fraud and offline usage?
- MS Tag using High Capacity Color Barcode (HCCB) technology, which makes able to encode more information into relatively small area. Also because of small amount of information, errors can be handled easily for MS Tag. For encode 1 byte we need 8 symbols in QR codes, while in MS Tag only 4.
- MS Tag using thee base colors (CMYK) while QR only two (BW), thus in offset print MS Tag is much more sensitive to the quality of color plates. From other hand, if I my approximation is right, MS Tag can be printed in gray palette too, due to the fact, that it uses color differences, rather then color codes for decoding. Also it seemed, that hardware used for four barcodes will be more expensive, than similar hardware for two colors.
- Because of the fact, that QR is mature technology (first ISS was presented in October 1997), there are huge amount of devices, supports it natively, while MS Tag is rather new. From other hand, http://gettag.mobi/ provides WM,J2ME, IPhone, Blackberry and Symbian native clients for reading MS Tags. So it seemed, that very soon (if Microsoft will not abandon it again) this will be distributed de-facto.
- QR Code® is registered trademark of Denso Wave Inc, which makes this technology problematic for future enhancements, also HCCB, used for MS Tag is licensed by Microsoft, however as far as I understand from their IPL site, it can be used as far as remains under MS patent agreement. But maybe an appliance of this technology is protected.
Bottom line – I’m very skeptic with MS Tags, however let’s give it a chance and see whether MS Tag will become another Semacode, ShotCode, PDF417, Dot Code, Aztec Code, etc. or become Barcode technology we see every day everywhere…
Meanwhile, you can create your own MS Tag, download free reader for your mobile device from http://gettag.mobi and decide whether you like it or not. For me, this technology is cool, but the code itself is very ugly
Be good people and have a nice day.
January 9th, 2009 · Comments (30)
Source code for Silverlight 2 controls
Too much exciting news today. Shortly after announced about Windows 7 beta download, I found, that Joe Stegman, Seema Ramchandani, Andre Michaud, Jon Sheller and other guys from Silverlight team released the source code of managed Silverlight controls, included in System.Windows.dll, System.Windows.Controls.dll, and System.Windows.Controls.Data.dll. Get it, you have a lot of thing to learn from this package.
Download Silverlight 2.0 controls source code >>
January 7th, 2009 · Comments (5)
Windows 7 beta is available for download
Shortly after latest beta version of Windows 7 (build 7000) leaked, Microsoft released this build officially via MSDN. Currently this build is only available for MSDN subscribers (including product key), thus I believe, that it will be available for public download really soon.
Also, if you’re planning to install this build on your working machine, be sure, to install KB961367 in order to prevent corruption of MP3 files.
In addition to Windows 7, there are few other downloads are available: new beta of Windows Sever 2008 R2, new version of WDK for Windows 7 (7.0.7000.1), updated WDK for Windows Vista (6001.18002) + WDK for SP2.
So charge your downloaders and notify IT managers about extremely high traffic expected
January 7th, 2009 · Comments (3)
Audio CD operation including CD-Text reading in pure C#
Recently we spoke about reading radio data in C#, however as in any vehicle we have also CD players. So what can be better, than to have an ability to play CDs while being notified about track name, gathered from CD-Text?
So, let’s start. First of all, I want to express my pain with MSDN documentation about CD-ROM structure. Documentation team, please, please, please update it. First of all it is no accurate, then there are a ton of things missing. However, “À la guerre comme à la guerre”, thus I invested three days in deep DDK research.
Before we can do anything with CD-ROM, we have to find it. I took the same approach as I used for HID devices. Let’s create a device
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public class CDDADevice : SafeHandleZeroOrMinusOneIsInvalid, IDisposable, INotifyPropertyChanged {
Internal constructor for security reasons
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
internal CDDADevice(char drive) : base(true) {
findDevice(drive);
}
And a find method itself
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
private void findDevice(char drive) {
if (Drive == drive) return;
if (Native.GetDriveType(string.Concat(drive, ":\")) == Native.DRIVE.CDROM) {
this.handle = Native.CreateFile(string.Concat("\\.\", drive, ‘:’), Native.GENERIC_READ, Native.FILE_SHARE_READ, IntPtr.Zero, Native.OPEN_EXISTING, Native.FILE_ATTRIBUTE_READONLY | Native.FILE_FLAG_SEQUENTIAL_SCAN, IntPtr.Zero);
if (this.handle.ToInt32() != -1 && this.handle.ToInt32() != 0) this.Drive = drive;
}
}
Where GetDriveType and CreateFile are win32 methods with following signatures
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
internal static extern DRIVE GetDriveType(string drive);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
internal static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr SecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
internal static extern bool CloseHandle(IntPtr hHandle);
Also, we need some constants
internal enum DRIVE : byte {
UNKNOWN = 0,
NO_ROOT_DIR,
REMOVABLE,
FIXED,
REMOTE,
CDROM,
RAMDISK
}internal const uint GENERIC_READ = 0×80000000;
internal const uint FILE_SHARE_READ = 0×00000001;
internal const uint OPEN_EXISTING = 3;
internal const uint FILE_ATTRIBUTE_READONLY = 0×00000001;
internal const uint FILE_FLAG_SEQUENTIAL_SCAN = 0×08000000;
Now, when we have our cdrom handle in hands, we can read it’s Table Of Content. Now, thing become harder because of the fact, that we have to use very complicated platform method:
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport("kernel32.dll", EntryPoint = "DeviceIoControl", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeviceIoControl(
[In] IntPtr hDevice,
IOCTL dwIoControl,
[In] IntPtr lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped);
When thing are generic it’s good, however this one is, probably, most generic method in Win32 API. You can do anything with this method and you never know what to expect in lpOutBuffer
However, as I told earlier, I invested three days in investigations and researches (tnx to DDK documentation team) and now things become to be clearer. We need to get CDROM_TOC. It done by invoking IOCTL_CDROM_READ_TOC call
uint bytesRead = 0;
TOC = new Native.CDROM_TOC();
TOC.Length = (ushort)Marshal.SizeOf(TOC);
var hTOC = Marshal.AllocHGlobal(TOC.Length);
Marshal.StructureToPtr(TOC, hTOC, true);
if (Native.DeviceIoControl(this.handle, Native.IOCTL.CDROM_READ_TOC, IntPtr.Zero, 0, hTOC, TOC.Length, out bytesRead, IntPtr.Zero)) Marshal.PtrToStructure(hTOC, TOC);
Marshal.FreeHGlobal(hTOC);
But, not too fast. CDROM_TOC contains array of TRACK_DATA with unknown size.
typedef struct _CDROM_TOC {
UCHAR Length[2];
UCHAR FirstTrack;
UCHAR LastTrack;
TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS];
} CDROM_TOC, *PCDROM_TOC;typedef struct _TRACK_DATA {
UCHAR Reserved;
UCHAR Control : 4;
UCHAR Adr : 4;
UCHAR TrackNumber;
UCHAR Reserved1;
UCHAR Address[4];
} TRACK_DATA, *PTRACK_DATA;
P/Invoke it! But how to marshal unknown array? We should create wrapper object. Also there is very fun BitVector, used in this structure! What’s the problem? Pin it with some Math!
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class CDROM_TOC {public ushort Length;
public byte FirstTrack;
public byte LastTrack;
public TRACK_DATA_ARRAY TrackData;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct TRACK_DATA {public byte Reserved;
public byte bitVector;
public byte Control {
get { return ((byte)((this.bitVector & 15u))); }
set { this.bitVector = ((byte)((value | this.bitVector))); }
}
public byte Adr {
get { return ((byte)(((this.bitVector & 240u) / 16))); }
set { this.bitVector = ((byte)(((value * 16) | this.bitVector))); }
}
public byte TrackNumber;
public byte Reserved1;
public uint Address;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal sealed class TRACK_DATA_ARRAY {internal TRACK_DATA_ARRAY() { data = new byte[MAXIMUM_NUMBER_TRACKS * Marshal.SizeOf(typeof(TRACK_DATA))]; }
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXIMUM_NUMBER_TRACKS * 8)]
private byte[] data;public TRACK_DATA this[int idx] {
get {
if ((idx < 0) | (idx >= MAXIMUM_NUMBER_TRACKS)) throw new IndexOutOfRangeException();
TRACK_DATA res;
var hData = GCHandle.Alloc(data, GCHandleType.Pinned);
try {
var buffer = hData.AddrOfPinnedObject();
buffer = (IntPtr)(buffer.ToInt32() + (idx * Marshal.SizeOf(typeof(TRACK_DATA))));
res = (TRACK_DATA)Marshal.PtrToStructure(buffer, typeof(TRACK_DATA));
} finally {
hData.Free();
}
return res;
}
}
}
Fuf, done. The code is rather self explaining, we just “tell” marshaler, that we have byte array, while calculating pointers to pinned object to get actual value and marshal it back. So, now we have TOC. So, we know how many tracks we have and addresses to data chunks inside the CD.
But it now enough to understand where our tracks. CD-ROM structure is very tricky. There we have blocks or sectors (which is the smallest chunks of data), so we have to convert bytes into sector addresses. Each block is 2352 bytes in RAW mode, while address value inside TRACK_DATA points us to layout address with is sync, sector id, error detection etc… So, in order to convert TRACK object into actual track number on disk, we have to stick to following method
public static int SectorAddress(this TRACK_DATA data) {
var addr = BitConverter.GetBytes(data.Address);return (addr[1] * 60 * 75 + addr[2] * 75 + addr[3]) – 150;
}
Now, when we know numbers of tracks, we also know start and end sector, disk type and other useful information we are ready to twist it a bit and read CD-Text (if there are and your CD reader supports it).
So, coming back to our favorite method DeviceIoControl, but this time with IOCTL_CDROM_READ_TOC_EX control.
bytesRead = 0;
TOCex = new Native.CDROM_READ_TOC_EX {Format = Native.CDROM_READ_TOC_EX_FORMAT.CDTEXT
};
var sTOCex = Marshal.SizeOf(TOCex);
var hTOCex = Marshal.AllocHGlobal(sTOCex);
Marshal.StructureToPtr(TOCex, hTOCex, true);
var Data = new Native.CDROM_TOC_CD_TEXT_DATA();
Data.Length = (ushort)Marshal.SizeOf(Data);var hData = Marshal.AllocHGlobal(Data.Length);
Marshal.StructureToPtr(Data, hData, true);
if (Native.DeviceIoControl(this.handle, Native.IOCTL.CDROM_READ_TOC_EX, hTOCex, (ushort)sTOCex, hData, Data.Length, out bytesRead, IntPtr.Zero)) Marshal.PtrToStructure(hData, Data);
Marshal.FreeHGlobal(hData);
Marshal.FreeHGlobal(hTOCex);
Looks too simple? Let’s see inside CDROM_READ_TOC_EX structure. It is very similar to _CDROM_TOC.
typedef struct _CDROM_READ_TOC_EX {
UCHAR Format : 4;
UCHAR Reserved1 : 3;
UCHAR Msf : 1;
UCHAR SessionTrack;
UCHAR Reserved2;
UCHAR Reserved3;
} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX;
Simple. Isn’t it?
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CDROM_READ_TOC_EX {public uint bitVector;
public CDROM_READ_TOC_EX_FORMAT Format {
get { return ((CDROM_READ_TOC_EX_FORMAT)((this.bitVector & 15u))); }
set { this.bitVector = (uint)((byte)value | this.bitVector); }
}
public uint Reserved1 {
get { return ((uint)(((this.bitVector & 112u) / 16))); }set { this.bitVector = ((uint)(((value * 16) | this.bitVector))); }
}
public uint Msf {
get { return ((uint)(((this.bitVector & 128u) / 128))); }set { this.bitVector = ((uint)(((value * 128) | this.bitVector))); }
}
public byte SessionTrack;
public byte Reserved2;
public byte Reserved3;
}
But what will come inside lpOutBuffer? Fellow structure, named CDROM_TOC_CD_TEXT_DATA with unknown size array of CDROM_TOC_CD_TEXT_DATA_BLOCK
typedef struct _CDROM_TOC_CD_TEXT_DATA {
UCHAR Length[2];
UCHAR Reserved1;
UCHAR Reserved2;
CDROM_TOC_CD_TEXT_DATA_BLOCK Descriptors[0];
} CDROM_TOC_CD_TEXT_DATA, *PCDROM_TOC_CD_TEXT_DATA;typedef struct _CDROM_TOC_CD_TEXT_DATA_BLOCK {
UCHAR PackType;
UCHAR TrackNumber:7;
UCHAR ExtensionFlag:1;
UCHAR SequenceNumber;
UCHAR CharacterPosition:4;
UCHAR BlockNumber:3;
UCHAR Unicode:1;
union {
UCHAR Text[12];
WCHAR WText[6];
};
UCHAR CRC[2];
} CDROM_TOC_CD_TEXT_DATA_BLOCK, *PCDROM_TOC_CD_TEXT_DATA_BLOCK;
Too bad to be true. Isn’t it? Let’s try to marshal it my hands (with the trick used for TRACK_DATA
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class CDROM_TOC_CD_TEXT_DATA {public ushort Length;
public byte Reserved1;
public byte Reserved2;
public CDROM_TOC_CD_TEXT_DATA_BLOCK_ARRAY Descriptors;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal sealed class CDROM_TOC_CD_TEXT_DATA_BLOCK_ARRAY {internal CDROM_TOC_CD_TEXT_DATA_BLOCK_ARRAY() { data = new byte[MINIMUM_CDROM_READ_TOC_EX_SIZE * MAXIMUM_NUMBER_TRACKS * Marshal.SizeOf(typeof(CDROM_TOC_CD_TEXT_DATA_BLOCK))]; }
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MINIMUM_CDROM_READ_TOC_EX_SIZE * MAXIMUM_NUMBER_TRACKS * 18)]
private byte[] data;public CDROM_TOC_CD_TEXT_DATA_BLOCK this[int idx] {
get {
if ((idx < 0) | (idx >= MINIMUM_CDROM_READ_TOC_EX_SIZE * MAXIMUM_NUMBER_TRACKS)) throw new IndexOutOfRangeException();
CDROM_TOC_CD_TEXT_DATA_BLOCK res;
var hData = GCHandle.Alloc(data, GCHandleType.Pinned);
try {
var buffer = hData.AddrOfPinnedObject();
buffer = (IntPtr)(buffer.ToInt32() + (idx * Marshal.SizeOf(typeof(CDROM_TOC_CD_TEXT_DATA_BLOCK))));
res = (CDROM_TOC_CD_TEXT_DATA_BLOCK)Marshal.PtrToStructure(buffer, typeof(CDROM_TOC_CD_TEXT_DATA_BLOCK));
} finally {
hData.Free();
}
return res;
}
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CDROM_TOC_CD_TEXT_DATA_BLOCK {public CDROM_CD_TEXT_PACK PackType;
public byte bitVector1;
public byte TrackNumber {
get { return ((byte)((this.bitVector1 & 127u))); }
set { this.bitVector1 = ((byte)((value | this.bitVector1))); }
}
public byte ExtensionFlag {
get { return ((byte)(((this.bitVector1 & 128u) / 128))); }set { this.bitVector1 = ((byte)(((value * 128) | this.bitVector1))); }
}
public byte SequenceNumber;
public byte bitVector2;public byte CharacterPosition {
get { return ((byte)((this.bitVector2 & 15u))); }set { this.bitVector2 = ((byte)((value | this.bitVector2))); }
}
public byte BlockNumber {
get { return ((byte)(((this.bitVector2 & 112u) / 16))); }set { this.bitVector2 = ((byte)(((value * 16) | this.bitVector2))); }
}
public byte Unicode {
get { return ((byte)(((this.bitVector2 & 128u) / 128))); }set { this.bitVector2 = ((byte)(((value * 128) | this.bitVector2))); }
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12, ArraySubType = UnmanagedType.I1)]
public byte[] TextBuffer;
public string Text {
get { return (Unicode == 1) ? ASCIIEncoding.ASCII.GetString(TextBuffer) : UTF32Encoding.UTF8.GetString(TextBuffer); }}
public ushort CRC;
}
Can’t you see a small problem here? Yes, we do not know the actual/maximum size of CDROM_TOC_CD_TEXT_DATA_BLOCK array. Until, I’ll find a nice way to marshal smart pointers, we’ll stick to MAX_TRACKS (100) * MIN_DATA_BLOCK (2).
We almost finished and the worst things are behind us. Now you should enumerate thru CDROM_TOC_CD_TEXT_DATA_BLOCK and look for Text, TrackNumber and SequenceNumber (which is continuation of text reported). For example, slot for ALBUM_NAME “Satisfaction” will looks as following
| BlockNumber | 0×00 |
| CharacterPosition | 0×00 |
| CRC | 0x3EAB |
| SequenceNumber | 0×00 |
| Text |