ich habe mal die Methode Clone wie von MrSparkle genannt versucht, und diese funktionierte bei mir ohne Probleme (8bppindexed).
public static Bitmap Clone(Bitmap bitmap)
{
if (bitmap == null)
throw new ArgumentNullException("bitmap");
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
return bitmap.Clone(rect, bitmap.PixelFormat);
}
Sollte diese trotzdem nicht funktionieren, kannst du die Daten auch manuell klonen:
public static Bitmap Clone2(Bitmap bitmap)
{
if (bitmap == null)
throw new ArgumentNullException("bitmap");
Bitmap clone;
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat);
try
{
clone = new Bitmap(bmpData.Width, bmpData.Height, bmpData.Stride, bmpData.PixelFormat, bmpData.Scan0);
}
finally
{
bitmap.UnlockBits(bmpData);
}
clone.Palette = bitmap.Palette;
return clone;
}
Ich hoffe das hilft dir weiter zum Thema klonen.
Warum das manuelle Kopieren von dir nicht funktioniert liegt am Layout der Farbstruct. Diese ist nicht ARGB sondern BGRA (siehe RGBQUAD):
Bei Dequeue wird die Verkettete Liste um eine Element verschoben (effektiv: last wird zu last.next). Dabei wird diese Node zum neuen "Anker" der Liste und wird NICHT vom GC abgeräumt - auch nicht das darin enthaltene Element.
der optionale Parameter ist nur dann optional, wenn du weder ihn, noch Parameter rechts von ihm angibst. Da du den Paramter "Zusaetzliches" angibst, musst du auch "JaNein" angeben (in vb kann man glaube ich, auch optionale Parameter in der Mitte weglassen).
Was funktionieren würde, wäre gar keinen Parameter anzugeben.
public static class EqualsExtensions
{
public static bool EqualsOneOf(this object first, params object[] others)
{
return others.Any(o => Object.Equals(first, o));
}
public static bool EqualsOneOf<T>(this IEquatable<T> first, params T[] others)
{
if (Object.ReferenceEquals(first, null))
return others.Any(o => Object.ReferenceEquals(o, null));
return others.Any(o => first.Equals(o));
}
}
Wäre diese Implementierung nicht "korrekter"? Die Methode soll schauen ob "first" zu einem der folgenden Objekte equivalent ist. Dies bedeut aber streng genommen nicht, dass diese auch IEquatable<T> implementieren, sondern nur vom Typen T sein müssen.
ich hab das Projekt mal umgebaut. Die .dll muss nurnoch ins Ausgabe-Verzeichnis des .NET Projektes kopiert werden.
Spooky
PS: StringBuilder braucht man wenn man einen Buffer _übergibt_ in den geschrieben werden soll. Diese Funktionen haben dann meistens noch einen Parameter, der die Bufferlänge angibt zb:
void FillMe(char * buffer, int length, ...);
->
void FillMe(StringBuilder b, int length, ...);
Wenn es um fixe Strings geht braucht man keinen StringBuilder anlegen.
edit:
Der .NET Typ DateTime und der C++ Typ time_t sind wohl doch nicht kompatibel, daher musst du wohl einen kompatiblen Typen suchen oder Hilfsmethoden implementieren.
DateTime ist intern ein .NET long. Der C++ Typ time_t (time.h), der intern ebenfalls ein 64bit Integer ist könnte dafür ggf verwerdendet werden. Time Beispiel
Wie zommi schon gesagt hat, ist char * der Typ den du verwenden solltest. Ggf kannst du auch wchar_t * (Unicode) nehmen:
Neues Projekt anlegen (Visual C++ -> Win32-Projekt) mit Anwendungstyp "Dll". Andere Optionen lassen, wie sie sind.
In der erzeugten .cpp Datei kannst du nun zB eine Funktion so deklarieren:
// Gehört eigentlich in die .h Datei
extern "C"
{
BOOL __declspec(dllexport) __stdcall CheckKey(const unsigned char *key);
}
BOOL __stdcall InternalHelper(const unsigned char *key);
// Ende .h Datei
// Kann von aussen aufgerufen
BOOL __stdcall CheckKey(const unsigned char *key) {
return InternalHelper(key);
}
// Nur intern verwendbar
BOOL __stdcall InternalHelper(const unsigned char *key) {
return FALSE;
}
Dabei ist zu beachten, dass Funktionen die mit __declspec(dllexport) deklariert sind, nach aussen exportiert werden (d.h. Hilfsmethoden ohne dieses Tag können auch von aussen nicht aufgerufen werden).
IntPtr strData = new IntPtr(unchecked(plstr.ToInt64() + 4));
geändert werden um auch unter 64bit zu funktionieren. Ggf könnte man die Offset Operation noch in eine sperate Methode mit Over-/Underflow Check auslagern.
public class Reference<T> where T : struct
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
protected T value;
public Reference()
{
}
public Reference(T value)
{
this.value = value;
}
public static implicit operator T(Reference<T> value)
{
return value.value;
}
public static implicit operator Reference<T>(T value)
{
return new Reference<T>(value);
}
public T Value
{
get { return value; }
set { this.value = value; }
}
public override string ToString()
{
return value.ToString();
}
public override int GetHashCode()
{
return value.GetHashCode();
}
public override bool Equals(object obj)
{
return (obj is Reference<T>) && value.Equals(((Reference<T>)obj).value);
}
}
deine Wrapper-Klasse ist genau richtig um aus einem Werttypen einen Referenztypen zu machen.
Nullable<T> macht aus einem Werttypen einen null-baren Typen, aber keinen Referenztyp.
Wenn der berechnete Wert eines Zählers von zwei Zählerlesevorgängen abhängt, gibt der erste Lesevorgang 0,0 zurück. Das Zurücksetzen der Leistungsindikatoreigenschaften, um einen anderen Indikator anzugeben, entspricht dem Erstellen eines neuen Leistungsindikators, und beim ersten Lesevorgang mit den neuen Eigenschaften wird 0,0 zurückgegeben. Die empfohlene Verzögerungszeit zwischen Aufrufen der NextValue-Methode beträgt eine Sekunde, um es dem Indikator zu ermöglichen, den nächsten inkrementellen Lesevorgang auszuführen.
PerformanceCounter pCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
pCounter.NextValue();
while (true)
{
Thread.Sleep(1000);
Console.WriteLine(pCounter.NextValue());
}
Wie dN!3L schon geschrieben hat ist ReferenceEquals (oder der cast nach Object) eine Lösung, hier in einem einfachen Beispiel:
class Point
{
public double X { get; set; }
public double Y { get; set; }
public static bool operator ==(Point a, Point b)
{
if (ReferenceEquals(a, b))
{
return true;
}
if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
{
return false;
}
return ((a.X == b.X) && (a.Y == b.Y));
}
public static bool operator !=(Point a, Point b)
{
return (!(a == b));
}
}
Leider ist das Ergebnis weiterhin, dass result.bmp genauso groß ist und die gleiche Auflösung hat wie test-1.bmp. Hat jemand einen weiteren Tipp auf LAger, was hier schief läuft?
Bei mir liefert die Clone Methode schon ein 32-bit Bild zurück. Von daher ist es nur logisch, dass die Datei dann auch 32-bit ist.
Du könntest diese Methode verwenden:
public static Bitmap ConvertBitmap(Bitmap bitmap, PixelFormat format)
{
if (bitmap == null)
{
throw new ArgumentNullException("bitmap");
}
Bitmap result = null;
try
{
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
result = new Bitmap(bitmap.Width, bitmap.Height, format);
BitmapData dstData = result.LockBits(rect, ImageLockMode.WriteOnly, format);
try
{
BitmapData srcData = new BitmapData();
srcData.Scan0 = dstData.Scan0;
srcData.Stride = dstData.Stride;
bitmap.LockBits(rect, ImageLockMode.ReadOnly | ImageLockMode.UserInputBuffer, format, srcData);
bitmap.UnlockBits(srcData);
}
finally
{
result.UnlockBits(dstData);
}
}
catch
{
if (result != null)
{
result.Dispose();
}
throw;
}
return result;
}
Dabei solltest du jedoch beachten, dass GDI+ bzw .NET kein Format16bppArgb1555 unterstützen. D.h. du musst dich mit Format16bppRgb555 oder Format16bppRgb565 begnügen.
Spooky
Edit: Methode geändert, sodass keine 3. temporäre Bitmap erzeugt wird. So schreibt die eine Bitmap die Pixeldaten direkt in die andere.
von den Namen der Datentypen her würde ich die Klasse so definieren:
[StructLayout(LayoutKind.Sequential, Size = 20)] // event. in der dllimport dann als "[in,out] S_RESOLUTION_PARAMS ResParam" aufrufen
public class S_RESOLUTION_PARAMS
{
public short wOffsetX; // i16 X offset of ROI (relative to visible area).
public short wOffsetY; // i16 Y offset of ROI (relative to visible area).
public ushort wSizeX; // u16 X size (width, columns) of ROI.
public ushort wSizeY; // u16 Y size (height, lines) of ROI.
public uint dwSkip; // u32 X- and Y- Skip Settings (see XY_SKIP_NONE).
public uint dwBin; // u32 X- and Y- Bin Settings (see XY_BIN_NONE).
public byte bKeepExposure; // u08 keep constant exposure (true=yes, false=no)
};
Durch die Angabe der absoluten Größe kannst du das Array weglassen (welches eh nur fürs Alignment ist).
Zu der C++ Anweisung:
"pResCap = (S_RESOLUTION_CAPS*) new (BYTE[dwCapSize]);"
In C++ kannst du Speicher mit dem new Operator allokieren. In dem Fall wird ein byte-array der Größe "dwCapSize" allokiert. Durch den Cast (S_RESOLUTION_CAPS*) kann nun der Speicher so verwendet werden, als sei es ein Array von "S_RESOLUTION_CAPS". new
public sealed class Polygon
{
public Header header;
public Parms parms;
public PointD[] points;
}
[StructLayout(LayoutKind.Sequential, Size = 1)]
public struct Header { }
[StructLayout(LayoutKind.Sequential, Size = 1)]
public struct Parms { }
public struct PointD
{
public double x;
public double y;
}
internal sealed class PolygonMarshaler : ICustomMarshaler
{
private unsafe struct Poly
{
public Header header;
public Parms parms;
public ushort pointCount;
public fixed PointD points[1];
}
private static ICustomMarshaler m = new PolygonMarshaler();
private static ICustomMarshaler GetInstance(string s)
{
return m;
}
#region ICustomMarshaler Member
public void CleanUpManagedData(object ManagedObj)
{
}
public void CleanUpNativeData(IntPtr pNativeData)
{
Marshal.FreeHGlobal(pNativeData);
}
public unsafe int GetNativeDataSize()
{
return sizeof(Poly);
}
public unsafe IntPtr MarshalManagedToNative(object ManagedObj)
{
if (!(ManagedObj is Polygon))
return IntPtr.Zero;
Polygon polygon = (Polygon)ManagedObj;
int size = sizeof(Poly);
if ((polygon.points != null) && (polygon.points.Length > 1))
size += ((polygon.points.Length - 1) * sizeof(PointD));
Poly* ptr = (Poly*)Marshal.AllocHGlobal(size);
ptr->header = polygon.header;
ptr->parms = polygon.parms;
ptr->pointCount = (ushort)(polygon.points == null ? 0 : polygon.points.Length);
for (int i = 0; i < ptr->pointCount; i++)
ptr->points[i] = polygon.points[i];
return (IntPtr)ptr;
}
public unsafe object MarshalNativeToManaged(IntPtr pNativeData)
{
if (pNativeData == IntPtr.Zero)
return null;
Polygon result = new Polygon();
Poly* ptr = (Poly*)pNativeData;
result.header = ptr->header;
result.parms = ptr->parms;
result.points = new PointD[ptr->pointCount];
for (int i = 0; i < ptr->pointCount; i++)
result.points[i] = ptr->points[i];
return result;
}
#endregion
}
Hier fehlen noch die konkreten Implementierungen von Header und Parms.
Ich hoffe du kannst damit einen Einstieg finden. Vielleicht lässt sich das auch eleganter nur unter der Verwendung der unsafe struct Poly lösen, kommt ganz drauf an, ob und wie du die eigentliche Klasse verwenden willst.
der Member points ist kein Zeiger auf ein PointArray sondern ein in die Struct eingebettetes Array von konstanter Größe 1.
Dadurch kann man wie bei einem Array auf die Punkte zugreifen. Es muss natürlich, wie Th69 schon geschrieben hatte, für jeden weiteren Punkt auch mehr Speicher allokiert werden:
Dieser Code erzeugt keinen Zeiger auf den ersten Buffer, sondern zwei von einander komplett unabhängige Buffer.
Die wohl sinnigste Deklaration wäre (wie schon gesagt) ref IntPtr.
Allerdings kommt dann das nächste Problem ...
In deinem Code wird der allokierte Speicher nicht wieder freigegeben, was man natürlich noch einbauen könnte. Jedoch wird einem der Zeiger auf den allokierten Speicher ...
*buffer+=netLen;
unter der Nase weg verändert ... (guter Stil?). Zwar wird der veränderte Wert in len wieder zurückgegeben, aber nun muss man entweder wieder rückwerts rechnen, oder sich den Zeiger doppelt vorhalten um auf die Daten zuzugreifen und den Speicher wieder freizugeben.
Wenn ich eine Funktion mit einem Buffer habe, gehe ich davon aus, dass der Buffer gefüllt wird mit Daten. Dabei kann ich ein ggf ein Offset angeben und die Länge des Buffers. Aber eine Funktion sollte dem Aufrufer nicht die Zeiger "verbiegen".
Am besten nach den Konstanten suchen, und die Daten-Typen beachten (signed/unsigned). Mit Hilfe der BitConverter Klasse sollte das recht einfach gehen.