How can i retrieve the is_sfparam-content, either using query or function module.
then will be passed as a parameter to cl_recp_data_cn_general=>get_contract.
do you have any idea? Where can I get that is_sfparam-content?
Thanks
CALL METHOD cl_recp_data_cn_general=>get_contract
EXPORTING
id_guid = is_sfparam-content
IMPORTING
es_contract = contract
CHANGING
cf_error = lf_error.
This guid paramater brings no sense as it is generated in runtime. You can check this yourself by putting breakpoint at the first line (e.g. line 102) of method cl_recp_data_cn_general=>get_contract and checking id_guid var in debugger. It will be different with each run of preview in RECN tcode.
Check also line 11 of CONSTRUCTOR method of CL_RECP_SF_DOC class, it is executed during each form generation.
The real contract object lays in variable go_busobj of program SAPLRECA_BDT_APPL_TOOL which brings RECN functionality and it is global i.e. it is loaded into memory constantly while RECN is running, just passing doc object into called methods thru the call stack, which you can follow in debugger.
Where really form generation takes place is CL_RECP_SF_JOB class, for preview it is _FP_PREVIEW method, for print it is _FP_PRINT. For example, in preview method form FM is called in that place
What you need to do if you want to call arbitrary contract print-form, which is what I assume you want to do by asking this question:
Find out smartform FM name by putting breakpoint in the above line
Build parameters for this FM calling. The only obligatory parameter is LS_SFPARAM-CONTENT which is the GUID.
You can generate this GUID manually by creating CL_RECP_SF_DOC object, let it be io_doc var. The constructor of this object has input parameter is_doc which should be filled according to the attributes of contract which you want to print, and which are stored in VIBDRO and VICNCN tables.
After creating this object pass its attribute io_doc->md_guid to ls_sfparam-content, generate other parameters with CL_RECP_SF_JOB->_sf_get_form_param and
Run the smartform FM /1BCDWB/SF000000XX found at step 1 with these parameters
I didn't check all these steps by myself but I believe it should work.
Related
I am trying to log field writes with bytebuddy. After reading some earlier posts, I started using MemberSubstitution and got something going using the following code:
private static Method FIELD_INTERCEPTOR = // reflective reference to interceptFieldWrite
AsmVisitorWrapper VISITOR = MemberSubstitution.relaxed()
.field(ElementMatchers.any())
.onWrite()
.replaceWith(FIELD_INTERCEPTOR)
.on(ElementMatchers.isMethod());
..
public static void interceptFieldWrite(Object object,Object value) {
System.out.println("intercepted field write in object " + object + " , attempt to set value to " + value);
}
..
The part I am struggling with is how to pass a reference to the field for which the access is intercepted to interceptFieldWrite (as string or instance of Field). If possible I would of course like to avoid reflection completely. I don't actually want to completely substitute field access, but just want to add a method with some checks just before it takes place. Is there a feature in bytebuddy to do this, or do I have to use something more low-level than ASM to achieve this ?
Byte Buddy offers this but you will have to compose your own StackManipulations to do so. The mechanism in MemberSubstitution is called replaceWithChain. Here you specify Steps where each step can do what you intend:
invoke a method via MethodInvocation.
write a field via FieldAccessor.
You will have to load the arguments to the method call and the field access prior to using the above stack manipulations via the MethodVariableAccess where the targeted element's offsets are represented by offsets.
In your case, this would require to read the target instance via
MethodVaribaleAccess.of(parameters.get(0)).loadFrom(offsets.get(0));
MethodVaribaleAccess.of(parameters.get(1)).loadFrom(offsets.get(1));
and the to execute the method or field write in question. The targeted field will be passed as target, you can cast it to FieldDescription if you only ever intercept fields.
Make sure you only intercept non-static fields where the this instance will not be passed.
I've found the InvokeDynamic class and have made it work with a static method handle acquired via MethodHandles.Lookup.findStatic().
Now I am trying to do the same thing, but with a virtual method handle acquired via MethodHandles.Lookup.findVirtual().
I can cause my bootstrap method to run, and I make sure in my bootstrap method that I'm returning a ConstantCallSite(mh), where mh is the result of calling MethodHandles.Lookup.findVirtual(). (This part all works fine, i.e. I understand how "indy" works.)
However, when I use the resulting Implementation as the argument to an intercept() call, I cannot pass the actual object on which the method represented by the method handle is to be invoked. This is due to the withArgument() method being used for two contradictory purposes.
Here is my recipe:
Implementation impl =
InvokeDynamic.bootstrap(myBootstrapDescription, someOtherConstantArgumentsHere)
.invoke(theMethodName, theMethodReturnType)
// 0 is the object on which I want to invoke my virtual-method-represented-by-a-method-handle;
// 1 is the sole argument that the method actually takes.
.withArgument(0, 1);
There are some problems here.
Specifically, it seems that withArgument() is used by ByteBuddy for two things, not just one:
Specifying the parameter types that will be used to build a MethodType that will be supplied to the bootstrap method. Let's say my virtual method takes one argument.
Specifying how the instrumented method's arguments are passed to the actual method handle execution.
If I have supplied only one argument, the receiver type is left unbound and execution of the resulting MethodHandle cannot happen, because I haven't passed an argument that will be used for the receiver type "slot". If I accordingly supply two arguments to (1) above (as I do in my recipe), then the method handle is not found by my bootstrap method, because the supplied MethodType indicates that the method I am searching for requires two arguments, and my actual method that I'm finding only takes one.
Finally, I can work around this (and validate my hypothesis) by doing some fairly ugly stuff in my bootstrap method:
First, I deliberately continue to pass two arguments, not one, even though my method only takes two arguments: withArgument(0, 1)
In my bootstrap method, I now know that the MethodType it will receive will be "incorrect" (it will have two parameter types, not one, where the first parameter type will represent the receiver type). I drop the first parameter using MethodType#dropParameterTypes(int, int).
I call findVirtual() with the new MethodType. It returns a MethodType with two parameter types: the receiver type that it adds automatically, and the existing non-dropped parameter type.
(More simply I can just pass a MethodType as a constant to my bootstrap method via, for example, JavaConstant.MethodType.of(myMethodDescription) or built however I like, and ignore the one that ByteBuddy synthesizes. It would still be nice if there were instead a way to control the MethodType that ByteBuddy supplies (is obligated to supply) to the bootstrap method.)
When I do things like this in my bootstrap method, my recipe works. I'd prefer not to tailor my bootstrap method to ByteBudddy, but will here if I have to.
Is it a bug that ByteBuddy does not seem to allow InvokeDynamic to specify the ingredients for a MethodType directly, without also specifying the receiver?
What you described, is entirely independent of Byte-Buddy. It’s just the way how invokedynamic works.
JVMS, §5.4.3.6
5.4.3.6. Dynamically-Computed Constant and Call Site Resolution
To resolve an unresolved symbolic reference R to a dynamically-computed constant or call site, there are three tasks. First, R is examined to determine which code will serve as its bootstrap method, and which arguments will be passed to that code. Second, the arguments are packaged into an array and the bootstrap method is invoked. Third, the result of the bootstrap method is validated, and used as the result of resolution.
…
The second task, to invoke the bootstrap method handle, involves the following steps:
An array is allocated with component type Object and length n+3, where n is the number of static arguments given by R (n ≥ 0).
The zeroth component of the array is set to a reference to an instance of java.lang.invoke.MethodHandles.Lookup for the class in which R occurs, produced as if by invocation of the lookup method of java.lang.invoke.MethodHandles.
The first component of the array is set to a reference to an instance of String that denotes N, the unqualified name given by R.
The second component of the array is set to the reference to an instance of Class or java.lang.invoke.MethodType that was obtained earlier for the field descriptor or method descriptor given by R.
Subsequent components of the array are set to the references that were obtained earlier from resolving R's static arguments, if any. The references appear in the array in the same order as the corresponding static arguments are given by R.
A Java Virtual Machine implementation may be able to skip allocation of the array and, without any change in observable behavior, pass the arguments directly to the bootstrap method.
So the first three arguments to the bootstrap method are provided by the JVM according to the rules cited above. Only the other arguments are under the full control of the programmer.
The method type provided as 3rd argument always matches the type of the invokedynamic instruction describing the element types to pop from the stack and the type to push afterwards, if not void. Since this happens automatically, there’s not even a possibility to create contradicting, invalid bytecode in that regard; there is just a single method type stored in the class file.
If you want to bind the invokedynamic instruction to an invokevirtual operation using a receiver from the operand stack, you have exactly the choices already mentioned in your question. You may derive the method from other bootstrap arguments or drop the first parameter type of the instruction’s type. You can also use that first parameter type to determine the target of the method lookup. There’s nothing ugly in this approach; it’s the purpose of bootstrap methods to perform adaptations.
In my current project in Access VBA, I created a window which works like a console and now I am trying to add a possibility to display any public variable. It should work like:
Show_var [variable_name]
So it should be like in the direct window where i can type:
? pVar.variable_A
I found out that using
Application.VBE.ActiveVBProject.VBComponents(11).CodeModule.CountOfLines
I can display the number of lines within a module or form so I thought perhaps I could somehow find the variables there, cycle through them and when the correct one is found, its value can be shown. OFC I could make a Select Case Statement where all variables are included but that is not the way I want to do it because it is complicated and must be changed every time update my public variable list.
There are so many problems that I think you are out of luck. Let me just list some of them:
There is no way to get a list of all variables - that would mean you would need access to the internal symbol table.
As a consequence, you would have to read the code (CodeModule lets you read the code of a module), and write an own parser to fetch all declarations (hopefully you use Option Explicit)
AFAIK, the is no method that can access the content of a variable via it's name.
Even if there would be any such method: What would you do with different data types, arrays and especially with objects.
If a user runs into problems, often it is a runtime error. If you don't handle that errors with some kind of error handler, the only option if a user cannot enter the debugger is to press "End" - which would destroy the content of all variables.
You have to deal with scope of variables, you can have several variables with the same name and you will likely have lots of variables that are out of scope in the moment you want to dump them.
below code is c#
ctx.CreateStreamResponse(stream => new Session(_Sessions, stream).Process(),"video/mp4");
and i need to this code as VB.NET code. am converting as below
ctx.CreateStreamResponse(Function(stream) New Session(_Sessions, stream).Process(), "video/mp4")
But getting error
overload resolution failed because no accessible
"CreateStreamResponse" can be called with these arguments.
CreateStreamResponse needs 2 parameters
Stream (as my sample Function(stream) New Session(_Sessions, stream).Process())
content type (as my sample "video/mp4")
Anyone can help me, please
I believe the issue seems to be that the method which you pass into CreateStreamResponse should be a Sub not a Function. i.e:
ctx.CreateStreamResponse(Sub(stream) New Session(_Sessions, stream).Process(), "video/mp4")
CreateStreamResponse takes an Action(Of Stream) delegate as the first argument and a contentType of String as the second argument.
Thus you need to use Sub rather than a Function as in this case an Action delegate can only encapsulate methods that return void (sub procedures). Also, ensure that the Process method being invoked is also a Sub procedure.
If the problem persists then as suggested by Microsoft docs:
Review all the overloads for the method and determine which one you
want to call.
In your calling statement, make the data types of the arguments
match the data types of the parameters defined for the desired
overload. You might have to use the CType Function to convert one or
more data types to the defined types.
for more information see here
I'm using the MSOfficeDemo/MSWord classes as a starter.
How can I print a document that is open in Word?
In a new method in the MSWord.java class I've tried:
this.invokeNoReply("Print", this.getDocuments());
this.invokeNoReply("PrintOut", this.getDocuments());
this.invokeNoReply("FilePrint", this.getDocuments());
I get an Unknown Name (hr=-2147352570) error for each of the above calls.
I've been searching for a week now and haven't found a solution.
Rather than guessing, you need to match your method signature to the documentation.
You need to actually print the active document (this.getActiveDocument()) rather than the collection of documents. Then refer to the Document methods to see which method (and arguments) to use, in this case PrintOut is the correct method.
What you pass for the parameters, you need to look at the various method signatures in ComLateBindingObject and pick the one that best matches your needs (you can pass one or two arguments, more than that you need an array.
This code should work... haven't tested it (don't have MSWord on my Windows VM) but combined with the links above it should get you in the right direction:
this.invokeNoReply("PrintOut", getActiveDocument());
If that doesn't work, try:
this.invokeNoReply("PrintOut", getActiveDocument().getIDispatch());
If you actually need to pass any of the parameters, you'll create a VARIANT for them and start filling in 1 or more of the parameters (or an array of them).