Trying to Start() a window/function in another DLL

Here are the 3 ways I’m trying it…

 Threadlong=start(remind_trigger(wo:ordernum),35000)
 Threadlong=start(remind_trigger,35000,'500')
 Threadlong=start(remind_trigger,35000,wo:ordernum)
 didthereminder=remind_trigger(wo:ordernum)

The 4th one works, but kind of blows everything up because of the different files the function uses which interferes with the files I have open. This is why I’d like to start the procedure or function. It was a procedure and I changed it to a function trying to get this thing to work. I tried the ‘500’ because wo:ordernum is actually a long, so a string like the docs says, just gives me errors, unknown function label and invalid prototype. Any suggestions would be appreciated.
Thank you

The only thing returned by STARTing a new thread is the thread number, so you can’t return a value from a function called with START.

Your easiest solution is to resolve your issues with option 4.

Maybe by using alias files in the called procedure?

Maybe have a look at UseType in the help, you should be able to call a procedure and not interfere with the current file pointers? The default is UseType:Uses which I think will prevent changing the buffer in your calling procedure, you probably don’t want UseType:Returns.

How is Remind_Trigger() prototyped?

It should be Remind_Trigger(STRING pOrderNumber)
I.e. One String parameter with no return type.

This is correct, none of the above were.

Remind_Trigger must be prototyped as
(String pOrderNum]
It should likely be “declared globally”.

It cannot return anything because the caller thread continues immediately. The two then proceed independently.

There are ways to Save and Restore your File settings if you need for it to be “not a thread” without resortung to as Alias. But as long as the task is independent of the caller, a thread is a good way to go.

wo:ordernum is a long… I can transfer it to a string variable and make the prototype a string. Now I realize changing it to a function was a mistake, of course I can’t receive anything back, nor do I need to… was just grasping. I’ll try it tomorrow. Thanks.

Doesn’t matter that it’s a long. As long as the receiver (remind_trigger) prototypes it as a string you’re fine. The conversion will happen automatically.

Equally in remind_trigger, presumably you’ll want to open the file and load the record. And it’s fine to just
wo:OrderNum = pOrderNum
it’ll convert as necessary.

Ok, that all worked. It still messed up a screen I was calling it from because I was using jhtml to read and write the html from and to a memo before I merged the data. I took it out and all was good. Turns out my code doesn’t care if it’s html or just plain text, the merge function I have just works either way. I create reminder templates, it has tokens which can be put into the template (a text or html memo). When it creates the reminder which is usually an Email ready to be sent, it merges the data. It was doing labor which could have a category that could trigger a reminder template, so now I wanted it to do parts as well. I use this software for our sales and subscriptions so I’m adding stuff for us as well as our customers. Anyway, got it working great thanks to all the help here. All I did was change the proc to use a string (and no return variable) and all the errors magically went away.

A possible problem with calling this procedure in a new thread is for the calling procedure to know whether it achieved what you wanted it to. Difficult to know if this is a factor in your case because you haven’t told us what the procedure is actually meant to do. There are ways to tell the calling procedure if the called procedure was successful.

That is correct, the calling procedure won’t know if it was successful or not. In this case it doesn’t really matter. The procedure I’m calling looks at the labor and/or parts items in the repair order and if it’s got something in the category record (a reminder list name) the item is associated with, that causes it to create a reminder or reminders and schedules them at the same time. In most cases nothing really happens, but in the cases there is a match, it does it’s thing. I have a test button so the customer can test the process because they’re the ones creating the template, which has tokens that are replaced when the actual reminder is made. In this case, if it fails, it’s probably because it’s not setup correctly. If it fails because of a technical issue like the file is messed up, there will be messages that pop up on the screen in the process itself.
If I really wanted to get a return value (which I really don’t need in this case), I could probably set a global variable (which I know is a sin these days). But it is the simplest. But then again because it’s asynchronous it wouldn’t be reliable. I guess if you’re going to Start a procedure, you just assume it’s going to take care of any errors on it’s own. But like you said, there are ways to check if the procedure went well… in this case, not an issue.

You can use NOTIFY to communicate back to the thread that called it and hook up in WindowManager.TakeNotify to perform required actions. If you pass current thread as a second parameter to your procedure, you can for example do

Notify(Event:CloseWindow,callingThread, SomeValueToTest)

and then in TakeNotify

Case NotifyCode
Of EVENT:CloseWindow

!perform some action based on Parameter

end

to communicate back to the thread that called it

You’ll need to pass the calling thread number into the started procedure (or communicate in some other fashion) so that the started procedure knows which thread to NOTIFY or POST back to

Also I declare equates for my notify codes, vs. using an EVENT

Notify:OnScreenImages:Show    EQUATE(100)
Notify:OnScreenImages:Hide    EQUATE(101)
Notify:ViewPointChange        EQUATE(102)
Notify:OnScreenImages:ShowAll EQUATE(103)
Notify:OnScreenImages:HideAll EQUATE(104)```

That is good to know. Fortunately I don’t need it this time, but I can see where I could use that in the future. Most of the time I call my functions on the same thread and wait for the return result. This is one of those times that I needed to start it because it messes with file and records that I have open. And, I really don’t care what the results were… it either worked or it didn’t, and if it didn’t it’s not a game changer really. Thanks again.

Have you considered using

RestoreState:RestoreBufferToo EQUATE(TRUE)
GetState:Blob_Save            EQUATE(TRUE)
GetState:Blob_Ignore          EQUATE(FALSE)  ! default

State:A                       LONG,AUTO
State:B                       LONG,AUTO
  CODE
  State:A = GETSTATE( FileA , GetState:Blob_Ignore ) 
  State:B = GETSTATE( FileB , GetState:Blob_Ignore )

  ! do stuff that messes with Files A & B

  RESTORESTATE( FileA , State:A, RestoreState:RestoreBufferToo )
  RESTORESTATE( FileB , State:B, RestoreState:RestoreBufferToo )

ABC File Manager has methods .SaveFile() .RestoreFile()
that wrap GetState() RestoreState()
plus call File Manager .SaveBuffer() .RestoreBuffer().

You would have to study ABFile.clw and docs to be sure of exactly what these offer beyond GetState() RestoreState(). They are part of ABC file handling used by the Browse / Form templates.