How to make Unified FFI work in Pharo - pharo

I have a C function that copies a string into a buffer that's been passed to it:
void get_machine(char *buf) {
/* do something to acquire the machine string */
strcpy(buf, machine_string);
}
I want to call it from Pharo:
machine := String new: 256.
self ffiCall: #( void get_machine(String machine) ) module: 'ffilibc.so'.
But this doesn't work: the contents of machine_string do not get copied into machine. What is the correct way to do this?

I learned that the String buffer is immutable. That's why the C function couldn't write to it.
The solution is to use a ByteArray.

"It does not work" is too vague. Can you tell me what's your error?
in case is "module not found", this is because you need to give the full path (unless library is in same place as the image). Also remember the library needs to be compiled for 32bits.

Related

String^ to LPCTSTR in VC++2010 (Windows form application)

How to convert System::string^ in to LPCTSTR ?
As my requirement is to clone a file using function CopyFile, it works fine if i give Fix name (OldFile.jpg and LatestFile.jpg) to its parameters (below Code: Works Fine)
LPCTSTR in_f,out_f;
in_f = _T("d:\\Old.jpg");
out_f = _T("d:\\Latest.jpg");
CopyFile(in_f,out_f,false);
above code clone the Old.jpeg in to a Latest.jpg but when i trying to give name (Latest.jpg) which is coming out from some String it won't create file (below Code: NOT Working)
String^ Name = "Latest";
//------Capture Current Date & Time
DateTime datetime = DateTime::Now;
//-------Convert Date Timt in to String
Name = Name + String::Format("{0}",datetime);
Name = Name->Replace('/','-');
Name = Name->Replace(':','-');
Name = Name + ".jpg";
LPCTSTR in_f,out_f;
in_f = _T("d:\\Old.jpg");
out_f = (LPCTSTR)Name; //Trying to Assign Current Latest file Name With date Time here
CopyFile(in_f,out_f,false);
The Problem is CopyFile Took LPCTSTR type as an argument , where as i am giving a type System::string^, So suggest me how to convert this System::string^ in to LPCTSTR so that i can add the current date time with in the name of my file.
I am Using VC++2010 and Windows form Application
Standard warning: While it's certainly possible to write the main body of your application in C++/CLI, or even write the GUI in C++/CLI using WinForms, it is not recommended. C++/CLI is intended for interop scenarios: where C# or other .Net code needs to interface with unmanaged C++, C++/CLI can provide the translation between the two. For primary development, it is recommended to use C# with either WinForms or WPF if you want managed code, or C++ with MFC if you want unmanaged.
I'm not sure I agree with Hans's comment that TCHAR is obsolete, but doing an explicit conversion to a wide string and calling CopyFileW is a good option.
Also, one could go the other direction, and convert from unmanaged to managed strings, and use the .Net method to copy files, File::Copy(String^, String^, Boolean).
To convert to a LPCTSTR, I would use marshal_as. Because it's implemented with templates, the compiler will resolve your LPCTSTR to call either the LPCSTR or LPCWSTR version, as appropriate.
Microsoft doesn't have dedicated documentation pages for each templated version of marshal_as, but the Overview of Marshaling in C++ page is a good place to start.
My test program:
#include <msclr\marshal.h>
int main(array<System::String^>^ args)
{
String^ managedStr = "I came from managed land!\r\n";
// This controls the lifetime of the LPCTSTR that marshal_as returns.
// When this goes out of scope, the LPCTSTR will no longer be valid,
// so be aware of its lifetime.
msclr::interop::marshal_context context;
LPCTSTR unmanagedStr = context.marshal_as<LPCTSTR>(managedStr);
OutputDebugString(unmanagedStr);
return 0;
}
Result:
I came from managed land!
You need to append a \0 character at the end of the Name string, since CopyFile() expects zero-terminated strings.
EDIT: As LucasTrzesniewski has pointed out, pinning a .NET string automatically yields a zero-terminated character array. This is documented in the C# specification. See the comments below for more information.
Moreover, you have to "pin" the string in memory, so the garbage collector won't move it around. Then you can create a pointer to the first character of the string. C++/CLI provides some utility types and functions to do this. Here's an example:
pin_ptr<const WCHAR> psName = PtrToStringChars (Name)
PtrToStringChars() is an inline function declared in vcclr.h. psName should be assignable to a LPCTSTR parameter - if not, use a cast. Note that PtrToStringChars() doesn't work if the input string is a nullptr. You need to test explicitly for this case. (However, in your case, Name is certainly not a nullptr).
The String remains pinned until the variable psName gets out of scope. This happens after leaving the { ... } block in which it's declared, e.g. after leaving the current function. No explicit unpinning is needed.
You need to marshaling it to "const char *" and make a static_cast to LPCTSTR.
Take a look at this https://msdn.microsoft.com/en-us/library/bb384865.aspx

variable does not properly update

Xilinx SDK 2016.1 freeRTOS823_xlinx OS platform
My code seemed to work fine until I introduced some freeRTOS elements. The general functionality of my code as follows:
In the Interrupt subroutine, I assign a value to a variable focusPosition that is read from the IP register of the Zynq Soc:
// separate file
u32 focusPosition=0;
static void ISR(void *CallbackRef)
{
focusPosition = XRb_focus_Get_position_o(CallbackRef);
}
Then I printf the value to the console in the main function:
// separate file
extern u32 focusPosition;
main{
...
while(1){
sleep(1);
xil_printf("%d\n",focusPosition);
}
}
The code prints the correct value, however, when I try to implement some additional lines in the code, like xTaskCreate() xEventGroupCreate(), something messes up all the memory and the printed value stays constant, which is not correct.
How can simple addition of the code that has nothing to do with the variable have any influence on that variable? As far as I understand, the xTaskCreate() and xEventGroupCreate() are created on the heap. I tired pocking around to see if Xil_DCacheDisable() would help, but no. Any ideas? Is my focusPosition variable properly defined/declared?
You should declare focusPosition as volatile otherwise the compiler does not expect it to be modified outside of the while loop so may optimize the code. Adding extra code may of caused this to happen. Any variable modified in an interrupt but used elsewhere should be declared volatile.

Converting LPCTSTR to LPWSTR

using MFC and Unicode-Build
i want to change the colum-header-text of a listctrl and to do so i have to convert an LPCTSTR to an LPWSTR. what i do now is
void CSPCListViewCtrl::SetHeaderText(long lCol, LPCTSTR lColText)
{
CListCtrl& ListCtrl = GetListCtrl();
LV_COLUMN lvc;
::ZeroMemory((void *)&lvc, sizeof(LVCOLUMN));
lvc.mask |= LVCF_TEXT;
ListCtrl.GetColumn(lCol, &lvc);
lvc.pszText = const_cast<LPWSTR>(lColText);
ListCtrl.SetColumn(lCol, &lvc);
}
it seems to work but the const_cast looks somewhat strange and wrong to me so i tried out something like
USES_CONVERSION;
lvc.pszText = CT2W(lColText);
this seems to work in release-build but produces garbage in debug-build so i wonder what is the correct way to do it?
TL;DR: Using const_cast<LPTSTR>(lColText) is safe when calling CListCtrl::SetColumn.
But why then is the pszText member of the LVCOLUMN structure declared non-const? The LVCOLUMN structure is used both to set and retrieve information. When retrieving a column's text, you need to pass in a modifiable buffer (and length argument). When setting a columns text, on the other hand, the system uses the pszText member and internally stores a copy. It does not attempt to write to it. This is documented as well, even if very subtly:
cchTextMax
Size in TCHARs of the buffer pointed to by the pszText member. If the structure is not receiving information about a column, this member is ignored.
This is a common pattern in the Windows API, where the same structure is used both as an input and output parameter. The only option to work around this would have been to introduce a const-ified version for those structures. When the Windows API was invented 30 years ago, this wasn't deemed necessary or useful. Besides, it would have made a common pattern (read-update-write) more tedious and error prone, as the data would have to be manually copied between unrelated types.
Now that you know, that using a const_cast is safe in the scenario you described, you may be wondering, if it is a good idea to use it. That depends on a number of factors, e.g.
Can you come up with a helpful comment to concisely explain, why this is ok? Something along the lines of // Totally safe, it's just that M$ sucks probably won't cut it.
Will all members on your team understand the implications, or will this present a red herring in heap corruption debug sessions?
Do you have coding guidelines that allow the use of const_casts?
Are you using static code analysis tools that won't produce false positives for const_casts?
If you find that you cannot satisfactorily answer all those questions, you may consider implementing (technically unnecessary) manual copying (and exchange a const_cast for exception handling):
void CSPCListViewCtrl::SetHeaderText(long lCol, LPCTSTR lColText) {
CListCtrl& ListCtrl = GetListCtrl();
LVCOLUMN lvc = {0};
lvc.mask |= LVCF_TEXT;
// Create modifiable copy of lColText
size_t colTextLength = _tcslen(lColText);
std::vector<TCHAR> buffer(colTextLength + 1);
std::copy(lColText, lColText + colTextLength + 1, buffer.data());
lvc.pszText = buffer.data();
ListCtrl.SetColumn(lCol, &lvc);
}
One more note on your use of character string encodings: You are mixing the use of Generic-Text Mappings with explicit Unicode (UTF-16LE) encoding. To add consistency, you should change the lColText argument to type LPCWSTR, and use an LVCOLUMNW structure (as well as a const_cast<LPWSTR> if you decide to go that route). Unfortunately, when using MFC, you will have to resort to using the generic-text mappings when calling any class members. But at least you will get a compiler error in case of mismatching character encodings.
You can use CString::GetBuffer()
void SetHeaderText(long lCol, LPCTSTR lColText)
{
LV_COLUMN lvc;
::ZeroMemory((void *)&lvc, sizeof(LVCOLUMN));
lvc.mask |= LVCF_TEXT;
list.GetColumn(lCol, &lvc);
CString str = lColText;
lvc.pszText = str.GetBuffer();
list.SetColumn(lCol, &lvc);
str.ReleaseBuffer();
//ReleaseBuffer is option in this case because
//"str" is local variable and is destroyed before being used again*
}
SetHeaderText(0, L"text");
In UNICODE, LPTSTR is just LPWSTR (or simply wchar_t*)
If for some reason you have ANSI text, then you can use CString for conversion
CStringA ansi = "Text";
CStringW wide = CStringW(ansi);
SetHeaderText(0, wide);
See also
CString::GetBuffer()

How to import platform-specific struct?

I've got a struct in a file that begins with this line:
// +build windows
Therefore it will only be built on Windows. However, the part of the application that initializes everything needs to check if it is running on Windows and if so, create an instance of the struct. I have no idea how to do this without breaking things on other platforms.
For example, if the file contains a function newWindowsSpecificThing() and I compile on Linux, the function won't exist because it is defined in a file that isn't being compiled. (And, of course, this will produce an error.)
How do I work around this dilemma?
I think your solution would be to have some method on your struct which is used on all platforms. Look at how the dir_*.go files work for the os package. The func (file *File) readdirnames(n int) (names []string, err error) is available on all platforms by providing it in dir_plan9.go, dir_unix.go and dir_windows.go.
For your problem, I'd take the same approach but with some generic method that does internal work. In your application logic you'd call that function and in your file_unix.go file you'd define that function to do nothing (empty body).
Somewhere you clearly have a function that calls newWindowsSpecificThing(). That should be in a Windows-specific file. If it were, then it wouldn't matter that it isn't available. The fact that you have something "check if it is running on Windows" suggests a if runtime.GOOS == "windows" statement somewhere. Rather than have that, move the entire if into a function that is defined in a Windows-specific file. You'll also need to define that function in a !windows file, which is fine.
As an example from my code, I have a function:
func Setup() *config {
var cfg *config
// setup portable parts of cfg
return PlatformSpecificSetup(cfg)
}
I then have a file marked // +build windows that defines PlatformSpecificSetup() one way, and another marked // +build !windows that defines it another. I never have to check runtime.GOOS and I never have to deal with undefined data types. The config struct itself is defined in those files, so it can have different fields for each platform (as long as they agree enough for Setup()). If I were being more careful, I could create a struct like:
type config struct {
// independent stuff
plat *platformConfig
}
And then just define platformConfig in each platform file, but in practice I've found that more trouble than it's worth.

Stack issues when calling a DLL compiled with Visual C++ in GCC

I'm trying to call some functions in a DLL compiled with (I believe) Visual C++ from my program, which is compiled using GCC.
To call the functions in the DLL, I do a LoadLibrary() on the DLL, and then a GetProcAddress() to get the address of a particular function, which I then call. This function returns a list of pointers to the functions in the DLL I'm to call.
Well, when I try to call those functions, they don't work properly. I ran my program through a debugger, and it looks like the DLL library function is looking for one of the passed arguments at ebp+8, even though GCC has put it at ebp-24.
It looks definitely like a stack issue. What's more, when the GCC program function which calls the DLL function returns, my program crashes -- so something screwey is going on with the stack. Does anyone know what I need to do in order to fix this? I'm not able to access the DLL code.
Also: I tried putting __cdecl and __stdcall before the DLL function definition in my program's source file, but this changes nothing.
Looks like a calling convention problem. Make sure you're putting the calling convention tag in the right place. With GCC, it should look like this:
typedef int (__stdcall *MyFunctionType)(int arg1, const char *arg2);
MyFunctionType myFunction = (MyFunctionType)GetProcAddress(myModule, "MyFunction");
// check for errors...
int x = myFunction(3, "hello, world!");
[EDIT]
Looks like your problem has nothing to do with calling conventions (although getting them right is important). You're misusing BSTRs -- a BSTR is not a simple char* pointer. It's a pointer to a Unicode string (wchar_t*), and furthermore, there is a 4-byte length prefix hidden before the first characters of the string. See MSDN for full details. So, the call to SetLicense() should look like this:
BSTR User = SysAllocString(L""); // Not sure if you can use the same object here,
BSTR Key = SysAllocString(L""); // that depends on if SetLicense() modifies its
// arguments; using separate objects to be safe
// check for errors, although it's pretty unlikely
(textCapLib.sdk)->lpVtbl->SetLicense((textCapLib.sdk), User, Key);
SysFreeString(User); // Hopefully the SDK doesn't hang on to pointers to these
SysFreeString(Key); // strings; if it does, you may have to wait until later to
// free them

Resources