我最近遇到过一种情况,我需要创建一个通用方法来从字节数组中读取数据类型.
我创建了以下类:
public class DataStream
{
public int Offset { get; set; }
public byte[] Data { get; set; }
public T Read<T>() where T : struct
{
unsafe
{
int dataLen = Marshal.SizeOf( typeof( T ) );
IntPtr dataBlock = Marshal.AllocHGlobal( dataLen );
Marshal.Copy( Data, Offset, dataBlock, dataLen );
T type = *( ( T* )dataBlock.ToPointer() );
Marshal.FreeHGlobal( dataBlock );
Offset += dataLen;
return type;
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,除了解除分配问题,此代码不会使用此消息进行编译:
Cannot take the address of, get the size of, or …
我正在重构我们目前使用的库,我遇到了以下问题.
我们曾经有过以下的东西:
class Blah
{
float[][] data;
public float[] GetDataReference(int index)
{
return data[index];
}
}
Run Code Online (Sandbox Code Playgroud)
由于各种原因,我已经用1维数组版本替换了这个锯齿状阵列版本,连接内部数组.我的问题是:我怎样才能返回对子数组的引用data?
class Blah
{
float[] data;
int rows;
public float[] GetDataReference(int index)
{
// Return a reference data from offset i to offset j;
}
}
Run Code Online (Sandbox Code Playgroud)
我认为不安全和指针的东西可能有用,是否可行?
在C#项目中,我需要通过在结构中放置引用来传递对象参数.即我有一个传递给调度员的结构
struct SOMESTRUCT
{
public int lpObject;
}
Run Code Online (Sandbox Code Playgroud)
其中lpObject包含指向自定义对象的指针
class SomeClass
{
private string foo;
}
Run Code Online (Sandbox Code Playgroud)
并且SOMESTRUCT结构从方法传递到方法,最终到达我的代码.我无法修改执行流程和奇怪的SOMSTRUCT系统,所以我猜测唯一的解决方案是将我的对象转换为这样的指针:
var myObject = new SomeClass();
GCHandle GC = GCHandle.Alloc(myObject, GCHandleType.Pinned);
int myRef = GC.AddrOfPinnedObject().ToInt32();
GC.Free();
SOMESTRUCT struct;
struct.lpObject = myRef;
someMethod(struct);
Run Code Online (Sandbox Code Playgroud)
但是,我无法弄清楚如何从lpObject字段中检索myObject成员.像这样的东西:
SomeClass myObject = CastPointerToObject(struct.myRef) as SomeClass;
Run Code Online (Sandbox Code Playgroud)
有办法做到这一点,还是不可能?如何告诉垃圾收集器处理对象?我应该创建一个新的垃圾收集对象并按字段复制数据字段吗?
TYIA,
我正在使用C#winforms项目中的"不安全"代码创建(然后更改)位图.这是每30ms左右完成的.我遇到的问题是"噪声"或随机像素有时会出现在结果位图中,我没有特别改变任何东西.
例如,我创建了一个100x100的位图.使用BitmapData和LockBits,我遍历位图并将某些像素更改为特定颜色.然后我UnlockBits设置一个图片框来使用图像.我设置的所有像素都是正确的,但我没有特别设置的像素有时看似是随机颜色.
如果我设置每个像素,噪音就会消失.但是,出于性能原因,我宁愿只设置最小数量.
任何人都可以解释为什么这样做?
这是一些示例代码:
// Create new output bitmap
Bitmap Output_Bitmap = new Bitmap(100, 100);
// Lock the output bitmap's bits
Rectangle Output_Rectangle = new Rectangle(
0,
0,
Output_Bitmap.Width,
Output_Bitmap.Height);
BitmapData Output_Data = Output_Bitmap.LockBits(
Output_Rectangle,
ImageLockMode.WriteOnly,
PixelFormat.Format32bppRgb);
const int PixelSize = 4;
unsafe
{
for (int y = 0; y < Output_Bitmap.Height; y++)
{
for (int x = 0; x < Output_Bitmap.Width/2; x++)
{
Byte* Output_Row = (Byte*)Output_Data.Scan0 + y * Output_Data.Stride;
Output_Row[(x …Run Code Online (Sandbox Code Playgroud) 我最近遇到了这样一个事实:在使用C#/ Mono中的某些概念时,我需要指定"不安全"选项.我不仅需要在我的代码中指定选项,我还必须在编译时指定它,这会调用"此代码本质上不安全且使用风险"的感觉.这里奇怪的是DllImport不需要不安全标志,所以我可以在我的"安全代码"中创建我想要的段错误.有没有理由避免我忽略的不安全代码?
我在DLL中有一个函数:
char __usercall MyUserCallFunction<al>(int arg1<esi>)
Run Code Online (Sandbox Code Playgroud)
因为我讨厌自己,所以我想使用P/Invoke在C#中调用它.
通常这可以通过获取函数委托来完成,la:
[UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Auto, SetLastError = true)]
public delegate char DMyUserCallFunction(IntPtr a1);
Run Code Online (Sandbox Code Playgroud)
然后通过执行以下操作来调用它:
var MyFunctionPointer = (DMyUserCallFunction)Marshal.GetDelegateForFunctionPointer(AddressOfFunction, typeof(DMyUserCallFunction));
MyFunctionPointer(IntPtr.Zero);
Run Code Online (Sandbox Code Playgroud)
但是,对于自定义用户调用约定,这将导致程序崩溃.有没有某种方法我可以使用不安全的代码或某种将代理放在适当位置的包装函数来做到这一点,但是不强迫我编写C++ DLL?
谢谢!
编辑:
正如dtb所建议的,我创建了一个非常小的C++ DLL,我通过P/Invoke来调用该函数.对于任何好奇的人来说,C++中的函数最终看起来像:
extern "C" __declspec(dllexport) int __stdcall callUsercallFunction(int functionPointer, int arg1 )
{
int retVal;
_asm
{
mov esi, arg1
call functionPointer
mov retVal, eax
}
//Fake returning al, the lower byte of eax
return retVal & 0x000000FF;
}
Run Code Online (Sandbox Code Playgroud) 我需要将1027*768位图渲染到客户端窗口(相同大小),并且我没有超过10-15 ms来完成此任务.我使用bufferedGraphics从分配bufferedGraphicsContect对象,仍然看到巨大的性能问题.
我使用不安全的代码来执行我的复制操作,并找到了令人难以置信的结果.我知道Graphics/BufferedGraphics对象应该在内存中有某种绘图表面.我想知道是否有人能指出我如何使用Marshal或其他一些不安全的低级方法写入这个表面的正确方向.
我正在移植旧的c#图形应用程序.我知道c#不是为重型图形设计的,并且有比GDI +更好的工具,不幸的是我没有那些奢侈品.
这就是我到目前为止所提出的......任何有用的见解都是非常有用的.
byte[] _argbs = null;
static readonly Bitmap _bmUnderlay = Properties.Resources.bg;
static Bitmap _bmpRender = new Bitmap(1024, 768, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
int bmpHeight = Properties.Resources.bg.Height;
int bmpWidth = Properties.Resources.bg.Width;
static BufferedGraphicsContext _bgc = new BufferedGraphicsContext();
internal unsafe void FillBackBuffer(Point cameraPos)
{
// lock up the parts of the original image to read (parts of it)
System.Drawing.Imaging.BitmapData bmd = _bmUnderlay.LockBits(
new Rectangle(cameraPos.X, cameraPos.Y, 1024, …Run Code Online (Sandbox Code Playgroud) 在这里,我正在尝试使用C#的不安全功能:http://ideone.com/L9uwZ5
我知道,在C#中这样的方式是最糟糕的,我想承认,主题中有一些信息.看看"变态"这个词.
我想在C#中实现快速排序,如pure-C方式(甚至不是C++).它可能很疯狂,但只是想深入了解不安全的C#的可能性.
我一直在尝试使用stackalloc运算符.我知道,这是来自堆栈的分配,而不是来自堆的分配,这就是我执行程序失败的原因.
但是当我在这个程序中没有看到任何异常/错误时我很困惑.
另外,正如您所看到的代码的注释部分:
struct Header
{
internal int* data;
};
Header* object_header = stackalloc Header[sizeof(Header)];
object_header->data = stackalloc int[length];
Run Code Online (Sandbox Code Playgroud)
我无法用最后一行编译它.C#编译器告诉我,在这个表达式中无法使用stackalloc.为什么?data是int*类型,为什么会出现错误?
我只想使用堆栈框架而不是使用堆.我知道,还有另一种方法,但它是来自堆的分配.
int*[] data = new int*[length * sizeof(int)];
IntPtr result = Marshal.AllocHGlobal(Marshal.SizeOf(length * sizeof(int)));
Marshal.WriteInt32(result, 0);
for(int i = 0; i < length * sizeof(int); i++) d[i] = (int*)result;
Run Code Online (Sandbox Code Playgroud)
例如,但它不是堆栈分配.
我怎么能用C#语言中的stack-allocation和pure-C style语法显式地解决我的perversion任务.
C#不是为这样的目标而创建的,而且这些功能很愚蠢 - 我知道,但主要的问题不是重要性,而是关于这些功能.
我经常环顾四周,似乎找不到与我正在做的事情相似的解决方案.我有两个应用程序,一个本机C++应用程序和一个托管C#应用程序.C++应用程序分配在内存管理器中使用的字节池.在此内存管理器中分配的每个对象都有一个标头,每个标头都有一个char*,指向给定对象的名称.C#app充当此内存的查看器.我使用内存映射文件允许C#app在C++应用程序运行时读取内存.我的问题是我试图从头结构中读取对象的名称并将其显示在C#中(或者只是将它存储在String中,无论如何).使用不安全的代码,我能够在四个字节组成转换char*成一个IntPtr,将其转换成一个void*,并调用Marshal.PtrToStringAnsi.这是代码:
IntPtr namePtr = new IntrPtr(BitConverter.ToInt32(bytes, index));
unsafe
{
void* ptr = namePtr.ToPointer();
char* cptr = (char*)ptr;
output = Marshal.PtrToStringAnsi((IntPtr)ptr);
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,bytes是从内存映射文件中读取的数组,它表示本机应用程序创建的所有字节池,并且index是名称指针的第一个字节的索引.
我已经验证,在托管方面,调用返回namePtr.ToPointer()的地址正是本机应用程序中名称指针的地址.如果这是本机代码,我会简单地转换ptr为a char*并且它会没问题,但在托管代码中,我已经阅读过,我必须使用Marshaller来执行此操作.
此代码会产生不同的结果.有时候cptr是null,有时它指向,有时它指向\0一些亚洲字符(当通过该PtrToStringAnsi方法运行时产生看似无关的字符).我认为这可能是一fixed件事,但ToPointer产生一个固定的指针.有时候,在char*调试者的演员表示Unable to evaluate the expression. The pointer is not valid或类似的东西之后(重新调整每一个变化的东西都不容易).有时我在读取内存时会遇到访问冲突,导致我进入C++方面.
在C++方面,我认为实际读取内存可能存在一些问题,因为虽然存储指针的内存是内存映射文件的一部分,但构成文本的实际字节却不是.所以我看看如何更改对内存的读/写访问权限(在Windows上,请注意)并在Windows库中找到VirtualProtect方法,我用它将内存访问权限更改为PAGE_EXECUTE_WRITECOPY,我认为这会给任何应用程序有一个指向该地址的指针将能够至少读取那里的内容.但这也没有解决问题.
简而言之:
我有一个指针(在C#中)到char数组中的第一个char(在C++应用程序中分配)并且我试图将该数组的char读入C#中的字符串.
编辑:
源标头如下所示:
struct AllocatorHeader
{
// These bytes are reserved, and their …Run Code Online (Sandbox Code Playgroud) 有没有办法获得固定大小的缓冲区的长度?
就像是:
public struct MyStruct
{
public unsafe fixed byte buffer[100];
public int foo()
{
return sizeof(buffer); // Compile error.
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法完成这样的事情?