For oleautomation type, there are VT_xxx types:
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = m_cPoints;
psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
For custom types, there is IRecordInfo:
SafeArrayCreateEx(VT_RECORD, 1, &rgbounds, pRecInfo);
But what is the right type for windows' system type such as POINT?
POINT is not an OLE-compatible type. VT_RECORD only works for custom types that are defined in a TypeLibrary. You will have to either:
create a TypeLibrary that replicates POINT and then retrieve IRecordInfo from the TypeLibrary
create a safearray of bytes (VT_UI1) instead and then copy the raw POINT bytes into it. The receiver will then have to read the bytes according.
Related
Example:
type MyString string
var s = "very long string"
var ms = MyString(s)
var s2 = string(s)
Are ms or s2 a full copy of s (as it would be done with []byte(s))? Or they are just a string struct copies (which keeps the real value in a pointer)?
What if we are passing this to a function? E.g.:
func foo(s MyString){
...
}
foo(ms(s)) // do we copy s here?
Spec: Conversions:
Specific rules apply to (non-constant) conversions between numeric types or to and from a string type. These conversions may change the representation of x and incur a run-time cost. All other conversions only change the type but not the representation of x.
So converting to and from the underlying type of your custom type does not make a copy of it.
When you pass a value to a function or method, a copy is made and passed. If you pass a string to a function, only the structure describing the string will be copied and passed, since strings are immutable.
Same is true if you pass a slice (slices are also descriptors). Passing a slice will make a copy of the slice descriptor but it will refer to the same underlying array.
Why the below doesn't work?
locations := make([]*LocationEvent, 0)
data := make([]Event, 0)
data = append(data, locations...)
where *LocationEvent (struct) implements Event (interface).
While the below works fine:
data = append(data, &LocationEvent{}, &LocationEvent{})
So how it is different when expanding the actual []*LocationEvent slice using ...?
The slice type must match the type of the variadic arguments in the append function exactly. locations is of type []*LocationEvent, and thus not compatible with []Event. There is no automatic "downcasting" in Go when working with slices.
You have to copy the locations to a new slice of Event, or add the items of locations one-by-one to the data slice.
For more explanation look here: https://stackoverflow.com/a/12754757/6655315
What is the idiomatic way to deal with unsized arrays in Go? I'm working on the ETW wrappers and the TdhGetEventInformation function fills in the provided memory buffer with event information. The event metadata is represented by TRACE_EVENT_INFO structure, which has an array member declared as:
EVENT_PROPERTY_INFO EventPropertyInfoArray[ANYSIZE_ARRAY];
I'm calling the TdhGetEventInformation function in a way that the provided buffer has enough space to populate event properties array:
var bufferSize uint32 = 4096
buffer := make([]byte, bufferSize)
tdhGetEventInformation.Call(
uintptr(unsafe.Pointer(eventRecord)),
0, 0,
uintptr(unsafe.Pointer(&buffer[0])),
uintptr(unsafe.Pointer(&bufferSize)),
)
However, since I'm tempting to model the Go counterpart struct with EventPropertyInfoArray field as
EventPropertyInfoArray [1]EventPropertyInfo
the compiler is not able to re dimension the array according to the number of available properties for each event, so I end up with one-array item.
Do you have any smart ideas on how handle this edge case?
Thanks in advance
So you want a variable sized array in Go? Use a slice?
EventPropertyInfoArray [1]EventPropertyInfo
Would be
EventPropertyInfoArray []EventPropertyInfo
If you have a rough idea of a maximum it could hold you could make an array using make something like this, but this wouldn't help you out in declaring a struct:
EventPropertyInfoArray = make([]EventPropertyInfo, len, capacity)
After lots of trial and error, I managed to get the right slice from the backing array through standard technique for turning arrays into slices:
properties := (*[1 << 30]EventPropertyInfo)(unsafe.Pointer(&trace.EventPropertyInfoArray[0]))[:trace.PropertyCount:trace.PropertyCount]
I have this declared above:
char PandaImage[] = "images/panda.png";
SDL_Texture* PandaTexture = nullptr;
I have a function to create textures:
void LoadMedia( SDL_Texture *ThisTexture, char *Image )
{
SDL_Surface* TempSurface = nullptr;
.......................
ThisTexture = SDL_CreateTextureFromSurface( gRenderer, TempSurface );
I call it as:
LoadMedia( PandaTexture, PandaImage );
It builds, logs the image loaded and texture created, but no image
If I hard change the line ( use Panda directly instead of This ):
PandaTexture = SDL_CreateTextureFromSurface( gRenderer, TempSurface );
My image is there.
I have always had trouble with & * and passing.
Is there a good, simple help for me?
Thanks for your kind help - back to Google for now
In short, I think you could solve your problem by changing the function to:
void LoadMedia( SDL_Texture** thisTexture, char* Image)
{
...
(*thisTexture) = SDL_CreateTextureFromSurface( gRenderer, TempSurface);
}
And by calling the function using:
LoadMedia( &PandaTexture, PandaImage);
An explanation:
Variables and Pointers
A variable is used to store data (a primitive or a class instance). For example:
int a = 10;
stores an integer in memory. This means, that symbol 'a' now represents number 10, which is stored somewhere in your computer's memory as 4 bytes.
A pointer is used to store an address (this address points towards a variable). For example:
int* a_address = 1234;
says that there is an integer stored at address 1234 in your computer's memory. A pointer always takes up the same amount of space (4 bytes on a 32 bit machine and 8 bytes on a 64 bit machine), as it simply stores an address.
Getting the Address of a Variable [&]
You will rarely ever set the address of a pointer yourself. Often, pointers are the result of a "new" call. Using "new" reserves memory to store an instance of the class you want to create, and returns the address of the object. In essence, it says: "I created an object for you, and you can find it at this location in your memory".
Alternatively, when you have a normal variable (primitive of class instance), you can find its address by using the & character. For example:
int a = 10;
int* a_address = &a;
says: "store the location of variable a in pointer a_address. Why would you do this? Say you have a very large instance (for example an SDL_Texture consisting of many, many pixels) and you want to pass it to a function (or pass it back outside of the function). If you were to pass it to the function as SDL_Texture thisTexture, you are copying the entire object (a so-called pass by value). This is time consuming. Alternatively, you could simply pass the address to the function, as an SDL_Texture * thisTexture. This is a so called pass by reference, and it is much faster as you can imagine.
Getting the Variable at an Address [*]
Obviously, if you have an address, you also need a way to get the actual variable at that address. This is done using the * character. It is called "dereferencing". For example:
int a = 10;
int* a_address = &a;
int b = (*a_address);
This last line says: "Give me the variable, stored at address a_address, and put it in b".
Function Parameters Going Out-of-scope
When a function ends, its local variables (including parameters) go out-of-scope. This means that their memory is freed (for variables, not for dynamically allocated objects stored as pointers!). Their values will be forgotten. In your case, you are passing an SDL_Texture * as a parameter. This means, a copy is made of the address stored in PandaTexture. This address is copied over to thisTexture. You then write the return value of SDL_CreateTextureFromSurface to thisTexture. Next the function ends, and thisTexture goes out-of-scope. As a result, the location of your SDL_Texture (the SDL_Texture * pointer) is lost forever. You actually want to store the address to pointer PandaTexture, but as you can see, the address is only written to thisTexture.
Solution: How to Fix your Function
We can fix this by passing a pointer, to your pointer called PandaTexture. A "pointer to a pointer" is written as:
SDL_Surface** thisTexture;
We want to pass the address of pointer PandaTexture to this. This way, we can write to PandaTexture from inside your method! After all, we know where PandaTexture stores its pointer in memory, allowing us to change it. To actually put the address of PandaTexture in it, we need to use the & character in the function call as such:
LoadMedia(&PandaTexture, PandaImage);
Next, inside of our function, we want to change the value of PandaTexture. However, we were passed &PandaTexture and not PandaTexture itself. To write the value of &PandaTexture (the address where our texture will be stored), we need dereferencing, as such:
(*thisTexture) = SDL_CreateTextureFromSurface(gRenderer, TempSurface);
This works because: "thisTexture is a pointer to a pointer to an SDL_Texture (aka an SDL_Texture**). By dereferencing it, we obtain a pointer to an SDL_Texture (aka an SDL_Texture*). Here we can store the return value of the SDL_CreateTextureFromSurface function.
Why do we not run into out-of-scope issues here? Parameter thisTexture will still go out of scope, and its value will be forgotten. But! We didn't write to thisTexture, instead we wrote our SDL_Texture * pointer to the address that thisTexture points to! This bit of memory is not cleared due to scoping, so we can view the results from outside the function!
In summary, you can solve your problem using a pointer to a pointer. I hope the above clears up the concepts of pointers, variables, addresses and dereferencing a bit!
I am trying to implement device mapper target by referring to the already existing ones dm-linear, dm-snapshot, dm-cache etc. In my implementation, I need to perform a read/modify/write operation on a certain sector range. Since the device mapper directly talks to the block layer, I am not sure what data structures/functions to use to read the sectors in the memory, modify the buffer and write it back to another sector range.
At the application level, we have syscalls and below we have vfs_read/vfs_write. Is there anything similar for device mapper layer?
I have been stuck here for very long. Any help will be appreciated.
NOTE: My answer is related to kernel version < 3.14, because since 3.14 API is slightly changed.
In kernel you read/write certain sectors with struct bio. This struct is used for all block level I/O. Comprehensive documentation can be found in kernel and on lwn. These are the several most significant members of this structure:
bio->bi_sector - first sector of block I/O request
bio->bi_size - size of I/O request
bio->bi_bdev - device to read/write
bio->bi_end_io - callback that kernel will call on the end of request
What you do in device mapper target is map incoming bio. When you creating your device mapper target you supply at least 2 callbacks: ctr, and map. For example, the simplest device-mapper target dm-zero declares it's callbacks as following:
static struct target_type zero_target = {
.name = "zero",
.version = {1, 1, 0},
.module = THIS_MODULE,
.ctr = zero_ctr,
.map = zero_map,
};
map is a key callback - it's a heart of every device-mapper target. map receive incoming bio and it can do anything with it. For example, dm-linear just shift sector of every incoming bio by predefined offset. See the code:
static sector_t linear_map_sector(struct dm_target *ti, sector_t bi_sector)
{
struct linear_c *lc = ti->private;
return lc->start + dm_target_offset(ti, bi_sector);
}
static void linear_map_bio(struct dm_target *ti, struct bio *bio)
{
struct linear_c *lc = ti->private;
bio->bi_bdev = lc->dev->bdev;
if (bio_sectors(bio))
bio->bi_sector = linear_map_sector(ti, bio->bi_sector);
}
static int linear_map(struct dm_target *ti, struct bio *bio)
{
linear_map_bio(ti, bio);
return DM_MAPIO_REMAPPED;
}
Because map receives pointer to bio it can change value under that pointer and that's it.
That's how you map I/O requests. If you want to create your own requests then you must allocate bio, fill it's sector, device, size, end callback and add buffers to read into/write from. Basically, it's just a few steps:
Call to bio_alloc to allocate bio.
Set bio->bi_bdev, bio->bi_sector, bio->bi_size, bio->bi_end_io
Add pages via bio_add_page.
Call submit_bio.
Handle results and errors in bio->bi_end_io callback
Example can be found in dm-crypt target in crypt_alloc_buffer function.