My Array<byte>^ function works in a previous project but not in a recent one - xaml

I've been working on DirectX lately and I have a Array<byte>^ function to read the shaders in the program. The function works in a program I made like 3 days ago, but then I ported the whole project to work with XAML and everything works basically the same except that this function now shows errors. The function is:
Array<byte>^ LoadShader(std::string File){
Array<byte>^ FileData = nullptr;
std::ifstream VertexFile(File, std::ios::in | std::ios::binary | std::ios::ate);
if(VertexFile.is_open()){
int Length = (int)VertexFile.tellg();
FileData = ref new Array<byte>(Length);
VertexFile.seekg(0, std::ios::beg);
VertexFile.read(reinterpret_cast<char*>(FileData->Data), Length);
VertexFile.close();
};
return FileData;
};
It's placed in a header file and the 3 errors presented are:
error C2143: syntax error : missing ';' before '<
error C2334: unexpected token(s) preceding '{'; skipping apparent function body
error C4430: missing type specifier - int assumed. Note: C++ does not support default-in
And I just don't know what to do... I've checked correct spelling of the header file, the function is of Array<byte>^ type and I'm certain I didn't jump the only body function in the header file.
If I remove the function, the header file works and I'm just baffled and have no idea how to fix this. For reference I'll post the complete header file underneath (it's not that big).
#pragma once
#include "DirectXHelper.h"
#include <fstream>
ref class DirectXBase abstract{
internal:
DirectXBase();
public:
virtual void Initialize(Windows::UI::Core::CoreWindow^ m_window, Windows::UI::Xaml::Controls::SwapChainBackgroundPanel^ m_panel);
virtual void CreateDeviceResources();
void CreateDepthStencil();
void CreatePipeline();
virtual void Render();
protected private:
Array<byte>^ LoadShader(std::string File){
Array<byte>^ FileData = nullptr;
std::ifstream VertexFile(File, std::ios::in | std::ios::binary | std::ios::ate);
if(VertexFile.is_open()){
int Length = (int)VertexFile.tellg();
FileData = ref new Array<byte>(Length);
VertexFile.seekg(0, std::ios::beg);
VertexFile.read(reinterpret_cast<char*>(FileData->Data), Length);
VertexFile.close();
};
return FileData;
};
protected private:
Platform::Agile<Windows::UI::Core::CoreWindow> window;
Windows::UI::Xaml::Controls::SwapChainBackgroundPanel^ panel;
Microsoft::WRL::ComPtr<ID3D11Device1> DXDevice;
Microsoft::WRL::ComPtr<ID3D11DeviceContext1> DXContext;
Microsoft::WRL::ComPtr<IDXGISwapChain1> SwapChain;
Microsoft::WRL::ComPtr<ID3D11RenderTargetView> RTView; //Render Target View
Microsoft::WRL::ComPtr<ID3D11DepthStencilView> DepthView; //3D Depth Stencil View
Microsoft::WRL::ComPtr<ID3D11Texture2D> DepthBuffer;
Microsoft::WRL::ComPtr<ID3D11InputLayout> InLayout;
Microsoft::WRL::ComPtr<ID3D11VertexShader> VShader; //Vertex Shader
Microsoft::WRL::ComPtr<ID3D11PixelShader> PShader; //Pixel Shader
};

Umm. Is it possible that your previous use had a using namespace Platform; somewhere in the file above the use of Array<byte>?
If so that would explain why it's not working.

Related

How to pass a reference to a void* from C++/CLI to a native C function

I'm trying to call a native Windows API from managed C++/CLI. One of the arguments is a void**. The idea is that the function will allocate a memory structure and return a void pointer to the caller, which should be passed back to the API on the next call. So I need to allocate storage for a pointer on the managed side and pass a reference to the C API. I can't figure out how to do this.
I've tried declaring a void * in the caller and passing a reference via various operators: &, internal_ptr<>, pin_ptr<>. I did the same with an IntPtr. I get errors saying the compiler can't convert this to a void**.
Here's one attempt using IntPtr and pin_ptr. I get the following compile error on line 28 (the line that declares the pin_ptr):
E0144 a value of type "interior_ptr<System::IntPtr>" cannot be used to initialize an entity of type "cli::pin_ptr<void *>"
#include <msclr\marshal.h>
using namespace msclr::interop;
using namespace System;
namespace CLRStorage
{
public ref class CompoundFile
{
private:
String ^ pathname;
IntPtr pRootStorage;
public:
CompoundFile CompoundFile::Create(String^ path)
{
STGOPTIONS stgOptions;
stgOptions.usVersion = 1;
stgOptions.reserved = 0;
stgOptions.ulSectorSize = 4096;
stgOptions.pwcsTemplateFile = NULL;
auto cf = gcnew CompoundFile();
cf->pathname = path;
marshal_context^ context = gcnew marshal_context();
pin_ptr<void*> ppRootStorage = &cf->pRootStorage;
StgCreateStorageEx(
context->marshal_as<WCHAR*>(path),
STGM_READWRITE & STGM_CREATE,
STGFMT_DOCFILE,
0,
&stgOptions,
NULL,
IID_IStorage,
ppRootStorage);
}
};
}
IntPtr can be converted to and from void*, but it isn't the same type.
Since the parameter is out-only, the simple solution is just to use a temporary:
void* pRootStorage;
StgCreateStorageEx(
context->marshal_as<WCHAR*>(path),
STGM_READWRITE & STGM_CREATE,
STGFMT_DOCFILE,
0,
&stgOptions,
NULL,
IID_IStorage,
&pRootStorage);
cf->pRootStorage = IntPtr(pRootStorage);
This will actually be a tiny bit faster as well, because no pinning is needed.
You also have a separate problem with bad member function syntax. You want
static CompoundFile^ Create(String^ path)
instead of
CompoundFile CompoundFile::Create(String^ path)
and don't forget to
return cf;
Then, marshal_context is not a ref class, so this line is wrong:
marshal_context^ context = gcnew marshal_context();
Instead use
marshal_context context;
and since it is not a pointer,
context.marshal_as<WCHAR*>(path)

C++/CLI: Interpreting "VOID" as "void"

I am doing something pretty ugly but nevertheless there seems to be something what appears to be a bug ..
I have an enum called BasicTypeID which is written in C#:
public enum BasicTypeID
{
//..
FUNCTION,
VOID,
FLOAT,
// ..
}
As I try to assign a value to an array element on position BasicTypeID::VOID like this:
typedef struct TypeInfo {
char * name;
unsigned char size;
unsigned char sign;
unsigned char real;
} TypeInfo;
static const TypeInfo TYPE_VOID = { "void", 0, 0, 0 };
static TypeInfo const **basic_type_info;
CDLLEXPORT void CLIParser_InitializeDebugInformation(char * source_folder_path, char * cdb_file_path)
{
// ..
int enum_size = Enum::GetNames(BasicTypeID::typeid)->Length;
*basic_type_info = new TypeInfo[enum_size];
basic_type_info[(int)BasicTypeID::VOID] = &TYPE_VOID; // Compile error
VOID *dummy1;
FLOAT dummy2;
// ..
}
I am receiving the errors:
error C2589: 'void' : illegal token on right side of '::'
error C2059: syntax error : '::'
whereas it is working if I use e.g. FUNCTION as index:
basic_type_info[(int)BasicTypeID::FUNCTION] = &TYPE_VOID; // Compiles without errors
it is also working for FLOAT:
basic_type_info[(int)BasicTypeID::FLOAT] = &TYPE_VOID; // Compiles without errors
Why is this happening?
The Windows headers have a #define VOID void, which messes up your C++/CLI code.
Why did they do this? Because back in the day when the Windows API was first defined, C compiler support for void wasn't uniform. Since the API has to work with these compilers, it supplied its own version in VOID, which is presumably expanded to void if your compiler supports it, or some other type if it doesn't. Then, they can't do anything about it because of backward compatibility.
Why not a typedef? Because apparently the Microsoft compilers at that time didn't consider typedef void VOID; to be legal C (they now do, I believe). And they had to retain the macro for backward compatibility, because while
#define VOID void
int c(VOID){ return 0; }
is legal,
typedef void VOID;
int c(VOID){ return 0; }
is not (in C89, anyway).
Pretty much all the other Windows API types are typedefs and not preprocessor macros, which is why FLOAT works for you but VOID doesn't.

Accessing a C/C++ structure of callbacks through a DLL's exported function using JNA

I have a vendor supplied .DLL and an online API that I am using to interact with a piece of radio hardware; I am using JNA to access the exported functions through Java (because I don't know C/C++). I can call basic methods and use some API structures successfully, but I am having trouble with the callback structure. I've followed the TutorTutor guide here and also tried Mr. Wall's authoritative guide here, but I haven't been able to formulate the Java side syntax for callbacks set in a structure correctly.
I need to use this exported function:
BOOL __stdcall SetCallbacks(INT32 hDevice,
CONST G39DDC_CALLBACKS *Callbacks, DWORD_PTR UserData);
This function references the C/C++ Structure:
typedef struct{
G39DDC_IF_CALLBACK IFCallback;
//more omitted
} G39DDC_CALLBACKS;
...which according to the API has these Members (Note this is not an exported function):
VOID __stdcall IFCallback(CONST SHORT *Buffer, UINT32 NumberOfSamples,
UINT32 CenterFrequency, WORD Amplitude,
UINT32 ADCSampleRate, DWORD_PTR UserData);
//more omitted
I have a G39DDCAPI.java where I have loaded the DLL library and reproduced the API exported functions in Java, with the help of JNA. Simple calls to that work well.
I also have a G39DDC_CALLBACKS.java where I have implemented the above C/C++ structure in a format works for other API structures. This callback structure is where I am unsure of the syntax:
import java.util.Arrays;
import java.util.List;
import java.nio.ShortBuffer;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.BaseTSD.DWORD_PTR;
import com.sun.jna.win32.StdCallLibrary.StdCallCallback;
public class G39DDC_CALLBACKS extends Structure {
public G39DDC_IF_CALLBACK IFCallback;
//more omitted
protected List getFieldOrder() {
return Arrays.asList(new String[] {
"IFCallback","DDC1StreamCallback" //more omitted
});
}
public static interface G39DDC_IF_CALLBACK extends StdCallCallback{
public void invoke(ShortBuffer _Buffer,int NumberOfSamples,
int CenterFrequency, short Amplitude,
int ADCSampleRate, DWORD_PTR UserData);
}
}
Edit: I made my arguments more type safe as Technomage suggested. I am still getting a null pointer exception with several attempts to call the callback. Since I'm not sure of my syntax regarding the callback structure above, I can't pinpoint my problem in the main below. Right now the relevant section looks like this:
int NumberOfSamples=65536;//This is usually 65536.
ShortBuffer _Buffer = ShortBuffer.allocate(NumberOfSamples);
int CenterFrequency=10000000;//Specifies center frequency (in Hz) of the useful band
//in received 50 MHz wide snapshot.
short Amplitude=0;//The possible value is 0 to 32767.
int ADCSampleRate=100;//Specifies sample rate of the ADC in Hz.
DWORD_PTR UserData = null;
G39DDC_CALLBACKS callbackStruct= new G39DDC_CALLBACKS();
lib.SetCallbacks(hDevice,callbackStruct,UserData);
//hDevice is a handle for the hardware device used-- works in other uses
//lib is a reference to the library in G39DDCAPI.java-- works in other uses
//The UserData is a big unknown-- I don't know what to do with this variable
//as a DWORD_PTR
callbackStruct.IFCallback.invoke(_Buffer, NumberOfSamples, CenterFrequency,
Amplitude, ADCSampleRate, UserData);
EDIT NO 2:
I have one callback working somewhat, but I don't have control over the buffers. More frustratingly, a single call to invoke the method will result in several runs of the custom callback, usually with multiple output files (results vary drastically from run to run). I don't know if it is because I am not allocating memory correctly on the Java side, because I cannot free the memory on the C/C++ side, or because I have no cue on which to tell Java to access the buffer, etc. Relevant code looks like:
//before this, main method sets library, starts DDCs, initializes some variables...
//API call to start IF
System.out.print("Starting IF... "+lib.StartIF(hDevice, Period)+"\n")
G39DDC_CALLBACKS callbackStructure = new G39DDC_CALLBACKS();
callbackStructure.IFCallback = new G39DDC_IF_CALLBACK(){
#Override
public void invoke(Pointer _Buffer, int NumberOfSamples, int CenterFrequency,
short Amplitude, int ADCSampleRate, DWORD_PTR UserData ) {
//notification
System.out.println("Invoked IFCallback!!");
try {
//ready file and writers
File filePath = new File("/users/user/G39DDC_Scans/");
if (!filePath.exists()){
System.out.println("Making new directory...");
filePath.mkdir();
}
String filename="Scan_"+System.currentTimeMillis();
File fille= new File("/users/user/G39DDC_Scans/"+filename+".txt");
if (!fille.exists()) {
System.out.println("Making new file...");
fille.createNewFile();
}
FileWriter fw = new FileWriter(fille.getAbsoluteFile());
//callback body
short[] deBuff=new short[NumberOfSamples];
int offset=0;
int arraySize=NumberOfSamples;
deBuff=_Buffer.getShortArray(offset,arraySize);
for (int i=0; i<NumberOfSamples; i++){
String str=deBuff[i]+",";
fw.write(str);
}
fw.close();
} catch (IOException e1) {
System.out.println("IOException: "+e1);
}
}
};
lib.SetCallbacks(hDevice, callbackStructure,UserData);
System.out.println("Main, before callback invocation");
callbackStructure.IFCallback.invoke(s_Pointer, NumberOfSamples, CenterFrequency, Amplitude, ADCSampleRate, UserData);
System.out.println("Main, after callback invocation");
//suddenly having trouble stopping DDCs or powering off device; assume it has to do with dll using the functions above
//System.out.println("StopIF: " + lib.StopIF(hDevice));//API function returns boolean value
//System.out.println("StopDDC2: " + lib.StopDDC2( hDevice, Channel));
//System.out.println("StopDDC1: " + lib.StopDDC1( hDevice, Channel ));
//System.out.println("test_finishDevice: " + test_finishDevice( hDevice, lib));
System.out.println("Program Exit");
//END MAIN METHOD
You need to extend StdCallCallback, for one, otherwise you'll likely crash when the native code tries to call the Java code.
Any place you see a Windows type with _PTR, you should use a PointerType - the platform package with JNA includes definitions for DWORD_PTR and friends.
Finally, you can't have a primitive array argument in your G39DDC_IF_CALLBACK. You'll need to use Pointer or an NIO buffer; Pointer.getShortArray() may then be used to extract the short[] by providing the desired length of the array.
EDIT
Yes, you need to initialize your callback field in the callbacks structure before passing it into your native function, otherwise you're just passing a NULL pointer, which will cause complaints on the Java or native side or both.
This is what it takes to create a callback, using an anonymous instance of the declared callback function interface:
myStruct.callbackField = new MyCallback() {
public void invoke(int arg) {
// do your stuff here
}
};

how to resolve AccessViolationException

Could you please help in resolving the below mentioned issue:
Following are the code snippet:
Managed code (VC++) - wrapper code:
Method-1:
void displayString(std::string abc)
{
std::string xyz=abc;
std::cout<<xyz;
}
Method-2:
void sendData(System::String^ input)
{
char* inputData = (char*)Marshal::StringToHGlobalAnsi(input).ToPointer();
std::string argData = inputData;
displayString(argData); //Working fine
//passing string instance to unmanaged code
/* while execution the below line the system throws: _CrtIsValidHeapPointer(pUserData), _BLOCK_TYPE_IS_VALID(pHead->nBlockUse), HEAP CORRUPTION DETECTED, and finally AccessViolationException */
sendDisplayString(argData); //AccessViolationException
sendDisplayString("Hello"); //AccessViolationException
}
unmanaged code C++ dll:
void sendDisplayString(std::string input)
{
std::cout<<input;
}
Note: Searched in all provided link but there is no resolution for this issue. All the links route to MSDN marshalling page.
Thanks in advance.
I guess it answers your question: http://support.microsoft.com/kb/172396

Loading interdependent assemblies from C++/CLI

I want to load two assemblies from C++/CLI; assembly A depends on assembly B, and both are VB.Net projects (3.5). I want them to load from a byte array, so I use Assembly::Load(), but when I try to instantiate a class from assembly A, the framework ignores the previously loaded assembly B and attempts to load it again, which fails because it is not in the search path. The "Name" of the assembly is the same, so I don't know why it fails. For testing purposes, my program loads the bytes directly from the compiled image, but the real code will be loaded differently. This is my test code:
#include "stdafx.h"
using namespace System;
using namespace System::Windows::Forms;
using namespace System::IO;
using namespace System::Reflection;
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
array<unsigned char>^ bytes;
FileStream^ f;
f = gcnew FileStream(L"c:\\...\\AssemblyB.dll", FileMode::Open);
bytes = gcnew array<unsigned char>((int)f->Length);
f->Read( bytes, 0, (int) f->Length );
f->Close();
f = nullptr;
Assembly^ assemblyb = Assembly::Load(bytes);
f = gcnew FileStream(L"c:\\...\\AssemblyA.dll", FileMode::Open);
bytes = gcnew array<unsigned char>((int)f->Length);
f->Read( bytes, 0, (int) f->Length );
f->Close();
f = nullptr;
Assembly^ assemblya = Assembly::Load(bytes);
bytes = nullptr;
// Here I get the file not found exception!
Object^ mf = assemblya->CreateInstance(L"AssemblyA.MainForm");
// This line is not reached unless I copy assemblyb.dll to my app's folder:
mf->GetType()->InvokeMember(L"ShowDialog",BindingFlags::Default | BindingFlags::InvokeMethod,
mf->GetType()->DefaultBinder, mf, nullptr );
return 0;
}
The error is:
Could not load file or assembly 'AssemblyB, Version=1.0.3650.39903, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
When I check assemblyb->FullName, it says exactly 'AssemblyB, Version=1.0.3650.39903, Culture=neutral, PublicKeyToken=null'.
Of course, if I copy AssemblyB.dll to my test program's folder the code works just fine, but that's not what I want.
Any ideas?
(By the way, my second step will be attempt to make AssemblyA use classes that my C++/CLI exe will expose.)
OK, I just embarrased myself. It's all in the docs.
// This class is just for holding a managed static variable for assemblyB
ref class Resolver {
public:
static Assembly^ assemblyB;
};
// This is the delegate for resolving assemblies
Assembly^ ResolveHandler(Object^ Sender, ResolveEventArgs^ args)
{
// Warning: this should check the args for the assembly name!
return Resolver::assemblyB;
}
.
.
.
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
// Set up the handler for the AssemblyResolve event
AppDomain::CurrentDomain->AssemblyResolve += gcnew ResolveEventHandler( ResolveHandler );
.
.
.
// Load assemblyb into the static variable available to the resolver delegate
Resolver::assemblyb = Assembly::Load(bytes);
.
.
.
I hope someone finds this useful. :)