How do I set the provider for a TPushEvent? - delphi

I have a TPushEvent and TKinveyProvider declared on my firemonkey form
I'm trying to manually set the value of the Provider in code. I realize that by default when you drop those controls on a form the the PushEvent's Provider property is automatically set to the TKinveyProvider. However, I'm working around an apparent bug and I'd like set it later.
Am I setting the provider property correctly in this snippet?
//In my form class
//...
myPushEvents: TPushEvents;
myKinveyProvider: TKinveyProvider;
//later on in one of my procedures/methods
//...
myPushEvents.Provider := myKinveyProvider;
When I look a the value else later on after it should have been set, it still appears to be nil.
Provider appears to be defined as a IBackendProvider which is an interface and I'm not sure if I have to assign it its provider differently than I would with a simple data type like an Integer or a String.

Yes, this is the right way to do it.
myPushEvents.Provider := myKinveyProvider
In this cases myPushEvents.Provider is being assigned a reference to myKinveyProvider. You don't have to do any special casting because myPushEvents.Provider expects something that conforms to the IBackendProvider interfcase, and myKinveyProvider (a TKinveyProvider) does.
Note: In my specific case, thanks to myPushEvents.Provider being set as the result of a timer finishing, it was indeed still nil.
Adding an
if (myPushEvents.Provider <> nil) then
begin
// ... use myPushEvents.Provider
end;
protected the usage of it until the value had been set properly after the timer ran.

Related

Include multi-selection option in file-open-dialog

To allow multiselection in a file-open-dialog and to avoid this long expression:
OpenDialogSourceFiles.Options := OpenDialogSourceFiles.Options + [Vcl.Dialogs.fdoAllowMultiSelect]; // works
I tried to use the shorter Include function:
System.Include(OpenDialogSourceFiles.Options, Vcl.Dialogs.fdoAllowMultiSelect); // error
However, the compiler marks this as erroneous.
This is by design. The Include procedure requires a variable as its first argument (it is a var parameter, essentially, even though the procedure is implemented by compiler magic), but TFileOpenDialog.Options is a property.
Hence you must use the verbose alternative. There's nothing you can do about it.
The same thing applies to Inc and TComponent.Tag, for instance.
(But you can write fdoAllowMultiSelect instead of Vcl.Dialogs.fdoAllowMultiSelect, Include instead of System.Include, etc. to make it a bit less verbose.)

How to find if an IHTMLDocument2 is equal to IDispatch document in Delphi?

I have a TEmbeddedWB (https://sourceforge.net/projects/embeddedwb/) with an iFrame in it. I have to find out that a specific HTML Tag is inside that iFrame or not. My iFrame object is a IHTMLFrameBase2, while the Tag is a IHTMLElement. I know that the iFrame.contentWindow.document (which is a IHTMLDocument2) is the same as Tag.document. But the Tag.document is an IDispatch object, therefore the following gives a false:
if iFrame.contentWindow.document = Tag.document then ShowMessage('In iFrame')
else ShowMessage('Not in iFrame');
I know that the two object is the same, because the Watch List can show their memory address:
But I can't get their addresses from code. What I've tried:
Addr(iFrame.contentWindow.document) // Gives variable required error
#iFrame.contentWindow.document // Gives variable required error
Pointer(iFrame.contentWindow.document) //Compiles, but gives wrong address
Format('%p',[iFrame.contentWindow.document]) //Compiles, but gives EConvertError
Note: If I run line-by-line the addresses that the Watch List is showing change after EVERY line of code, no matter the code affects the WebBrowser or not.
From the rules of COM:
It is required that any call to QueryInterface on any interface for a given object instance for the specific interface IUnknown must always return the same physical pointer value. This enables calling QueryInterface(IID_IUnknown, ...) on any two interfaces and comparing the results to determine whether they point to the same instance of an object (the same COM object identity).
So, ask them both for their IUnknown interface, and compare.
var
disp: IDispatch;
doc: IHTMLDocument2;
....
if (disp as IUnknown) = (doc as IUnknown) then
....

Delphi - deferring assignment to an out parameter

In Delphi, suppose I have a method with a (much simplified) signature like this:
procedure abc( const prop1:string; const arg1:TValue; const prop2:string;
out arg2:TValue );
I'm building a TList<PPropValPair> of records like this using the parameters provided:
type
TPVPType = (ptIn, ptOut);
PPropValPair = ^TPropValPair;
TPropValPair = record
io : TPVPType;
prop : string; // property name
iVal : TValue; // input value
oVar : Variant; // <-- how to save for later use??? Variant? TValue?
end;
(On the face of it, this example looks silly. Again, it's quite simplified just to communicate the problem.)
At run-time, I want to stuff all of the input values ival (where io=ptIn) into each public property 'prop' in a class, call a class method, then extract the values of all public properites 'prop' (where io=ptOut) into oVar.
The input side is working fine using RTTI.
However, I need to somehow save a REFERENCE to the output vars in oVar so I can save the value of the associated properties after the class method has been called.
I'm not assigning anything to arg2 directly. Rather, I'm saving a reference to arg2 and assigning the value indirectly later on.
The trick is ... I don't want to have to do any additional annotations of the output parameters in abc(...).
In C++, you can declare a parameter as a 'reference' by prepending it with '&'. So in C++ terms this might be defined roughly as:
procedure abc( arg1 : TValue; &arg2 : TValue );
Later, you can refer to &arg2 and it's using a POINTER to the object. But in calling the function, you just say:
abc( somevar1, somevar2 );
somevar1 is passed by value, and somevar2 is passed by reference. Inside the function, I can save somevar2 in a reference var, then later on assign a value to it via the pointer (if it's a string) by saying &arg2ref = 'abc'.
I'm guessing there's a way to do this in Delphi, either with a Variant as the oVar type, or using RTTI, or something else. I just haven't figured out the magic combination of pieces yet. (I just don't use pointers very often in Delphi.)
Maybe I need to save a raw pointer in oVar along with the type (say, oType), and cast a value through the pointer to save the property's value?
I'm hoping someone here might have some clear ideas.
BTW, I'm using Delphi XE3.
Use a pointer. It doesn't have to (and indeed shouldn't) be a "raw" pointer. Use a typed pointer, PValue. Pass in a PValue to your function, and then store that in oVal, which you should also declare a a PValue. Use # to create a pointer, and ^ to dereference.
I would not recommend passing arg2 by reference. Although you can still use # on it to get a pointer to the original variable passed to abc, the reference parameter disguises the fact that the variable needs to remain available indefinitely. Instead, declare arg2 as PValue so it's more obvious to the caller that indirection is involved.
// declaration
procedure abc(...; arg2: PValue);
// call
abc(..., #somevar2);

Delphi DataSnap authorization not repecting TRoleAuth attribute

I am trying to implement authorization in a Delphi XE DataSnap application. I broke this down into a very simple example, but still do not see the effects of the TRoleAuth attribute for a method or class.
Here is a simple DSServerMethods class that includes the generated sample methods. The class has been decorated with the guest and anyone authorized roles, and the unwelcome denied role. The ReverseString method has been decorated with the readonly denied role:
type
[TRoleAuth('guest,anyone','unwelcome')]
TMyDSServerMethods = class(TDSServerModule)
DataSetProvider1: TDataSetProvider;
...
public
{ Public declarations }
function EchoString(Value: string): string;
[TRoleAuth('','readonly')]
function ReverseString(Value: string): string;
...
end;
I am assigning roles on the OnUserAuthenticate method. For example, I have a user for whom I am assigning the readonly role from OnUserAuthenticate, a role which I believe should deny that user permission to execute the ReverseString function.
From what I understand, my code should compare the user's roles against the EventObject.AuthorizedRoles and EventObject.DeniedRoles TStrings from the OnUserAuthorize method of the TDSAuthenticationManager, and set the valid formal parameter of this method accordingly.
Here is a simple OnUserAuthorize method I am using for tesing. When I step into it using the debugger in response to a user with the readonly role attempting to invoke ReverseString, EventObject.AuthorizedRoles and EventObject.DeniedRoles are both nil, and EventObject.Roles contains the readonly role.
procedure TServerContainer1.DSAuthenticationManager1UserAuthorize(
Sender: TObject; EventObject: TDSAuthorizeEventObject;
var valid: Boolean);
begin
outputdebugstring(PChar(Eventobject.UserName));
if EventObject.UserRoles <> nil then
outputdebugstring(PChar(eventobject.UserRoles.Text));
if EventObject.AuthorizedRoles <> nil then
outputdebugstring(PChar(eventobject.AuthorizedRoles.Text));
if EventObject.DeniedRoles <> nil then
outputdebugstring(PChar(eventobject.DeniedRoles.Text));
valid := True;
end;
Am I missing the point, or is there a property that I need to set somewhere to enable the TRoleAuth attribute to function?
= = = = = = = = = =
Edit: Mat DeLong provided the answer. The DSAuth unit (where the TRoleAuth custom attribute class is declared) was missing from the interface section of the unit in which the DSServerModule descendant was defined.
One thing to make sure of is that in your server methods class you have the "DSAuth" unit in the uses clause of the interface section. If you don't, you should see a compile time warning saying "Unsupported language feature: ‘custom attribute’". If this is happening, it means your attributes are being ignored because the TRoleAuth type is unknown.
If that isn't the case, then I'm not sure what else it would be. If working properly, in your OnUserAuthorize event, you should see "EventObject.DeniedRoles" containing the "readonly" role defined in the code attribute. You should also see "EventObject.UserRoles" containing this role. If this is the case, then you wouldn't need to implement OnUserAuthorize at all, and the code would automatically deny this user authorization.
A couple things to note:
If you put a TRoleAuth attribute on a function or procedure, it replaces the attribute put on the class (only for that one method.) It doesn't add to it.
If you set a design-time attribute that ends up apply to the method (by modifying the 'Roles' collection on the TDSAuthenticationManager component) then the attribute(s) you added in code will be ignored.
Hope that helps,
Mat

Increasing a pointer not compiling the way I had planned

I tried to make my code as simple as possible,but I failed at it.
This is my code:
class function TWS.WinsockSend(s:integer;buffer:pointer;size:word):boolean;
begin
dwError := Send(s,buffer,size,0);
// Debug
if(dwError = SOCKET_ERROR) then
begin
dwError := WSAGetLastError;
CloseSocket(s);
WSACleanup;
case (dwerror) of
//Case statement
else
LogToFile('Unhandled error: ' + IntToStr(dwError) + ' generated by WSASend');
end;
Exit(false);
end;
// if the size of the bytes sent isn't the expected one.
while(dwError <> size) do
dwError:= dwError + Send(s,Ptr(cardinal(buffer) + dwError),size-dwError,0);
Exit(true);
end;
The error is placed at
dwError:= dwError + Send(s,Ptr(cardinal(buffer) + dwError),size-dwError,0);
Error is "Constant object cannot be passed as var parameter"
I understand I need a variable,but isn't there a way I can do it without adding one more line?
When the compiler complains about the way you're passing a parameter, the first thing you need to know is what the parameter expects. Therefore, you should go look at the declaration of Send. If looking at the declaration doesn't immediately give you an idea of what to fix, then you need to include that declaration with the code you post in your question.
I suspect that this actually has nothing to do with incrementing a pointer. Instead, the compiler is complaining about the third parameter, where you are trying to pass the expression size-dwError. I guess the parameter is declared like this:
var buffersize: Word;
The function plans on providing a new value for that parameter — that's what var means — so the thing you pass to that parameter needs to be something that can receive a value. You can't assign a new value to the result of subtracting two variables.
Take a closer look at where the compiler complained about that line. Didn't it place the cursor somewhere near the third parameter? That's a clue that the problem is there.
Decrement size, and then pass it to the function.
Dec(size, dwError);
Inc(dwError, Send(s, Ptr(cardinal(buffer) + dwError), size, 0));
Why do you care about adding another line? Have you reached your quota for the day? Lines are cheap; don't be afraid to use two to express yourself when one won't do. Likewise for variables. When your code doesn't work, saving a byte or two doesn't matter at all.
At the very least, you should have added more lines in order to track down the source of the problem. When you have one line of code that's performing several independent calculations (such as getting a new pointer value, getting a new size, and calling a function), break the line into several separate pieces. That way, if there's a problem with one of them and the compiler complains, you'll know exactly which one to blame.
Correct, this will not work as written. When your dealing with var parameters, you have to build the parameter BEFORE passing it to the procedure/function. When a Var parameter is passed, the procedure is allowed to modify it. If you attempted to copy two variables together on the call, where would this result go?
The other issue is that dwError is not delcared. A class method does NOT have access to the data elements of the object the class defines. If you drop the class, then you will have access to the data elements, but will require that the class first be created.
You should only be using class methods in places where the input and output are completely contained within the method.
How are you allocating your buffer? Internally is it an array?
Sounds like Send has a format parameter (like send (const something;size:integer)
Workaround is using pchar (entirepointerexpression)[0]

Resources