In F# i'm using an external DLL (in this case SDL Graphics library) I'm importing the method I require as follows...
[<DllImport("SDL2.dll", CallingConvention = CallingConvention.Cdecl)>]
extern int SDL_QueryTexture(nativeint texture, uint32& format, int& access, int& w, int& h)
This works fine and I can successfully call the method using the following...
let result = SDLDefs.SDL_QueryTexture(textTexture, &format, &access, &w, &h)
The problem is that the native SDL methods accept null values for many pointer arguments. This is required in some scenarios (which function like overloaded methods). I can't find any way to call these methods from F# passing nulls.
For example, this fails with "does not have null as proper value"
let result = SDLDefs.SDL_QueryTexture(textTexture, &format, null, &w, &h)
I read about the attribute [AllowNullLiteral] but it seems like I can only apply it to types I define, and not pre-defined types which are used in my imported DLL.
Is there any way I can do this?
If you want to specify nulls, you need to use "raw pointers", which are represented by types nativeint and nativeptr<T>.
[<DllImport("SDL2.dll", CallingConvention = CallingConvention.Cdecl)>]
extern int SDL_QueryTexture(nativeint texture, uint32& format, nativeint access, int& w, int& h)
// Call without null
let access = 42
let pAccess = NativePtr.stackalloc<int> 1
NativePtr.write pAccess access
SQL_QueryTexture( textTexture, &format, NativePtr.toNativeInt pAccess, &w, &h )
let returnedAccess = NativePtr.read pAccess
// Call with null
SQL_QueryTexture( textTexture, &format, null, &w, &h )
NOTE: be careful with stackalloc. Allocating memory on the stack is quite handy, because you don't need to explicitly release it, but pointers to it will become invalid once you exit the current function. So you can only pass such pointers to an external function if you're sure that the function won't store the pointer and try to use it later.
If you need to pass a pointer to real heap memory that's not going anywhere, you'll need Marshal.AllocHGlobal. But don't forget to release! (or else :-)
let access = 42
let pAccess = Marshal.AllocHGlobal( sizeof<int> )
NativePtr.write (NativePtr.ofNativeInt pAccess) access
SQL_QueryTexture( textTexture, &format, pAccess, &w, &h )
Marshal.FreeHGlobal( pAccess )
Related
Good day, everybady,
I work on Windows7 (64 bits) and try use COM / OLE object "iTunesApp Class". This object has installed with iTunes application.
My code is following
HRESULT hr;
CLSID clsid;
IiTunes *pIiTunes = nullptr;
//Apple.iTunes
CLSIDFromProgID(OLESTR("iTunes.Application.1"), &clsid);
hr = CoCreateInstance(clsid, nullptr, CLSCTX_LOCAL_SERVER, __uuidof(IiTunes), reinterpret_cast<LPVOID *>(&pIiTunes));
if (pIiTunes != nullptr)
{
VARIANT data[16];
OLECHAR ver[4096] = L"vaneustroev#gmail.com";
pIiTunes->Authorize(1, data, (BSTR*)ver);
}
Then (pIiTunes->Authorize(1, data, (BSTR*)ver); ) I've got exception '...exception from address 0x000007FEFF4E4FCA (oleaut32.dll) ...Violation of access rights at address 0x000007FEFF4E4FCA...'
I don't know which parameters for pIiTunes->Authorize() I must set
I don't know what is the value of parameters that must be set, but I know the types of these parameters.
First one is a int32, second is a VARIANT reference, third is a array of BSTR. VARIANTs must be initialized and cleared after use, BSTRs must be allocated (a BSTR is not a OLECHAR *) and freed after use.
So, beyond the real semantics of the method, you can call it like this:
VARIANT data;
VariantInit(&data); // undercovers, this will just zero the whole 16-bytes structure
// ... do something with data here
BSTR ver = SysAllocString(L"vaneustroev#gmail.com"); // you should check for null -> out of memory
pIiTunes->Authorize(1, &data, &ver);
// always free BSTRs and clear VARIANTS
SysFreeString(ver);
VariantClear(&data);
If you use Visual Studio, there are cool Compiler COM Support Classes that ease VARIANT and BSTR programming considerably, as you could rewrite all this like this:
_variant_t data;
_bstr_t ver = L"vaneustroev#gmail.com";
BSTR b = ver;
pIiTunes->Authorize(1, &data, &b);
Visual Studio also provides a library called ATL that has other wrappers. Using them is similar:
CComVariant data;
CComBSTR ver = L"vaneustroev#gmail.com";
BSTR b = ver;
pIiTunes->Authorize(1, &data, &b);
For example:
int x=0;
int y=0;
where x and y are global variables, and in main() function we do the following:
x++;
y++;
How to get the newest value of global variables x and y in llvm.
when I try to do errs()<<g; they give the initial value as #BB0 = global i32
but I need to get the actual value like x=1, by using llvm.
Assuming you're using LLVM's API:
If the global is constant you can access its initialization value directly, for example:
Constant* myGlobal = new GlobalVariable( myLlvmModule, myLlvmType, true, GlobalValue::InternalLinkage, initializationValue );
...
Constant* constValue = myGlobal->getInitializer();
And if that value is of e.g. integer type, you can retrieve it like so:
ConstantInt* constInt = cast<ConstantInt>( constValue );
int64_t constIntValue = constInt->getSExtValue();
If the global isn't constant, you must load the data it points to (all globals are actually pointers):
Value* loadedValue = new LoadInst( myGlobal );
A global is basically a pointer. You can get the address in the host program via ExecutionEngine::getGlobalValueAddress and then you can dereference that address in order to get the stored value.
I've been trying to use libtooling to rename classes in source, and have hit a snag wrt function returns: there doesn't seem to be an API to get the source extent of just the return type.
I could hack it by assuming the return type is before the function id, but this doesn't handle trailing return types in C++11.
Does anyone have a better suggestion?
Thanks!
// simplified example replacing only value type returns
virtual void run(const ast_matchers::MatchFinder::MatchResult& Result) {
SourceManager& src = *result_.SourceManager;
const FunctionDecl* const function =
result_.Nodes.getDeclAs<FunctionDecl>("function");
CharSourceRange range = Lexer::makeFileCharRange(
CharSourceRange::getTokenRange(function->getLocStart(),
function->getLocation.getLocWithOffset(-1)),
src, LangOptions());
_replace->insert(Replacement(src, range, "newClass));
}
I currently stuck in a problem.
Below is the original code
sem_t s;
sem_init(&s, 0, 1);
And I need to replace sem_init with sem_open because it will be used on iOS
sem_t s;
sem_open("/s", O_CREAT, 0644, 1); //which will return sem_t*
How should I assign the return address to s?
Thanks
p.s. i do not declare sem_t* s, because this is a huge library which I won't change it too much
Create a new semaphore pointer,
sem_t *sptr;
Invoke sem_open as sptr holds the address,
sptr = sem_open("/s", O_CREAT, 0644, 1);
And below preprocessor macro should do the trick,
#define s *sptr
With the above method, when ever s is passed as argument, for example sem_wait(&s) boils to sem_wait(&*sptr) => sem_wait(sptr) which is desired without changing sem_t s.
I am trying to send a multipart MIME message with custom streaming (multiple binary files). To this end, I cannot get my CURLOPT_READFUNCTION callback to use a pointer set by CURLFORM_STREAM.
So far as I can tell, the CURLFORM_STREAM documentation automatically calls the CURLOPT_READFUNCTION pointer when it begins to stream data. This is not happening for me.
Here's my current code sample (I've been trying different configurations with no success). CURLCODECHECK and CURLFORMCHECK are macros that throw exceptions on an error. streams is a vector of my own StreamData structs.
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_HTTPPOST, 1L));
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_READFUNCTION, ::StreamReadFunction));
for (auto iter = streams.begin(); iter != streams.end(); ++iter)
{
std::string const & name = iter->first;
auto streamData = iter->second;
CURLFORMCHECK(curl_formadd(&m_Post, &last,
CURLFORM_COPYNAME, name.c_str(),
CURLFORM_FILENAME, streamData->fileName.c_str(),
CURLFORM_CONTENTTYPE, streamData->mimeType.c_str(),
CURLFORM_STREAM, (void *) streamData.get(),
CURLFORM_CONTENTSLENGTH, streamData->size,
CURLFORM_END));
}
My ::StreamReadFunction does get called, but unless I call curl_easy_setopt() with CURLOPT_READDATA set, it gets passed a null pointer for the fourth (void * userdata) argument.
In short, CURLOPT_HTTPPOST is not a replacement for CURLOPT_POST. Both must be provided and CURLOPT_POST must be set first.
I moved my curl_formadd() call to the top of the function, and followed it with:
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_POST, 1L));
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_POSTFIELDSIZE, fieldSize));
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_READFUNCTION, ::StreamReadFunction));
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_HTTPPOST, m_Post));
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_VERBOSE, 1L));
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_HEADER, 1L));
This then properly called my ::StreamReadFunction with my stream pointer.
Note that CURLOPT_POST must be set before CURLOPT_HTTPPOST for the stream callback to use the proper pointer (placing CURLOPT_POST later will cause a null pointer to be passed in).