我正在使用webclient从网址获取图片数据,并尝试使用它生成视频:
//http://www.codeproject.com/Articles/7388/A-Simple-C-Wrapper-for-the-AviFile-Library
WebClient client = new WebClient();
System.Net.WebRequest request = System.Net.WebRequest.Create(images);
System.Net.WebResponse response = request.GetResponse();
System.IO.Stream responseStream = response.GetResponseStream();
Bitmap bitmap = new Bitmap(responseStream);
//create a new AVI file
AviManager aviManager = new AviManager(@"C:\Users\Laptop\Documents\tada.avi", false);
//add a new video stream and one frame to the new file
//set IsCompressed = false
VideoStream aviStream = aviManager.AddVideoStream(false, 2, bitmap);
aviManager.Close();
但它削减了以下内容。在这一行的图书馆
int result = Avi.AVIFileCreateStream(aviFile, out aviStream, ref strhdr);
我收到以下错误:
System.AccessViolationException:'尝试读取或写入受保护的 记忆。这通常表明其他内存已损坏。'
答案 0 :(得分:1)
你现在可能有“Any CPU
”所以你的应用程序会被编译/运行为64位进程(在64位Windows版本上)。
问题似乎是AVI Wrapper库可能从未使用64位.NET应用程序进行测试....它没有正确定义“pinvoke”定义,因此参数被正确地推送/弹出在进行64位API调用时进行堆栈。
将您的项目设置“平台目标”更改为x86 ...以便您可以避免此问题....并且可以在32位模式下调用“avifil32.dll”。
Windows确实附带了32位和64位的AVI库,因此理论上可以在64位进程时调用AVI库....但是您需要正确定义互操作/编组pinvoke。
在32位(Microsoft使用ILP32数据模型)......
在64位(Microsoft使用LLP64或P64数据模型)....
(见https://msdn.microsoft.com/en-us/library/windows/desktop/aa384083(v=vs.85).aspx)
经常发生的错误是“pinvoke”定义在定义指针类型时使用了“int”,而不是更正确的IntPtr
类型。
因此,“call”在32bit上运行正常(因为“int”与“指针”的大小相同)....而在64bit上它们的大小不同。
当你64位时其他的东西也会改变...比如默认的边界对齐...这可以改变结构中类型的偏移 - 所以你在定义你的pinvoke c#结构时必须要小心......所以他们匹配。
如果您对函数调用AVIFileCreateStream
感兴趣,其WIN32签名如下:
STDAPI AVIFileCreateStream(
PAVIFILE pfile,
PAVISTREAM *ppavi,
AVISTREAMINFO *psi
);
其参数的“类型”是:
typedef IAVIFile *PAVIFILE; // i.e. just a pointer
typedef IAVIStream *PAVISTREAM; // i.e. just a pointer
typedef struct {
DWORD fccType;
DWORD fccHandler;
DWORD dwFlags;
DWORD dwCaps;
WORD wPriority;
WORD wLanguage;
DWORD dwScale;
DWORD dwRate;
DWORD dwStart;
DWORD dwLength;
DWORD dwInitialFrames;
DWORD dwSuggestedBufferSize;
DWORD dwQuality;
DWORD dwSampleSize;
RECT rcFrame;
DWORD dwEditCount;
DWORD dwFormatChangeCount;
TCHAR szName[64];
} AVISTREAMINFO;
该封装库使用以下内容将.NET“pinvoke”定义为AVIFileCreateStream
:
//Create a new stream in an open AVI file
[DllImport("avifil32.dll")]
public static extern int AVIFileCreateStream(
int pfile,
out IntPtr ppavi,
ref AVISTREAMINFO ptr_streaminfo);
您可以立即看到第一个参数定义错误。
当“调用”时....只有4个字节将被放入堆栈中,用于第一个参数...而不是8,然后用于第二个参数(这是一个指向指针的指针)8个字节被推(因为使用了IntPtr)(“写”地址的地址),第三个参数是AVISTREAMINFO结构的地址。
因此,当调用AVIFileCreateStream
时,它访问堆栈上的那些参数,但它们基本上是垃圾......它将尝试使用具有错误值的指针(即只有4个字节的(第一个参数)指针地址已经通过堆栈...而剩余的4个字节(8字节指针)从堆栈中的“下一个”东西填充...因此指针地址很可能是垃圾....这就是你获得访问权限的原因。
它应该被定义的方式是这样的(注意还有其他方法可以实现相同的目的):
[DllImport("avifil32.dll", SetLastError=true)]
public static extern int AVIFileCreateStream(IntPtr pfile, out IntPtr ppavi, ref AVISTREAMINFO psi);