private unsafe short AllocateBufferProc(int size, IntPtr *bufferID) { #if DEBUG DebugUtils.Ping(DebugFlags.BufferSuite, string.Format("Size: {0}", size)); #endif if (size < 0 || bufferID == null) { return(PSError.paramErr); } *bufferID = IntPtr.Zero; try { *bufferID = Memory.Allocate(size, false); bufferIDs.Add(*bufferID, size); } catch (OutOfMemoryException) { // Free the buffer memory if the framework throws an OutOfMemoryException when adding to the bufferIDs list. if (*bufferID != IntPtr.Zero) { Memory.Free(*bufferID); *bufferID = IntPtr.Zero; } return(PSError.memFullErr); } return(PSError.noErr); }
private unsafe void DisposeRegularHandle(Handle h) { #if DEBUG DebugUtils.Ping(DebugFlags.HandleSuite, string.Format("Handle: 0x{0}", h.ToHexString())); #endif DisposeHandleImpl(h); }
private unsafe short ReadPortForWritePort(IntPtr *readPort, IntPtr writePort) { #if DEBUG DebugUtils.Ping(DebugFlags.ChannelPorts, string.Format("readPort: {0}, writePort: {1}", DebugUtils.PointerToString(readPort), writePort.ToString())); #endif return(PSError.memFullErr); }
private unsafe short WriteBasePixels(IntPtr port, VRect *writeRect, PixelMemoryDesc srcDesc) { #if DEBUG DebugUtils.Ping(DebugFlags.ChannelPorts, string.Format("port: {0}, rect: {1}", port.ToString(), DebugUtils.PointerToString(writeRect))); #endif return(PSError.memFullErr); }
internal IntPtr LockHandle(Handle h, byte moveHigh) { #if DEBUG DebugUtils.Ping(DebugFlags.HandleSuite, string.Format("Handle: 0x{0}, moveHigh: {1}", h.ToHexString(), moveHigh)); #endif HandleEntry item; if (handles.TryGetValue(h, out item)) { return(item.Pointer); } else { if (SafeNativeMethods.GlobalSize(h.Value).ToInt64() > 0L) { IntPtr hPtr = Marshal.ReadIntPtr(h.Value); if (IsValidReadPtr(hPtr) && SafeNativeMethods.GlobalSize(hPtr).ToInt64() > 0L) { return(SafeNativeMethods.GlobalLock(hPtr)); } return(SafeNativeMethods.GlobalLock(h.Value)); } if (IsValidReadPtr(h.Value) && IsValidWritePtr(h.Value)) // Pointer to a pointer? { return(h.Value); } return(IntPtr.Zero); } }
internal int GetHandleSize(Handle h) { #if DEBUG DebugUtils.Ping(DebugFlags.HandleSuite, string.Format("Handle: 0x{0}", h.ToHexString())); #endif HandleEntry item; if (handles.TryGetValue(h, out item)) { return(item.Size); } else { if (SafeNativeMethods.GlobalSize(h.Value).ToInt64() > 0L) { IntPtr hPtr = Marshal.ReadIntPtr(h.Value); if (IsValidReadPtr(hPtr)) { return(SafeNativeMethods.GlobalSize(hPtr).ToInt32()); } else { return(SafeNativeMethods.GlobalSize(h.Value).ToInt32()); } } return(0); } }
private short PropertySetProc(uint signature, uint key, int index, IntPtr simpleProperty, Handle complexProperty) { #if DEBUG DebugUtils.Ping(DebugFlags.PropertySuite, string.Format("Sig: {0}, Key: {1}, Index: {2}", DebugUtils.PropToString(signature), DebugUtils.PropToString(key), index.ToString())); #endif if (signature != PSConstants.kPhotoshopSignature) { return(PSError.errPlugInPropertyUndefined); } switch (key) { case PSProperties.BigNudgeH: case PSProperties.BigNudgeV: case PSProperties.Caption: case PSProperties.Copyright: case PSProperties.EXIFData: case PSProperties.XMPData: case PSProperties.GridMajor: case PSProperties.GridMinor: case PSProperties.RulerOriginH: case PSProperties.RulerOriginV: case PSProperties.URL: case PSProperties.WatchSuspension: break; default: return(PSError.errPlugInPropertyUndefined); } return(PSError.noErr); }
private IntPtr BufferLockProc(IntPtr bufferID, byte moveHigh) { #if DEBUG DebugUtils.Ping(DebugFlags.BufferSuite, string.Format("Buffer: 0x{0}", bufferID.ToHexString())); #endif return(bufferID); }
private unsafe short SetHandleSize(Handle h, int newSize) { #if DEBUG DebugUtils.Ping(DebugFlags.HandleSuite, string.Format("Handle: 0x{0}", h.ToHexString())); #endif if (newSize < 0) { return(PSError.paramErr); } if (AllocatedBySuite(h)) { try { PSHandle *handle = (PSHandle *)h.Value; IntPtr ptr = Memory.ReAlloc(handle->pointer, newSize); handle->pointer = ptr; handles.AddOrUpdate(h, new HandleEntry(h, ptr, newSize)); } catch (OutOfMemoryException) { return(PSError.memFullErr); } } else { if (SafeNativeMethods.GlobalSize(h.Value).ToInt64() > 0L) { IntPtr hPtr = Marshal.ReadIntPtr(h.Value); if (IsValidReadPtr(hPtr) && SafeNativeMethods.GlobalSize(hPtr).ToInt64() > 0L) { IntPtr hMem = SafeNativeMethods.GlobalReAlloc(hPtr, new UIntPtr((uint)newSize), NativeConstants.GPTR); if (hMem == IntPtr.Zero) { return(PSError.memFullErr); } Marshal.WriteIntPtr(h.Value, hMem); } else { if (SafeNativeMethods.GlobalReAlloc(h.Value, new UIntPtr((uint)newSize), NativeConstants.GPTR) == IntPtr.Zero) { return(PSError.memFullErr); } } } else { return(PSError.nilHandleErr); } } return(PSError.noErr); }
private void BufferFreeProc(IntPtr bufferID) { #if DEBUG DebugUtils.Ping(DebugFlags.BufferSuite, string.Format("Buffer: 0x{0}, Size: {1}", bufferID.ToHexString(), Memory.Size(bufferID))); #endif Memory.Free(bufferID); bufferIDs.Remove(bufferID); }
internal unsafe Handle NewHandle(int size) { if (size < 0) { return(Handle.Null); } Handle handle = Handle.Null; try { // The Photoshop API 'Handle' is an indirect pointer. // As some plug-ins may dereference the pointer instead of calling HandleLockProc we recreate that implementation. handle = new Handle(Memory.Allocate(PSHandle.SizeOf, true)); PSHandle *hand = (PSHandle *)handle.Value; hand->pointer = Memory.Allocate(size, true); handles.Add(handle, new HandleEntry(handle, hand->pointer, size)); #if DEBUG string message = string.Format("Handle: 0x{0}, pointer: 0x{1}, size: {2}", handle.ToHexString(), hand->pointer.ToHexString(), size); DebugUtils.Ping(DebugFlags.HandleSuite, message); #endif } catch (OutOfMemoryException) { if (handle != Handle.Null) { // Free the handle pointer if it has been allocated. // This would occur if the framework throws an OutOfMemoryException when adding to the handles dictionary. PSHandle *hand = (PSHandle *)handle.Value; if (hand->pointer != IntPtr.Zero) { Memory.Free(hand->pointer); hand->pointer = IntPtr.Zero; } Memory.Free(handle.Value); handle = Handle.Null; } return(Handle.Null); } return(handle); }
internal void UnlockHandle(Handle h) { #if DEBUG DebugUtils.Ping(DebugFlags.HandleSuite, string.Format("Handle: 0x{0}", h.ToHexString())); #endif if (!AllocatedBySuite(h)) { if (SafeNativeMethods.GlobalSize(h.Value).ToInt64() > 0L) { IntPtr hPtr = Marshal.ReadIntPtr(h.Value); if (IsValidReadPtr(hPtr) && SafeNativeMethods.GlobalSize(hPtr).ToInt64() > 0L) { SafeNativeMethods.GlobalUnlock(hPtr); } else { SafeNativeMethods.GlobalUnlock(h.Value); } } } }
private static unsafe bool EnumPiPL(IntPtr hModule, IntPtr lpszType, IntPtr lpszName, IntPtr lParam) { GCHandle handle = GCHandle.FromIntPtr(lParam); QueryFilter query = (QueryFilter)handle.Target; IntPtr hRes = UnsafeNativeMethods.FindResourceW(hModule, lpszName, lpszType); if (hRes == IntPtr.Zero) { #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format("FindResource failed for PiPL in {0}", query.fileName)); #endif return(true); } IntPtr loadRes = UnsafeNativeMethods.LoadResource(hModule, hRes); if (loadRes == IntPtr.Zero) { #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format("LoadResource failed for PiPL in {0}", query.fileName)); #endif return(true); } IntPtr lockRes = UnsafeNativeMethods.LockResource(loadRes); if (lockRes == IntPtr.Zero) { #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format("LockResource failed for PiPL in {0}", query.fileName)); #endif return(true); } #if DEBUG short fb = Marshal.ReadInt16(lockRes); // PiPL Resources always start with 1, this seems to be Photoshop's signature #endif int version = Marshal.ReadInt32(lockRes, 2); if (version != PSConstants.LatestPiPLVersion) { #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format("Invalid PiPL version in {0}: {1}, Expected version {2}", query.fileName, version, PSConstants.LatestPiPLVersion)); #endif return(true); } string entryPoint = null; string category = null; string title = null; FilterCaseInfoCollection filterInfo = null; AETEData aete = null; string enableInfo = null; int count = Marshal.ReadInt32(lockRes, 6); byte *propPtr = (byte *)lockRes.ToPointer() + 10; for (int i = 0; i < count; i++) { PIProperty *pipp = (PIProperty *)propPtr; if (pipp->vendorID != PSConstants.kPhotoshopSignature) { // The property data is padded to a 4 byte boundary. propPtr += PIProperty.SizeOf + ((pipp->propertyLength + 3) & ~3); continue; } uint propKey = pipp->propertyKey; int propertyLength = pipp->propertyLength; byte *dataPtr = propPtr + PIProperty.SizeOf; if (propKey == PIPropertyID.PIKindProperty) { if (*(uint *)dataPtr != PSConstants.FilterKind) { #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format("{0} is not a valid Photoshop Filter.", query.fileName)); #endif return(true); } } else if (propKey == query.platformEntryPoint) { entryPoint = StringUtil.FromCString(dataPtr); } else if (propKey == PIPropertyID.PIVersionProperty) { int packedVersion = *(int *)dataPtr; int major = packedVersion >> 16; int minor = packedVersion & 0xffff; if (major > PSConstants.latestFilterVersion || major == PSConstants.latestFilterVersion && minor > PSConstants.latestFilterSubVersion) { #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format("{0} requires newer filter interface version {1}.{2} and only version {3}.{4} is supported", new object[] { query.fileName, major, minor, PSConstants.latestFilterVersion, PSConstants.latestFilterSubVersion })); #endif return(true); } } else if (propKey == PIPropertyID.PIImageModesProperty) { if ((dataPtr[0] & PSConstants.flagSupportsRGBColor) != PSConstants.flagSupportsRGBColor) { #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format("{0} does not support the plugInModeRGBColor image mode.", query.fileName)); #endif return(true); } } else if (propKey == PIPropertyID.PICategoryProperty) { category = StringUtil.FromPascalString(dataPtr); } else if (propKey == PIPropertyID.PINameProperty) { title = StringUtil.FromPascalString(dataPtr); } else if (propKey == PIPropertyID.PIFilterCaseInfoProperty) { FilterCaseInfoResult result = FilterCaseInfoParser.Parse(dataPtr, propertyLength); if (result != null) { filterInfo = result.filterCaseInfo; // The actual property length may be longer than the header specifies // if the FilterCaseInfo fields are incorrectly escaped. if (propertyLength != result.propertyLength) { propertyLength = result.propertyLength; } } } else if (propKey == PIPropertyID.PIHasTerminologyProperty) { PITerminology *term = (PITerminology *)dataPtr; if (term->version == PSConstants.LatestTerminologyVersion) { #if DEBUG string aeteName = StringUtil.FromCString(dataPtr + PITerminology.SizeOf); #endif aete = ParseAETEResource(hModule, term->terminologyID); } } else if (propKey == PIPropertyID.PIEnableInfoProperty) { enableInfo = StringUtil.FromCString(dataPtr); } else if (propKey == PIPropertyID.PIRequiredHostProperty) { uint host = *(uint *)dataPtr; if (host != PSConstants.kPhotoshopSignature && host != PSConstants.AnyHostSignature) { #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format("{0} requires host '{1}'.", query.fileName, DebugUtils.PropToString(host))); #endif return(true); } } #if DEBUG else { DebugUtils.Ping(DebugFlags.PiPL, string.Format("Unsupported property '{0}' in {1}", DebugUtils.PropToString(propKey), query.fileName)); } #endif int propertyDataPaddedLength = (propertyLength + 3) & ~3; propPtr += PIProperty.SizeOf + propertyDataPaddedLength; } PluginData enumData = new PluginData(query.fileName, entryPoint, category, title, filterInfo, query.runWith32BitShim, aete, enableInfo); if (enumData.IsValid()) { query.plugins.Add(enumData); } return(true); }
private unsafe short ReadPixelsProc(IntPtr port, PSScaling *scaling, VRect *writeRect, PixelMemoryDesc *destination, VRect *wroteRect) { #if DEBUG DebugUtils.Ping(DebugFlags.ChannelPorts, string.Format("port: {0}, rect: {1}", port.ToString(), DebugUtils.PointerToString(writeRect))); #endif if (scaling == null || writeRect == null || destination == null) { return(PSError.paramErr); } if (destination->depth != 8) { return(PSError.errUnsupportedDepth); } if ((destination->bitOffset % 8) != 0) { return(PSError.errUnsupportedBitOffset); } if ((destination->colBits % 8) != 0) { return(PSError.errUnsupportedColBits); } if ((destination->rowBits % 8) != 0) { return(PSError.errUnsupportedRowBits); } int channel = port.ToInt32(); if (channel < PSConstants.ChannelPorts.Red || channel > PSConstants.ChannelPorts.SelectionMask) { return(PSError.errUnknownPort); } VRect srcRect = scaling->sourceRect; VRect dstRect = scaling->destinationRect; int srcWidth = srcRect.right - srcRect.left; int srcHeight = srcRect.bottom - srcRect.top; int dstWidth = dstRect.right - dstRect.left; int dstHeight = dstRect.bottom - dstRect.top; if (channel == PSConstants.ChannelPorts.SelectionMask) { if (srcWidth == dstWidth && srcHeight == dstHeight) { FillSelectionMask(destination, filterImageProvider.Mask, srcRect); } else if (dstWidth < srcWidth || dstHeight < srcHeight) // scale down { if ((scaledSelectionMask == null) || scaledSelectionMask.Width != dstWidth || scaledSelectionMask.Height != dstHeight) { if (scaledSelectionMask != null) { scaledSelectionMask.Dispose(); scaledSelectionMask = null; } scaledSelectionMask = new MaskSurface(dstWidth, dstHeight); scaledSelectionMask.SuperSampleFitSurface(filterImageProvider.Mask); } FillSelectionMask(destination, scaledSelectionMask, dstRect); } else if (dstWidth > srcWidth || dstHeight > srcHeight) // scale up { if ((scaledSelectionMask == null) || scaledSelectionMask.Width != dstWidth || scaledSelectionMask.Height != dstHeight) { if (scaledSelectionMask != null) { scaledSelectionMask.Dispose(); scaledSelectionMask = null; } scaledSelectionMask = new MaskSurface(dstWidth, dstHeight); scaledSelectionMask.BicubicFitSurface(filterImageProvider.Mask); } FillSelectionMask(destination, scaledSelectionMask, dstRect); } } else { if (srcWidth == dstWidth && srcHeight == dstHeight) { FillChannelData(channel, destination, filterImageProvider.Source, srcRect); } else if (dstWidth < srcWidth || dstHeight < srcHeight) // scale down { if ((scaledChannelSurface == null) || scaledChannelSurface.Width != dstWidth || scaledChannelSurface.Height != dstHeight) { if (scaledChannelSurface != null) { scaledChannelSurface.Dispose(); scaledChannelSurface = null; } scaledChannelSurface = new Surface(dstWidth, dstHeight); scaledChannelSurface.SuperSampleFitSurface(filterImageProvider.Source); } FillChannelData(channel, destination, scaledChannelSurface, dstRect); } else if (dstWidth > srcWidth || dstHeight > srcHeight) // scale up { if ((scaledChannelSurface == null) || scaledChannelSurface.Width != dstWidth || scaledChannelSurface.Height != dstHeight) { if (scaledChannelSurface != null) { scaledChannelSurface.Dispose(); scaledChannelSurface = null; } scaledChannelSurface = new Surface(dstWidth, dstHeight); scaledChannelSurface.BicubicFitSurface(filterImageProvider.Source); } FillChannelData(channel, destination, scaledChannelSurface, dstRect); } } if (wroteRect != null) { *wroteRect = dstRect; } return(PSError.noErr); }
private void RecoverHandleSpace(int size) { #if DEBUG DebugUtils.Ping(DebugFlags.HandleSuite, string.Format("size: {0}", size)); #endif }
/// <summary> /// Loads the 8bf filters from the specified file. /// </summary> /// <param name="fileName">The plug-in file name.</param> /// <returns>An enumerable collection containing the filters within the plug-in.</returns> /// <exception cref="System.ArgumentNullException"><paramref name="fileName"/> is null.</exception> internal static IEnumerable <PluginData> LoadFiltersFromFile(string fileName) { if (fileName == null) { throw new ArgumentNullException(nameof(fileName)); } ProcessorArchitecture platform = PEFile.GetProcessorArchitecture(fileName); if (!DllProcessorArchtectureIsSupported(platform)) { // Ignore any DLLs that cannot be used on the current platform. return(System.Linq.Enumerable.Empty <PluginData>()); } List <PluginData> pluginData = new List <PluginData>(); // Use LOAD_LIBRARY_AS_DATAFILE to prevent a BadImageFormatException from being thrown if the file is a different processor architecture than the parent process. using (SafeLibraryHandle dll = UnsafeNativeMethods.LoadLibraryExW(fileName, IntPtr.Zero, NativeConstants.LOAD_LIBRARY_AS_DATAFILE)) { if (!dll.IsInvalid) { QueryFilter queryFilter = new QueryFilter(fileName, platform); GCHandle handle = GCHandle.Alloc(queryFilter, GCHandleType.Normal); try { IntPtr callback = GCHandle.ToIntPtr(handle); if (UnsafeNativeMethods.EnumResourceNamesW(dll, "PiPl", new UnsafeNativeMethods.EnumResNameDelegate(EnumPiPL), callback)) { queryFilter = (QueryFilter)GCHandle.FromIntPtr(callback).Target; pluginData.AddRange(queryFilter.plugins); } else if (UnsafeNativeMethods.EnumResourceNamesW(dll, "PiMI", new UnsafeNativeMethods.EnumResNameDelegate(EnumPiMI), callback)) { // If there are no PiPL resources scan for Photoshop 2.5's PiMI resources. queryFilter = (QueryFilter)GCHandle.FromIntPtr(callback).Target; pluginData.AddRange(queryFilter.plugins); } #if DEBUG else { DebugUtils.Ping(DebugFlags.PiPL, string.Format("EnumResourceNames(PiPL, PiMI) failed for {0}", fileName)); } #endif } finally { if (handle.IsAllocated) { handle.Free(); } } } } int count = pluginData.Count; if (count > 1) { // If the DLL contains more than one filter, add a list of all the entry points to each individual filter. // Per the SDK only one entry point in a module will display the about box the rest are dummy calls so we must call all of them. string[] entryPoints = new string[count]; for (int i = 0; i < count; i++) { entryPoints[i] = pluginData[i].EntryPoint; } for (int i = 0; i < count; i++) { pluginData[i].ModuleEntryPoints = new ReadOnlyCollection <string>(entryPoints); } } return(pluginData); }
private unsafe short PropertyGetProc(uint signature, uint key, int index, IntPtr *simpleProperty, Handle *complexProperty) { #if DEBUG DebugUtils.Ping(DebugFlags.PropertySuite, string.Format("Sig: {0}, Key: {1}, Index: {2}", DebugUtils.PropToString(signature), DebugUtils.PropToString(key), index.ToString())); #endif if (signature != PSConstants.kPhotoshopSignature) { return(PSError.errPlugInPropertyUndefined); } short error = PSError.noErr; byte[] bytes = null; switch (key) { case PSProperties.BigNudgeH: case PSProperties.BigNudgeV: error = GetSimpleProperty(simpleProperty, new Fixed16(PSConstants.Properties.BigNudgeDistance).Value); break; case PSProperties.Caption: if (complexProperty != null) { *complexProperty = HandleSuite.Instance.NewHandle(0); } break; case PSProperties.ChannelName: string name = string.Empty; switch (index) { case 0: name = Resources.RedChannelName; break; case 1: name = Resources.GreenChannelName; break; case 2: name = Resources.BlueChannelName; break; case 3: name = Resources.AlphaChannelName; break; default: return(PSError.errPlugInPropertyUndefined); } bytes = Encoding.ASCII.GetBytes(name); error = CreateComplexPropertyHandle(complexProperty, bytes); break; case PSProperties.Copyright: case PSProperties.Copyright2: error = GetSimpleProperty(simpleProperty, false); break; case PSProperties.EXIFData: case PSProperties.XMPData: if (complexProperty != null) { // If the complexProperty is not IntPtr.Zero we return a valid zero byte handle, otherwise some filters will crash with an access violation. *complexProperty = HandleSuite.Instance.NewHandle(0); } break; case PSProperties.GridMajor: error = GetSimpleProperty(simpleProperty, new Fixed16(PSConstants.Properties.GridMajor).Value); break; case PSProperties.GridMinor: error = GetSimpleProperty(simpleProperty, PSConstants.Properties.GridMinor); break; case PSProperties.ImageMode: error = GetSimpleProperty(simpleProperty, PSConstants.plugInModeRGBColor); break; case PSProperties.InterpolationMethod: error = GetSimpleProperty(simpleProperty, PSConstants.Properties.InterpolationMethod.NearestNeghbor); break; case PSProperties.NumberOfChannels: error = GetSimpleProperty(simpleProperty, numberOfChannels); break; case PSProperties.NumberOfPaths: error = GetSimpleProperty(simpleProperty, 0); break; case PSProperties.WorkPathIndex: case PSProperties.ClippingPathIndex: case PSProperties.TargetPathIndex: error = GetSimpleProperty(simpleProperty, PSConstants.Properties.NoPathIndex); break; case PSProperties.RulerUnits: error = GetSimpleProperty(simpleProperty, PSConstants.Properties.RulerUnits.Pixels); break; case PSProperties.RulerOriginH: case PSProperties.RulerOriginV: error = GetSimpleProperty(simpleProperty, new Fixed16(0).Value); break; case PSProperties.SerialString: bytes = Encoding.ASCII.GetBytes(HostSerial); error = CreateComplexPropertyHandle(complexProperty, bytes); break; case PSProperties.URL: if (complexProperty != null) { *complexProperty = HandleSuite.Instance.NewHandle(0); } break; case PSProperties.Title: case PSProperties.UnicodeTitle: string title = "temp.pdn"; // some filters just want a non empty string if (key == PSProperties.UnicodeTitle) { bytes = Encoding.Unicode.GetBytes(title); } else { bytes = Encoding.ASCII.GetBytes(title); } error = CreateComplexPropertyHandle(complexProperty, bytes); break; case PSProperties.WatchSuspension: error = GetSimpleProperty(simpleProperty, false); break; case PSProperties.DocumentWidth: error = GetSimpleProperty(simpleProperty, documentWidth); break; case PSProperties.DocumentHeight: error = GetSimpleProperty(simpleProperty, documentHeight); break; case PSProperties.ToolTips: error = GetSimpleProperty(simpleProperty, true); break; case PSProperties.HighDpi: error = GetSimpleProperty(simpleProperty, highDpi); break; default: return(PSError.errPlugInPropertyUndefined); } return(error); }
private void BufferUnlockProc(IntPtr bufferID) { #if DEBUG DebugUtils.Ping(DebugFlags.BufferSuite, string.Format("Buffer: 0x{0}", bufferID.ToHexString())); #endif }