PInvoke - Issue while calling DJVU function from C# code. Attempted to read or write protected memory - pinvoke

UPDATE 3-4-15:11IS
As recommended by David modified PInvoke as below, this time I am getting different error "Unhandled exception of type System.ExecutionEngineException occurred in mscorlib.dll"
[DllImport("C:\\Program Files\\DJVULIBRE\\LIBDJVULIBRE.dll", CharSet=CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private unsafe static extern int ddjvu_page_render(IntPtr page, ddjvu_render_mode_t mode, ref ddjvu_rect_t pagerect,
ref ddjvu_rect_t renderrect,
IntPtr pixelformat,
uint rowsize,
[Out][MarshalAs(UnmanagedType.LPArray)]byte[] imagebuffer);
Thanks David for your valuable time, I think is close to a fix.
HISTORY
I know there are many questions in this subject but none of them help to resolve the issue I am currently facing.
Below is the API function in C Language
DDJVUAPI int
ddjvu_page_render(ddjvu_page_t *page,
const ddjvu_render_mode_t mode,
const ddjvu_rect_t *pagerect,
const ddjvu_rect_t *renderrect,
const ddjvu_format_t *pixelformat,
unsigned long rowsize,
char *imagebuffer );
Below is the PInvoke signature of C Function added in .NET code
[DllImport("C:\\Program Files\\DJVULIBRE\\LIBDJVULIBRE.dll", CharSet=CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private unsafe static extern int ddjvu_page_render(IntPtr page, ddjvu_render_mode_t mode, IntPtr pagerect,
IntPtr renderrect,
IntPtr pixelformat,
ulong rowsize,
[Out][MarshalAs(UnmanagedType.LPArray)]byte[] imagebuffer);
Below is how I am calling this function in the c# code
byte* buffer = (byte *)Memory.Alloc(nSize);
try
{
IntPtr ptr1 = (IntPtr)Memory.Alloc(Marshal.SizeOf(prect));
Marshal.StructureToPtr(prect, ptr1, false);
IntPtr ptr2 = (IntPtr)Memory.Alloc(Marshal.SizeOf(rrect));
Marshal.StructureToPtr(rrect, ptr2, false);
byte[] array = new byte[nSize];
fixed (byte* p = array) Memory.Copy(buffer, p, nSize);
ddjvu_page_render(page, ddjvu_render_mode_t.DDJVU_RENDER_MASKONLY, ptr1, ptr2, fmt, (ulong)stride, array);
}
finally
{
Memory.Free(buffer);
}
call to ddjvu_page_render in above code is throwing "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
Prior to this post I must have tried all the option could find in various blogs.
Appreciate any help, is almost a day I am clueless, your timely help could save my job
UPDATE 3-4-15:7:44IS
This code is using DJVULibre
UPDATE 3-4-15:8:35IS
Here is the code I have in Form Load
ctx = ddjvu_context_create(System.AppDomain.CurrentDomain.FriendlyName);
if (ctx != null)
{
string djFile = "C:\\Users\\rammohan.chavakula\\Documents\\eiasample.djvu";
doc = ddjvu_document_create_by_filename(ctx, djFile, 100);
if (doc != null)
{
while (ddjvu_job_status(ddjvu_document_job(doc)) >= ddjvu_status_t.DDJVU_JOB_OK)
SpinDdjvuMessageLoop(ctx, true);
int pageCount = ddjvu_document_get_pagenum(doc);
mediaboxes = new Rectangle[pageCount];
for (int i = 0; i < pageCount; i++)
{
ddjvu_status_t status;
ddjvu_pageinfo_t info = new ddjvu_pageinfo_t();
while ((status = ddjvu_document_get_pageinfo_imp(doc, i, ref info, (uint)System.Runtime.InteropServices.Marshal.SizeOf(info))) < ddjvu_status_t.DDJVU_JOB_OK)
SpinDdjvuMessageLoop(ctx, true);
if (status != ddjvu_status_t.DDJVU_JOB_OK)
continue;
mediaboxes[i] = new Rectangle(0, 0, info.width / info.dpi,
info.height / info.dpi);
}
}
ddjvu_context_release(ctx);
}
In OnPaint function I have this below code
if (doc == null)
{
base.OnPaint(e);
return;
}
Rectangle pageRc = PageMediabox(1);
Rectangle screen = Transform(pageRc, 1, zoom, rotation, false);
Rectangle full = Transform(PageMediabox(1), 1, zoom, rotation, false);
full.Intersect(screen);
IntPtr page = ddjvu_page_create_by_pageno(doc, 1);
if (page == null )
{
base.OnPaint(e);
return;
}
int rotation4 = (((-rotation / 90) % 4) + 4) % 4;
ddjvu_page_set_rotation(page, (ddjvu_page_rotation_t)rotation4);
while (ddjvu_job_status(ddjvu_page_job(page)) >= ddjvu_status_t.DDJVU_JOB_OK)
SpinDdjvuMessageLoop(ctx, true);
if (ddjvu_job_status(ddjvu_page_job(page)) >= ddjvu_status_t.DDJVU_JOB_FAILED)
{
base.OnPaint(e);
return;
}
IntPtr fmt = ddjvu_format_create(ddjvu_format_style_t.DDJVU_FORMAT_BGR24, 0, (UIntPtr)null);
ddjvu_format_set_row_order(fmt, /* top_to_bottom */1);
ddjvu_rect_t prect = new ddjvu_rect_t(full.X, full.Y, (uint)full.Width, (uint)full.Height);
ddjvu_rect_t rrect = new ddjvu_rect_t(screen.X, 2 * full.Y + screen.Y + full.Height - screen.Height, (uint)screen.Width, (uint)screen.Height);
int stride = ((screen.Width * 3 + 3) / 4) * 4;
//byte tmp;
////ScopedMem<char> bmpData(SAZA(char, stride * (screen.dy + 5)));
//for (int y = 0; y < rrect.h; y++) {
// int step_y = y * SCREEN_WIDTH;
// for (int x=0; x < rrect.w; x++) {
// tmp = (byte)((imagebuf[x + step_y] >> 5) << 5);
// }
//}
int rowsize = mediaboxes[0].Width * 3;
int nSize = rowsize * (mediaboxes[0].Height) * 10;
unsafe
{
byte* buffer = (byte *)Memory.Alloc(nSize);
try
{
IntPtr ptr1 = (IntPtr)Memory.Alloc(Marshal.SizeOf(prect));
Marshal.StructureToPtr(prect, ptr1, false);
IntPtr ptr2 = (IntPtr)Memory.Alloc(Marshal.SizeOf(rrect));
Marshal.StructureToPtr(rrect, ptr2, false);
byte[] array = new byte[nSize];
fixed (byte* p = array) Memory.Copy(buffer, p, nSize);
ddjvu_page_render(page, ddjvu_render_mode_t.DDJVU_RENDER_MASKONLY, ptr1, ptr2, fmt, (ulong)stride, array);
}
finally
{
Memory.Free(buffer);
}
ddjvu_page_render should return arbitrary data of page which is to be rendered in a given rectangle area. Once after that I should be able to create image from arbitrary data & display in the screen

Here's how I would write the p/invoke:
[DllImport(dllname, CharSet=CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private static extern int ddjvu_page_render(
[In] IntPtr page,
[In] ddjvu_render_mode_t mode,
[In] ref ddjvu_rect_t pagerect,
[In] ref ddjvu_rect_t renderrect,
[In] ref ddjvu_format_t pixelformat,
[In] uint rowsize,
[Out] byte[] imagebuffer
);
Note that I've stopped using unsafe, and am letting the marshaler handle the structs automatically.
There are quite a few assumptions here that I cannot verify:
The calling convention. It might not be cdecl. The C++ header will would have the definitive answer.
The first parameter is a void* handle type, I presume.
ddjvu_render_mode_t is an enum that you have translated correctly.
The three ref parameters are structs, passed by reference. I cannot check that you have translated them correctly.
Calling this function would be something like this:
byte[] imagebuffer = new byte[nSize];
int retval = ddjvu_page_render(
page,
ddjvu_render_mode_t.DDJVU_RENDER_MASKONLY,
ref prect,
ref rrect,
ref fmt,
(uint)stride,
imagebuffer
);
if (retval != ??)
// handle error
This is quite a broad brush answer. I hope it points you in the right direction. I don't think that all your problems will be solved by this.

Related

Why does my screen starts blinking when I toggle the full screen state?

I'm trying to implement full screen support on my Direct3D11 application, but I've been having a issue with this. I'm using the ALT+ENTER key combination that makes the IDXGISwapChain change the target window to full screen and back. But when I go into full screen my back buffer starts blinking between the color that I have set on the call to ID3D11DeviceContext::ClearRenderTargetView to black.
I also have code in the WinProc function of my window, that when it receives the WM_SIZE message, this code is executed.
If I don't use this code to resize the buffers, the blinking doesn't happen for some reason.
If I call ID3D11DeviceContext::ClearRenderTargetView once after creating the new swap chain, and again after calling IDXGISwapChain::Present, the blinking also doesn't happen.
It's a bit confusing, but I have a theory that maybe, when I go to full screen mode and call IDXGISwapChain::ResizeBuffers it somehow makes my swap chain have more than one buffer, and when I call IDXGISwapChain::Present it rotates to the next buffer, which is on the default color black.
Note that I have also tried to call IDXGISwapChain::SetFullscreenState, but the issue persists.
My code is too big to paste here, so I took the code from this tutorial and changed it a bit to show the behaviour I'm describing:
#include <windows.h>
#include <d3d11.h>
#pragma comment (lib, "d3d11.lib")
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
// global declarations
IDXGISwapChain* swapchain;
ID3D11Device* dev;
ID3D11DeviceContext* devcon;
ID3D11RenderTargetView* backbuffer;
void InitD3D(HWND hWnd);
void RenderFrame(void);
void CleanD3D(void);
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int main()
{
HWND hWnd;
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = GetModuleHandle(nullptr);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = L"WindowClass";
RegisterClassEx(&wc);
RECT wr = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
hWnd = CreateWindowEx(NULL,
L"WindowClass",
L"Our First Direct3D Program",
WS_OVERLAPPEDWINDOW,
300,
300,
wr.right - wr.left,
wr.bottom - wr.top,
NULL,
NULL,
GetModuleHandle(nullptr),
NULL);
ShowWindow(hWnd, SW_SHOW);
InitD3D(hWnd);
MSG msg;
while (TRUE)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
break;
}
RenderFrame();
}
CleanD3D();
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
case WM_SIZE: {
if (swapchain)
{
devcon->OMSetRenderTargets(0, 0, 0);
backbuffer->Release();
HRESULT hr;
hr = swapchain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
ID3D11Texture2D* pBuffer;
hr = swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D),
(void**)&pBuffer);
hr = dev->CreateRenderTargetView(pBuffer, NULL,
&backbuffer);
pBuffer->Release();
devcon->OMSetRenderTargets(1, &backbuffer, NULL);
float fColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
devcon->ClearRenderTargetView(backbuffer, fColor);
DXGI_SWAP_CHAIN_DESC Desc;
ZeroMemory(&Desc, sizeof(DXGI_SWAP_CHAIN_DESC));
swapchain->GetDesc(&Desc);
D3D11_VIEWPORT vp;
vp.Width = Desc.BufferDesc.Width;
vp.Height = Desc.BufferDesc.Height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
devcon->RSSetViewports(1, &vp);
}
return 1;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
void InitD3D(HWND hWnd)
{
DXGI_SWAP_CHAIN_DESC scd;
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
scd.BufferCount = 1;
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
scd.BufferDesc.Width = SCREEN_WIDTH;
scd.BufferDesc.Height = SCREEN_HEIGHT;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.OutputWindow = hWnd;
scd.SampleDesc.Count = 1;
scd.Windowed = TRUE;
scd.Flags = 0;
D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&scd,
&swapchain,
&dev,
NULL,
&devcon);
ID3D11Texture2D* pBackBuffer;
swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
pBackBuffer->Release();
devcon->OMSetRenderTargets(1, &backbuffer, NULL);
float fColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
devcon->ClearRenderTargetView(backbuffer, fColor);
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = SCREEN_WIDTH;
viewport.Height = SCREEN_HEIGHT;
devcon->RSSetViewports(1, &viewport);
}
void RenderFrame(void)
{
swapchain->Present(1, 0);
}
void CleanD3D(void)
{
swapchain->SetFullscreenState(FALSE, NULL);
swapchain->Release();
backbuffer->Release();
dev->Release();
devcon->Release();
After messing a bit with the code, I've noticed that when the SampleDesc::Count variable from the DXGI_SWAP_CHAIN_DESC is not equal to 1, the blinking also doesn't happen.

Passing string array from Borland C++ to C#

I want to pass list of email address strings from Borland C++ to my C# library. Below my C# side code. I could make call to PrintName() method and it works. Now I want to print email addresses, but if I call PrintEmails() function nothing happens. Could you please suggest how I can pass multiple email addresses to C# lib.
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("4A686AB1-8425-43D9-BD89-B696BB5F6A18")]
public interface ITestConnector
{
void PrintEmails(string[] emails);
void PrintName(string name);
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(ITestConnector))]
[Guid("7D818287-298A-41BF-A224-5EAC9C581BD0")]
public class TestConnector : ITestConnector
{
public void PrintEmails(string[] emails)
{
System.IO.File.WriteAllLines(#"c:\temp\emails.txt", emails);
}
public void PrintName(string name)
{
System.IO.File.WriteAllText(#"c:\temp\name.txt", name);
}
}
I have imported TLB file of above C# library into RAD Studio and my C++ side code is as below.
interface ITestConnector : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE PrintEmails(LPSAFEARRAY* emails/*[in,out]*/) = 0; // [-1]
virtual HRESULT STDMETHODCALLTYPE PrintName(WideString name/*[in]*/) = 0; // [-1]
};
TTestConnector *connector = new TTestConnector(this);
SAFEARRAYBOUND bounds[] = {{2, 0}}; //Array Contains 2 Elements starting from Index '0'
LPSAFEARRAY pSA = SafeArrayCreate(VT_VARIANT,1,bounds); //Create a one-dimensional SafeArray of variants
long lIndex[1];
VARIANT var;
lIndex[0] = 0; // index of the element being inserted in the array
var.vt = VT_BSTR; // type of the element being inserted
var.bstrVal = ::SysAllocStringLen( L"abc#xyz.com", 11 ); // the value of the element being inserted
HRESULT hr= SafeArrayPutElement(pSA, lIndex, &var); // insert the element
// repeat the insertion for one more element (at index 1)
lIndex[0] = 1;
var.vt = VT_BSTR;
var.bstrVal = ::SysAllocStringLen( L"pqr#xyz.com", 11 );
hr = SafeArrayPutElement(pSA, lIndex, &var);
connector->PrintEmails(pSA);
delete connector;
Below C++ side code worked in my case.
SAFEARRAYBOUND saBound[1];
saBound[0].cElements = nElements;
saBound[0].lLbound = 0;
SAFEARRAY *pSA = SafeArrayCreate(VT_BSTR, 1, saBound);
if (pSA == NULL)
{
return NULL;
}
for (int ix = 0; ix < nElements; ix++)
{
BSTR pData = SysAllocString(elements[ix]);
long rgIndicies[1];
rgIndicies[0] = saBound[0].lLbound + ix;
HRESULT hr = SafeArrayPutElement(pSA, rgIndicies, pData);
_tprintf(TEXT("%d"), hr);
}

iTextSharp Twisting CCITTFaxDecode extracted data with GetDrawingImage()

On certain images, when I call:
PdfImageObject pimg = new PdfImageObject(stream);
Image bmp = pimg.GetDrawingImage();
The Image that is returned is twisted. I've seen this before and it usually has to do with byte alignment but I'm not sure how to get around this.
The /DecodeParms for this object are /EndOfLine true /K 0 /Columns 3300.
I have tried using the GetStreamBytesRaw() with BitMiracle.LibTiff and with it I can get the data formatted properly although the image is rotated. I'd prefer for GetDrawingImage() to decode the data properly if possible, assuming that is the problem.
I could provide the PDF via email if requested.
Thanks,
Darren
For anyone else that runs across this scenario here is my solution. The key to this puzzle was understanding that /K 0 is G3, /K -1 (or anything less than 0) is G4 /K 1 (or anything greater than 0) is G3-2D.
The twisting happens when you try to make G3 compressed data fit into a G4 image which it appears that is what iTextSharp may be doing. I know it definitely does not work with how I have iTextSharp implemented in my project. I confess that I cannot decipher all the decoding stuff that iTextSharp is doing so it could be something I'm missing too.
EndOfLine didn't have any part in this puzzle but I still think putting line feeds in binary data is a strange practice.
99% of this code came from BitMiracle.LibTiff.Net - Thank you.
int nK = 0;// Default to 0 like the PDF Spec
PdfObject oDecodeParms = stream.Get(PdfName.DECODEPARMS);
if (oDecodeParms is PdfDictionary)
{
PdfObject oK0 = ((PdfDictionary)oDecodeParms).Get(PdfName.K);
if (oK0 != null)
nK = ((PdfNumber)oK0).IntValue;
}
using (MemoryStream ms = new MemoryStream())
{
using (Tiff tiff = Tiff.ClientOpen("custom", "w", ms, new TiffStream()))
{
tiff.SetField(TiffTag.IMAGEWIDTH, width);
tiff.SetField(TiffTag.IMAGELENGTH, height);
if (nK == 0 || nK > 0) // 0 = Group 3, > 0 = Group 3 2D
tiff.SetField(TiffTag.COMPRESSION, Compression.CCITTFAX3);
else if (nK < 0) // < 0 = Group 4
tiff.SetField(TiffTag.COMPRESSION, Compression.CCITTFAX4);
tiff.SetField(TiffTag.BITSPERSAMPLE, bpc);
tiff.SetField(TiffTag.SAMPLESPERPIXEL, 1);
tiff.WriteRawStrip(0, rawBytes, rawBytes.Length); //saving the tiff file using the raw bytes retrieved from the PDF.
tiff.Close();
}
TiffStreamForBytes byteStream = new TiffStreamForBytes(ms.ToArray());
using (Tiff input = Tiff.ClientOpen("bytes", "r", null, byteStream))
{
int stride = input.ScanlineSize();
Bitmap result = new Bitmap(width, height, pixelFormat);
ColorPalette palette = result.Palette;
palette.Entries[0] = System.Drawing.Color.White;
palette.Entries[1] = System.Drawing.Color.Black;
result.Palette = palette;
for (int i = 0; i < height; i++)
{
Rectangle imgRect = new Rectangle(0, i, width, 1);
BitmapData imgData = result.LockBits(imgRect, ImageLockMode.WriteOnly, pixelFormat);
byte[] buffer = new byte[stride];
input.ReadScanline(buffer, i);
System.Runtime.InteropServices.Marshal.Copy(buffer, 0, imgData.Scan0, buffer.Length);
result.UnlockBits(imgData);
}
}
}
/// <summary>
/// Custom read-only stream for byte buffer that can be used
/// with Tiff.ClientOpen method.
/// </summary>
public class TiffStreamForBytes : TiffStream
{
private byte[] m_bytes;
private int m_position;
public TiffStreamForBytes(byte[] bytes)
{
m_bytes = bytes;
m_position = 0;
}
public override int Read(object clientData, byte[] buffer, int offset, int count)
{
if ((m_position + count) > m_bytes.Length)
return -1;
Buffer.BlockCopy(m_bytes, m_position, buffer, offset, count);
m_position += count;
return count;
}
public override void Write(object clientData, byte[] buffer, int offset, int count)
{
throw new InvalidOperationException("This stream is read-only");
}
public override long Seek(object clientData, long offset, SeekOrigin origin)
{
switch (origin)
{
case SeekOrigin.Begin:
if (offset > m_bytes.Length)
return -1;
m_position = (int)offset;
return m_position;
case SeekOrigin.Current:
if ((offset + m_position) > m_bytes.Length)
return -1;
m_position += (int)offset;
return m_position;
case SeekOrigin.End:
if ((m_bytes.Length - offset) < 0)
return -1;
m_position = (int)(m_bytes.Length - offset);
return m_position;
}
return -1;
}
public override void Close(object clientData)
{
// nothing to do
return;
}
public override long Size(object clientData)
{
return m_bytes.Length;
}
}

WlanEnumInterfaces don't return Guid C# Whit P/Invoke

Hy Guy i have a a problem whit c# to call a native function wlanenuminterfaces
the function return ok = (0) but i don't know why... the Guid of interface is all {000000000000000000}
why? someone can help me ? thanks so much i pos the code...
[DllImport("wlanapi.dll")]
internal static extern int WlanEnumInterfaces([In]IntPtr HandleClient, [In,Out]IntPtr Reserved, [In,Out] WLAN_INTERFACE_INFO_LIST ine);`
[StructLayout(LayoutKind.Sequential)]
internal class WLAN_INTERFACE_INFO_LIST
{
internal int dwNumberOfItems;
internal int dwIndex;
internal WLAN_INTERFACE_INFO[] InterfaceInfo;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal class WLAN_INTERFACE_INFO
{
internal Guid interfaceGuid;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
internal string strInterfaceDescription;
internal WLAN_INTERFACE_STATE Istate;
}
internal enum WLAN_INTERFACE_STATE
{
wlan_interface_state_not_ready = 0,
wlan_interface_state_connected = 1,
wlan_interface_state_ad_hoc_network_formed = 2,
wlan_interface_state_disconnecting = 3,
wlan_interface_state_disconnected = 4,
wlan_interface_state_associating = 5,
wlan_interface_state_discovering = 6,
wlan_interface_state_authenticating = 7
}
info = new WLAN_INTERFACE_INFO_LIST();
list = new WLAN_INTERFACE_INFO();
IntPtr info1 = Marshal.AllocHGlobal(Marshal.SizeOf(info));
IntPtr list1 = Marshal.AllocHGlobal(Marshal.SizeOf(list));
int enuminterface = Win32Intereop.WlanEnumInterfaces(handle, IntPtr.Zero, info);
if (enuminterface != 0)
{
MessageBox.Show("Problema Enum Interface");
}
IntPtr num = (IntPtr)info.dwNumberOfItems;
info.dwNumberOfItems = Marshal.ReadInt32(num);
info.InterfaceInfo = new WLAN_INTERFACE_INFO[info.dwNumberOfItems];
for (int i = 0; i < info.dwNumberOfItems; i++)
{
info.InterfaceInfo[i] = list;
}

WINCODEC_ERR_WIN32ERROR 0x88982F94 when calling IWICComponentFactory.CreateBitmapFromMemory

I'm getting the following error when calling IWICComponentFactory.CreateBitmapFromMemory and passing it a pointer to Scan0 of a 32bppArgb GDI+ bitmap
WINCODEC_ERR_WIN32ERROR
0x88982F94
Windows Codecs received an error from the Win32 system.
IWICComponentFactory interface decl:
new IWICBitmap CreateBitmapFromMemory(
uint uiWidth,
uint uiHeight,
[MarshalAs(UnmanagedType.LPStruct)]
Guid pixelFormat,
uint cbStride,
uint cbBufferSize,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)]
byte[] pbBuffer
);
new IWICBitmap CreateBitmapFromMemory(
uint uiWidth,
uint uiHeight,
[MarshalAs(UnmanagedType.LPStruct)]
Guid pixelFormat,
uint cbStride,
uint cbBufferSize,
IntPtr pbBuffer
);
Full code:
public static IWICBitmap ToWic(IWICComponentFactory factory, Bitmap bit) {
BitmapData bd = bit.LockBits(new Rectangle(0, 0, bit.Width, bit.Height),
ImageLockMode.ReadOnly, bit.PixelFormat);
IWICBitmap b = null;
try {
//Create WIC bitmap directly from unmanaged memory
b = factory.CreateBitmapFromMemory((uint)bit.Width, (uint)bit.Height,
ConversionUtils.FromPixelFormat(bit.PixelFormat), (uint)bd.Stride,
(uint)(bd.Stride * bd.Height), bd.Scan0);
return b;
} finally {
bit.UnlockBits(bd);
}
}
Width, Height, buffer size, format GUID, and scan size all seem correct. I can't figure out why this is happening (there are no google results for the error code or message
This isn't an answer as to why the original code doesn't work - but it's a workaround. Using IWICImagingFactory_CreateBitmapFromMemory_Proxy , everything works fine. But why didn't the original work as it's supposed to? And why the _Proxy methods with near-identical signatures?
[DllImport("WindowsCodecs.dll", EntryPoint = "IWICImagingFactory_CreateBitmapFromMemory_Proxy")]
internal static extern int CreateBitmapFromMemory(IWICComponentFactory factory, uint width, uint height, ref Guid pixelFormatGuid, uint stride, uint cbBufferSize, IntPtr pvPixels, out IWICBitmap ppIBitmap);
public static IWICBitmap ToWic(IWICComponentFactory factory, Bitmap bit) {
Guid pixelFormat = ConversionUtils.FromPixelFormat(bit.PixelFormat);
if (pixelFormat == Guid.Empty) throw new NotSupportedException("PixelFormat " + bit.PixelFormat.ToString() + " not supported.");
BitmapData bd = bit.LockBits(new Rectangle(0, 0, bit.Width, bit.Height), ImageLockMode.ReadOnly, bit.PixelFormat);
IWICBitmap b = null;
try {
//Create WIC bitmap directly from unmanaged memory
long result = CreateBitmapFromMemory(factory, (uint)bit.Width,
(uint)bit.Height, ref pixelFormat, (uint)bd.Stride,
(uint)(bd.Stride * bd.Height), bd.Scan0, out b);
if (result == 0x80070057) throw new ArgumentException();
if (result < 0) throw new Exception("HRESULT " + result);
return b;
} finally {
bit.UnlockBits(bd);
}
}
For reference, here is the COM method and here is the proxy method. Both use [IN] BYTE *pbBuffer.