As an exercise, I'm trying to create a wrapper for sqlite3. I've got the bridging header set up, and I can see the tool tips for the sqlite3 functions, but I can't figure out how to call sqlite3_open
sqlite3.h contains the following definitions of sqlite3 and sqlite3_open:
typedef struct sqlite3 sqlite3;
SQLITE_API int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
Which means that sqlite3_open takes as a trailing parameter a pointer to a pointer to an anonymous structure, which seems clear enough in the tooltip:
func sqlite3_open(filename: CString, ppDb: CMutablePointer<COpaquePointer>) -> CInt
Knowing that CMutablePointer means to pass in &T, the closest I've come is:
class Database {
var handle:COpaquePointer
init(file:String) {
let error = sqlite3_open(file as CString, &handle)
}
deinit {
sqlite3_close(handle)
}
}
There's no error on the sqlite3_close line, so I think I'm at least close, but the sqlite3_open line yields:
Cannot convert the expression's type 'CInt' to type '$T9'
Any clues on how to do this?
Please, no answers that say to use FMDB or other Objective-C based interfaces. As I said, this is at least partially an exercise in figuring out how to use C libraries from swift.
The problem is not with the handle parameter, but with the string conversion. The following works…
class Database {
var handle: COpaquePointer = nil
init(file: NSString) {
let error = sqlite3_open(file.cStringUsingEncoding(NSUTF8StringEncoding), &handle)
}
}
I'm unsure as to why the 'as CString' doesn't work.
When you add #import <sqlite3.h> into Bridging-Header, the sqlite3 C/C++ API will be 'translated' into native swift function. So, the sqlite3_open will be like below.
func sqlite3_open(file:String, inout ppdb:COpaquePointer) -> Int
And you can call this function with "String" type parameter instead of "CString". The swift compiler will translate "String" into UTF8 String data stream automatically.
let error = sqlite3_open(filePath, &db)
Related
I call a function from DLL-file in Inno Setup Script and its return type is PAnsiChar.
In order to get the whole string I need to dereference the pointer but the standard pascal syntax doesn't work here.
Is it even possible to do that?
function SQLDLL : PAnsiChar;
external 'GetSQLServerInstances#files:IsStartServer.dll stdcall setuponly';
function NextButtonClick(CurPage: Integer): Boolean;
var
hWnd: Integer;
Str : AnsiString;
begin
if CurPage = wpWelcome then begin
hWnd := StrToInt(ExpandConstant('{wizardhwnd}'));
MessageBox(hWnd, 'Hello from Windows API function', 'MessageBoxA', MB_OK or MB_ICONINFORMATION);
MyDllFuncSetup(hWnd, 'Hello from custom DLL function', 'MyDllFunc', MB_OK or MB_ICONINFORMATION);
Str := SQLDLL;
try
{ if this DLL does not exist (it shouldn't), an exception will be raised }
DelayLoadedFunc(hWnd, 'Hello from delay loaded function', 'DllFunc', MB_OK or MB_ICONINFORMATION);
except
{ handle missing dll here }
end;
end;
Result := True;
end;
I have only the DLL-file. The original language is Delphi.
I updated to the latest version of Inno Setup 6.0.3 and tested this code on my home Windows 10 Pro machine:
[Setup]
AppName=My Program
AppVersion=1.5
WizardStyle=modern
DefaultDirName={autopf}\My Program
DisableProgramGroupPage=yes
DisableWelcomePage=no
UninstallDisplayIcon={app}\MyProg.exe
OutputDir=userdocs:Inno Setup Examples Output
[Files]
Source: "MyProg.exe"; DestDir: "{app}"
Source: "MyProg.chm"; DestDir: "{app}"
Source: "Readme.txt"; DestDir: "{app}"; Flags: isreadme
Source: "IsStartServer.dll"; Flags: dontcopy
[Code]
function SQLDLL : PAnsiChar;
external 'GetSQLServerInstances#files:IsStartServer.dll stdcall';
function NextButtonClick(CurPage: Integer): Boolean;
var
Str : PAnsiChar;
begin
Str := SQLDLL;
Result := True;
end;
and now I'm having this kind of error:
I don't understand why does it have to look into my 'temp' directory? I've also heard that this problem may somehow be connected with the group policies in Windows 10 UAC, but I'm not really sure what should I do here to get rid of this error.
If I understand correctly, your SQLDLL manages some memory buffer itself and returns a pointer to a Unicode string (not ANSI, that's why you got only one character when you tried PAnsiChar, according to your comment).
Inno Setup doesn't support this directly and doesn't even have a PWideChar type. However, we can handle it ourselves. We just have to allocate a Inno string with the right size and copy the data manually.
Here is a working example how to do that. It uses GetCommandLineW as an example function that returns a PWideChar, but you can do the same with your SQLDLL function.
Get the pointer from the external function and store it in a variable (a Cardinal - in my example I created a typedef PWideChar for it).
Get the string length using lstrlenW.
Create an empty regular String, but set it to the right length using SetLength. This will reserve enough capacity that we can write the actual contents into it in the next step.
Use lstrcpyW to copy the string that's referenced by the pointer to your regular String variable.
(In case you use the ANSI version of Inno Setup: Use WideCharToMultiByte instead, see my update at the end of this post.)
The trick is to import lstrcpyW in such a way that the destination pointer is declared as String but the source pointer is declared as Cardinal (or my typedef PWideChar here).
type
PWideChar = Cardinal; { Inno doesn't have a pointer type, so we use a Cardinal instead }
{ Example of a function that returns a PWideChar }
function GetCommandLineW(): PWideChar;
external 'GetCommandLineW#kernel32.dll stdcall';
{ This function allows us to get us the length of a string from a PWideChar }
function lstrlenW(lpString: PWideChar): Cardinal;
external 'lstrlenW#kernel32.dll stdcall';
{ This function copies a string - we declare it in such a way that we can pass a pointer
to an Inno string as destination
This works because Inno will actually pass a PWideChar that points to the start of the
string contents in memory, and internally the string is still null-terminated
We just have to make sure that the string already has the right size beforehand! }
function lstrcpyW_ToInnoString(lpStringDest: String; lpStringSrc: PWideChar): Integer;
external 'lstrcpyW#kernel32.dll stdcall';
function InitializeSetup(): Boolean;
var
returnedPointer: PWideChar; { This is what we get from the external function }
stringLength: Cardinal; { Length of the string we got }
innoString: String; { This is where we'll copy the string into }
begin
{ Let's get the PWideChar from the external function }
returnedPointer := GetCommandLineW();
{ The pointer is actually just a renamed Cardinal at this point: }
Log('String pointer = ' + IntToStr(returnedPointer));
{ Now we have to manually allocate a new Inno string with the right length and
copy the data into it }
{ Start by getting the string length }
stringLength := lstrlenW(returnedPointer);
Log('String length = ' + IntToStr(stringLength));
{ Create a string with the right size }
innoString := '';
SetLength(innoString, stringLength);
{ This check is necessary because an empty Inno string would translate to a NULL pointer
and not a pointer to an empty string, and lstrcpyW cannot handle that. }
if StringLength > 0 then begin
{ Copy string contents from the external buffer to the Inno string }
lstrcpyW_ToInnoString(innoString, returnedPointer);
end;
{ Now we have the value stored in a proper string variable! }
Log('String value = ' + innoString);
Result := False;
end;
If you put this into an installer and run it, you see output like this:
[15:10:55,551] String pointer = 9057226
[15:10:55,560] String length = 106
[15:10:55,574] String value = "R:\Temp\is-9EJQ6.tmp\testsetup.tmp" /SL5="$212AC6,121344,121344,Z:\Temp\testsetup.exe" /DEBUGWND=$222722
As you can see, the command line string (which we get as a PWideChar) is copied to a regular string variable correctly and can be accessed normally at the end.
Update: In case you are using the ANSI version of Inno Setup and not Unicode, this code alone won't work. The change needed is this: Instead of using lstrcpyW, you'd use WideCharToMultiByte:
function WideCharToMultiByte_ToInnoString(CodePage: Cardinal; dwFlags: Cardinal; lpWideCharStr: PWideChar; cchWideChar: Cardinal; lpMultiByteStr: String; cbMultiByte: Cardinal; lpDefaultChar: Cardinal; lpUsedDefaultChar: Cardinal): Integer;
external 'WideCharToMultiByte#kernel32.dll stdcall';
{ Later on: Instead of calling lstrcpyW_ToInnoString, use this:
Note: The first parameter 0 stands for CP_ACP (current ANSI code page), and the
string lengths are increased by 1 to include the null terminator }
WideCharToMultiByte_ToInnoString(0, 0, returnedPointer, stringLength + 1, innoString, stringLength + 1, 0, 0);
You cannot dereference a pointer in Inno Setup Pascal Script.
But there are numerous hacks that allow that. Those hacks are very specific, so it depends on particular use case.
Though in your specific case, as pointers to character arrays are widespread in APIs, Inno Setup Pascal Script (similarly to Delphi) can assign a pointer to a character array to a string.
So, you should be able to simply assign the PChar to AnsiString:
function ReturnsPAnsiChar: PAnsiChar; extern '...';
var
Str: AnsiString;
begin
Str := ReturnsPAnsiChar;
end;
See How to return a string from a DLL to Inno Setup?
Can some one help me understand why it's failing to use the syntax like [Error 1] and [Error 2]?, why [ok 1] is possible and working just fine.
Is the basic design to use Animal as field to serve as generic type good? or any thing bad about it? or any better solution suggested?
package main
import (
pp "github.com/davecgh/go-spew/spew"
)
type Cat struct {
Name string
Age int
}
type Animal interface{}
type House struct {
Name string
Pet *Animal
}
func config() *Animal {
c := Cat{"miao miao", 12}
// return &Animal(c) //fail to take address directly [Error 1]
// return &(Animal(c)) //fail to take address directly [Error 2]
a := Animal(c) //[Ok 1]
return &a
}
func main() {
pp.Dump(config())
pp.Dump(*config())
pp.Dump((*config()).(Cat)) //<-------- we want this
pp.Dump((*config()).(Cat).Name)
pp.Dump("---------------")
cfg := config()
pp.Dump(&cfg)
pp.Dump(*cfg)
pp.Dump((*cfg).(Cat)) //<-------- we want this
pp.Dump((*cfg).(Cat).Name)
pp.Dump("---------------")
}
Ok, two thing:
You cannot take the address of the result of a conversion directly, as it is not "addressable". See the section of the spec about the address-of operator for more information.
Why are you using a pointer to an interface at all? In all my projects I have only ever used an interface pointer once. An interface pointer is basically a pointer to a pointer, sometimes needed, but very rare. Internally interfaces are a type/pointer pair. So unless you need to modify the interface value instead of the value the interface holds then you do not need a pointer. This post may be of interest to you.
Let's assume I have this struct with a method:
package main
import (
"fmt"
"reflect"
)
type MyStruct struct {
}
func (a *MyStruct) AAction() {
fmt.Println("Hello a")
}
Now, if I want to call the method "AAction" by string, I can use reflection (this works):
func main() {
reflect.New(reflect.TypeOf(MyStruct{})).MethodByName("AAction").Call([]reflect.Value{})
}
The problem is, that I don't want to use MyStruct{} as an expression, but as a string. Of course this doesn't work:
func main() {
theStruct := "MyStruct"
theAction := "AAction"
reflect.New(reflect.TypeOf(theStruct)).MethodByName(theAction).Call([]reflect.Value{})
}
because reflect.Typeof(theStruct) would be a string.
I tried reading through the documentation, sadly, I can't find anything very useful.
I found this similar question: Call a Struct and its Method by name in Go?
Under the accepted question, the OP asks:
The issue in my case Is I cant not declare t is typed T, its must be some how I can declare t typed T by the name of T is string "T"
which gets answered by
[...] I would suggest to match the name against the string "T" somewhere in your code [...]
which doesn't solve the problem, as I would still need to call MyStruct{} somewhere.
The question is: is there any way to use a struct by giving the name as a string? (without manually mapping the the name of the struct to the struct)
Working version with using reflect.TypeOf(MyStruct{}):
PlayGround
Not working version, obviously calling the method on a string: PlayGround
Sorry, you can't. The answer is: you could not. There is no builtin or pre-initialized registry of type names.
To get started with reflection (reflect package), you need a value (of the type in question). Based on a string (string name of the type), you can't acquire a value of that type, so you can't get started.
If you do want to do what you want only by a string type name, you need to build your own "registry" prior to doing what you want.
I am trying to write a csv parser using the example provided here. It works great for all native types but I am having trouble with any structs that contain a timestamp of type time.Time. It exits with an error of "cannot convert this type".
This is the code.
//For each field in a given struct...
//Get a field
val := sv.Field(i)
// this is necessary because Kind can't tell
// distinguish between a primitive type
// and a type derived from it. We're looking
// for a Value interface defined on
// the pointer to this value
_, ok := val.Addr().Interface().(Value)
if ok {
val = val.Addr()
kind = value_k
} else {
switch Kind {
case reflect.Int, reflect.Int16, reflect.Int8,
reflect.Int32, reflect.Int64:
kind = int_k
case reflect.Uint, reflect.Uint16, reflect.Uint8,
reflect.Uint32, reflect.Uint64:
kind = uint_k
case reflect.Float32, reflect.Float64:
kind = float_k
case reflect.String:
kind = string_k
default:
// Kind is Struct here
kind = value_k
_, ok := val.Interface().(Value)
if !ok {
err = os.NewError("cannot convert this type ")
this = nil
return
}
}
}
What this code does is take an interface and a reader. It attempts to match the field headers in the reader (csv file) with field names in the interface. It also reflects on the interface (struct) and collects positional a type information for later setting the fields in the iterator. It is this step that is failing for non-native types.
I've tried a few methods to work around this but the only thing that seems to work is changing the timestamp to a string. I am undoubtedly missing something and would greatly appreciate some guidance.
In Swift the ampersand sign & is for inout parameters. Like
var value = 3
func inoutfunc(inout onlyPara: Int) {
onlyPara++
}
inoutfunc(&value) // value is now 4
That doesn't look like onlyPara is a pointer, maybe it is and get dereferences immediately when using it inside the function.
Is onlyPara a pointer?
When I don't need a IntPointer type, why are the framework methods using a NSErrorPointer type? Because they can't change the methods because of existing Objective-C code?
But why is then Swift converting &error to NSErrorPointer, is that autoboxed?
var errorPtr: NSErrorPointer = &error
And when I have a NSErrorPointer. How do I dereference it?
var error: NSError = *errorPtr // won't work
Maybe someone can enlighten me. Using only Swift is easy. I think the questions are one chunk of knowledge over & between swift and Objective-C (as the address of operator)
Solution to 4. I found out how to dereference it:
var error: NSError = errorPtr.memory!
I suggest you read the Pointers section of the Using Swift with Cocoa and Objective-C guide: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/doc/uid/TP40014216-CH8-XID_16
There is a table at the bottom of the Pointers section, which explains how class pointers bridge to Swift pointer types. Based on that, the NSError pointer should be AutoreleasingUnsafePointer<NSError>. Searching trough the headers for NSErrorPointer yields this:
typealias NSErrorPointer = AutoreleasingUnsafePointer<NSError?>
Why the extra ? after NSError? I guess it's because NSError can also be nil.
Hope it helps!
Swift 3
var errorPtr: NSErrorPointer = nil
callSomeFunctionThatReceivesParamByReference(.., error: errorPtr)
if let error = errorPtr?.pointee { ... }