I have an old point of system program written in clipper. I have successfully decompiled the program in RESCUE5. The decompiler has written the source files to .udf. I have made the necessary changes to the .udf files and I would to recompile the program now. What is the best way to do this.
Sample of the .udf file
/* ------ Rescue5 1.11 (c) APTware 1993,94 ------
Name: ACC_CN
Params: None.
Return: Logical
Example: ACC_CN()
..........................................................................
*/
FUNCTION ACC_CN()
LOCAL cStr := SPACE(1)
LOCAL cStr1 := SPACE(5)
LOCAL nNum, nNum1, nNum2, nNum3, nNum4, nNum5, nNum6, _Def, nNum7 := ;
0, nNum8 := 1
LOCAL nNum9 := 0, nNum10 := 0, nNum11 := 0
IF MEMVAR->T_CODE[1] = " "
SCROLL(21, 3, 21, 36)
SETPOS(21, 3)
DEVPOS(21, 3)
DEVOUT(PADC("No details entered ... Hit a key", 35))
SET(17, "OFF")
__WAIT("")
SET(17, "ON")
RETURN .F.
ENDIF
GET_REM()
SCROLL(21, 3, 21, 36)
SETPOS(21, 3)
DEVPOS(21, 5)
DEVOUT("Accept details and print ?")
SETPOSBS()
AADD(GETLIST, __GET({|_bDef|IF(_bDef == NIL, cStr, cStr := _bDef)}, ;
"conf", NIL, NIL, NIL))
READMODAL(GETLIST)
MEMVAR->GETLIST := {}
If you want to compile things in CLIPPER, use .PRG files in plain CLIPPER language. You will get databases in DBF format. It might be helpful to find an application that works with SQL databases. That is a very easy way to import DBF files to SQL.
In addition, you can import the DBF files to Microsoft Access.
If you look around you may find Nantucket Clipper 5.2e. This is very stable and friendly.
You might find a book by someone named Straley or similar.
Related
I want to execute HelloWorldConsole.exe with an shipped Mono Framework through Go.
So I want to call mono-2.0-sgen.dll funtion "mono_main" to execute the exe.
mono-2.0-sgen.dll is a PE32 executable for MS Windows, see.
But I get the error "not a valid Win32 application"
_ = os.Setenv("MONO_PATH", `\mono\lib\mono\4.5;C:\DEV\HelloWorldConsole\HelloWorldConsole\bin\Debug`)
_ = os.Setenv("MONO_CFG_DIR", `"C:\Program Files (x86)\Mono\etc"`)
_ = os.Setenv("MONO_CONFIG", `"C:\Program Files (x86)\Mono\etc\mono\config"`)
mono := `C:\Program Files (x86)\Mono\bin\mono-2.0-sgen.dll`
app := `C:\DEV\HelloWorldConsole\HelloWorldConsole\bin\Debug\HelloWorldConsole.exe`
fmt.Println("Execute")
var mod = syscall.NewLazyDLL(mono)
var proc = mod.NewProc("mono_main")
ret, _, _ := proc.Call(0,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("mono.exe"))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(app))) )
Same behavior with windows.NewLazySystemDLL
dll := windows.NewLazySystemDLL(mono)
lazyProc := dll.NewProc("mono_main")
lazyProc.Call()
Function Name
Full Error:
panic: Failed to load C:\Program Files (x86)\Mono\bin\mono-2.0-sgen.dll: %1 is **not a valid Win32 application**.
%1 is not a valid Win32 application
The error %1 is not a valid Win32 application is a discription of Win32 error code from windows itself.
The Win32 error code itself is 0x000000C1 ERROR_BAD_EXE_FORMAT, see learn.microsoft.com.
BAD_EXE_FORMATmeans you call a x86 dll within a x64 process. You must use the x86 variant of Go, e.g. go1.12.1.windows-386.zip from https://golang.org/dl/.
Now must change the GOROOT and PATH to the extracted bin folder and then you are ready to go.
Type of Arguments
When you call mono_main you need to consume the this function in the right way.
If you take an look at the implementation you see that the signature is int mono_main (int argc, char* argv[]);. argc and argv is a widly used pattern, see here.
Working Sample
func main() {
_ = os.Setenv("MONO_PATH", `C:\DEV\HelloWorldConsole\HelloWorldConsole\bin\x86\Debug\mono\lib\mono\4.5;C:\DEV\HelloWorldConsole\HelloWorldConsole\bin\x86\Debug\`)
_ = os.Setenv("MONO_CFG_DIR", `C:\DEV\HelloWorhpm.goldConsole\HelloWorldConsole\bin\x86\Debug\mono\etc`)
_ = os.Setenv("MONO_CONFIG", `C:\DEV\HelloWorldConsole\HelloWorldConsole\bin\x86\Debug\mono\etc\mono\config`)
_ = os.Chdir(`C:\DEV\HelloWorldConsole\HelloWorldConsole\bin\x86\Debug\`)
mono := `C:\DEV\HelloWorldConsole\HelloWorldConsole\bin\x86\Debug\mono\bin\mono-2.0-sgen.dll`
// https://github.com/mono/mono/blob/c5b88ec4f323f2bdb7c7d0a595ece28dae66579c/mcs/tools/mkbundle/template_main.c#L1
dll := windows.NewLazySystemDLL(mono)
lazyProc := dll.NewProc("mono_main")
dotNetAssembly := []byte(`HelloWorldConsole.exe`)
var argumentData [260]byte
ptr := unsafe.Pointer(&argumentData)
copy(argumentData[:], dotNetAssembly)
args := [2]uintptr{0, uintptr(ptr)}
_, _, _ = lazyProc.Call(2, uintptr(unsafe.Pointer(&args)))
}
Setting up an asynchronous download in AutoHotkey is a pain, but this is is necessary if you want to run some code during the download, like for example updating progress bar.
So the question is:
Is there a short and simple way of downloading a file with a progress bar, without including huge 1000+ lines libraries?
I came up with that code quite some time ago and you can still find it on the AHK forums, however, why not share it with the Stackoverflow community:
DownloadFile(UrlToFile, SaveFileAs, Overwrite := True, UseProgressBar := True, ExpectedFileSize := 0) {
;Check if the file already exists and if we must not overwrite it
If (!Overwrite && FileExist(SaveFileAs))
Return
;Check if the user wants a progressbar
If (UseProgressBar) {
;Initialize the WinHttpRequest Object
WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
;Download the headers
WebRequest.Open("HEAD", UrlToFile)
WebRequest.Send()
try {
;Store the header which holds the file size in a variable:
FinalSize := WebRequest.GetResponseHeader("Content-Length")
} catch e {
; Cannot get "Content-Length" header
FinalSize := ExpectedFileSize
}
;Create the progressbar and the timer
Progress, , , Downloading..., %UrlToFile%
LastSizeTick := 0
LastSize := 0
; Enable progress bar updating if the system knows file size
SetTimer, __UpdateProgressBar, 1500
}
;Download the file
UrlDownloadToFile, %UrlToFile%, %SaveFileAs%
;Remove the timer and the progressbar because the download has finished
If (UseProgressBar) {
Progress, Off
SetTimer, __UpdateProgressBar, Off
}
Return
;The label that updates the progressbar
__UpdateProgressBar:
;Get the current filesize and tick
CurrentSize := FileOpen(SaveFileAs, "r").Length ;FileGetSize wouldn't return reliable results
CurrentSizeTick := A_TickCount
;Calculate the downloadspeed
SpeedOrig := Round((CurrentSize/1024-LastSize/1024)/((CurrentSizeTick-LastSizeTick)/1000))
SpeedUnit := "KB/s"
Speed := SpeedOrig
if (Speed > 1024) {
; Convert to megabytes
SpeedUnit := "MB/s"
Speed := Round(Speed/1024, 2)
}
SpeedText := Speed . " " . SpeedUnit
;Save the current filesize and tick for the next time
LastSizeTick := CurrentSizeTick
LastSize := FileOpen(SaveFileAs, "r").Length
if FinalSize = 0
{
PercentDone := 50
} else {
;Calculate percent done
PercentDone := Round(CurrentSize/FinalSize*100)
SpeedText := SpeedText . ", " . Round((FinalSize - CurrentSize) / SpeedOrig / 1024) . "s left"
}
;Update the ProgressBar
Progress, %PercentDone%, %PercentDone%`% (%SpeedText%), Downloading..., Downloading %SaveFileAs% (%PercentDone%`%)
Return
}
Here are some examples:
Example 1 - Download a firefox setup with a progressbar and overwrite it if it already exists on the disk:
DownloadFile("http://download-installer.cdn.mozilla.net/pub/firefox/releases/26.0/win32/en-US/Firefox%20Setup%2026.0.exe", "firefox_setup.exe")
Example 2 - Download Autohotkey with a progressbar and don't overwrite it if it already exists:
Url = http://ahkscript.org/download/ahk-install.exe
DownloadAs = AutoHotkey_L Installer.exe
Overwrite := False
UseProgressBar := True
DownloadFile(Url, DownloadAs, Overwrite, UseProgressBar)
Example 3 - Download a CCleaner setup and open a Save As dialog, asking the user where to save the file, overwriting it if already exists:
FileSelectFile, SaveAs, S, ccsetup410.exe
DownloadFile("http://download.piriform.com/ccsetup410.exe", SaveAs, True, True)
In the [Files] section, I use a Pascal scripting which calls my own DLL to generate a folder name where I want my program documentation to be installed. My DLL and my Pascal script appear to be working properly, but when I run my installer on Windows 7, Inno Setup uses the directory name as the file name instead of appending the file name to the directory name, and I end up getting all 3 documentation files copied into a file that has the name that I wanted the directory to have. Oddly, the code does work properly when I run it on Windows XP.
Here is some of the relevant code:
The [Files] section:
[Files]
Source: "doc 1.pdf"; DestDir: "{code:DocumentFolder}";
Source: "doc 2.pdf"; DestDir: "{code:DocumentFolder}";
Source: "doc 3.pdf"; DestDir: "{code:DocumentFolder}";
The Pascal script:
// Get the path to the documentation folder
// DocPath() returns a path name without a trailing backslash
// unless it returns a null string.
function DocumentFolder(Param: String) : String;
var
s : String;
k : integer;
begin
SetLength(s, 255);
k := DocPath(s); // Path to "MyCompany\MyProg" folder or something like it
if 0 = k then s := ExpandConstant('{app}'); // Just use the program folder if there is no public folder
Result := s;
end;
The reason I am scripting at all is that I'd like to have the documentation go into a folder within the system's public folder if there is one, but alternately into the program folder on a system with no public folder.
If I have missed some totally easy way to do that, kindly let me know.
Anyway, when I run this on a Windows 7 system, here is what I get, according to Inno Setup's debug log:
[10:47:42.406] Dest filename: C:\Users\Public\MyCompany\MyProgDocs
[10:47:42.409] Time stamp of our file: 2002-07-10 10:33:02.000
[10:47:42.412] Installing the file.
[10:47:42.453] Successfully installed the file.
[10:47:42.458] -- File entry --
[10:47:44.595] Dest filename: C:\Users\Public\MyCompany\MyProgDocs
[10:47:44.598] Time stamp of our file: 2014-09-13 21:14:36.000
[10:47:44.600] Dest file exists.
[10:47:44.601] Time stamp of existing file: 2002-07-10 10:33:02.000
[10:47:44.603] Version of our file: (none)
[10:47:44.609] Version of existing file: (none)
[10:47:44.611] Installing the file.
[10:47:44.637] Successfully installed the file.
[10:47:44.640] -- File entry --
[10:47:45.603] Dest filename: C:\Users\Public\MyCompany\MyProgDocs
[10:47:45.606] Time stamp of our file: 2014-09-16 14:51:26.000
[10:47:45.608] Dest file exists.
[10:47:45.610] Time stamp of existing file: 2014-09-13 21:14:36.000
[10:47:45.612] Version of our file: (none)
[10:47:45.615] Version of existing file: (none)
[10:47:45.617] Installing the file.
[10:47:45.710] Successfully installed the file.
As you can see, each of my 3 PDF files have been copied into a file named C:\Users\Public\MyCompany\MyProgDocs instead of C:\Users\Public\MyCompany\MyProgDocs\doc 1.pdf etc. as I intended. The destination file is created by the first line in the [Files] section, and is then overwritten by the second, and overwritten again by the third.
By stepping thru with the debugger, I see that my Pascal script and the DLL that supports it are working properly.
The call DocPath(s) returns the number of characters in the string, and sets its parameter s to the string value I want. On XP, it returns a zero and sets s to the null string. On Windows 7, DocPath(s) returns 36 and sets s to C:\Users\Public\MyCompany\MyProgDocs.
How can I fix this?
EDIT:
Here is some of the relevant code from my DLL:
#define FOLDERNAME _T("MyCompany")
static CString GetPublicPath()
{
TCHAR pubpath[_MAX_PATH] = {_T("")};
int nameSize = ::GetEnvironmentVariable(_T("public"), pubpath, countof(pubpath));
if (0 < nameSize)
{
TCHAR* wdbuf = _tgetcwd(NULL, 0);
_tchdir(pubpath);
_tmkdir(FOLDERNAME);
_tchdir(FOLDERNAME);
_tcscat(pubpath, _T("\\"));
_tcscat(pubpath, FOLDERNAME);
_tchdir(wdbuf);
free(wdbuf);
}
return CString(pubpath);
}
int STDCALL DocPath(wchar_t** x)
{
CString docpath = GetPublicPath();
docpath = StripBackslash(docpath);
if (0 < docpath.GetLength())
{
docpath += _T("\\MyProgDocs");
}
_tcscpy(*x, docpath.GetBuffer());
::MessageBox(0, *x, _T("DLL DocPath()"), MB_OK);
return _tcslen(*x);
}
I don't have the call to MessageBox() in the production version but it has been useful for debugging. The macro countof is like sizeof but returns an array count rather than a byte size so it works properly for wide characters.
If k > 0 you must set the lenght of s to k.
But it is much easier to get the environment variable from inno (and unnecessary to write a dll) - for example:
function DocumentFolder(dummy: String): String;
var
s: String;
begin
s := GetEnv('public');
if Length(s) > 0 then
s := s + '\MyCompany\MyProgDocs'
else
s := ExpandConstant('{app}');
Result := s;
end;
I'm having problem using the Navigate Shell command when the path include an # sign.
; this will create 2 folders at the root of your C: drive
myPath1 := "C:\delete_me\"
myPath2 := "C:\delete#me\"
if !FileExist(myPath1)
FileCreateDir, %myPath1%
if !FileExist(myPath2)
FileCreateDir, %myPath2%
; make an Explorer active and press Alt-1 and Alt-2
return
!1::
strWinId := WinExist("A")
TrayTip, %myPath1%, %strWinId%
For pExp in ComObjCreate("Shell.Application").Windows
if (pExp.hwnd = strWinId)
try pExp.Navigate(myPath1)
return
!2::
strWinId := WinExist("A")
TrayTip, %myPath2%, %strWinId%
For pExp in ComObjCreate("Shell.Application").Windows
if (pExp.hwnd = strWinId)
try pExp.Navigate(myPath2)
return
Alt-1 works well. But, with Alt-2, the Navigate command returns "file:///C:/delete#me/ » not found.".
If there is no "/" after the "#" (eg myPath := "C:\delete#me"), it works. But this cannot be a solution because the destination path can be deeper in a subfolder (eg. "C:\delete#me\xyz").
I tried to encode the "#", replacing it with "%23", without success. Found nothing on the web or MSDN about that. Any idea?
[keywords: haskmark, hashtag, number sign or pound]
I have what looks to be a working solution for this, which I've also posted here:
4 options to change the current folder in Windows Explorer - Page 3 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=526&p=153676#p153676
;links:
;Explorer Windows Manipulations - Page 5 - Scripts and Functions - AutoHotkey Community
;https://autohotkey.com/board/topic/19039-explorer-windows-manipulations/page-5#entry297581
;Navigate2 Method (IWebBrowser2)
;https://msdn.microsoft.com/en-us/library/aa752134(v=vs.85).aspx
;4 options to change the current folder in Windows Explorer - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=5&t=526
;windows - Navigate Shell command not working when the path includes an hash - Stack Overflow
;https://stackoverflow.com/questions/22868546/navigate-shell-command-not-working-when-the-path-includes-an-hash
;an AutoHotkey v1.1 script
;note: will create folder: %A_Desktop%\abc#def\abc#def
;q:: ;explorer - navigate to folder (tested on Windows 7)
WinGet, hWnd, ID, A
WinGetClass, vWinClass, % "ahk_id " hWnd
if !(vWinClass = "CabinetWClass") && !(vWinClass = "ExploreWClass")
return
vDir = %A_Desktop%\abc#def\abc#def
;vDir = %A_Desktop%\abc def\abc def
if !FileExist(vDir)
FileCreateDir, % vDir
DllCall("shell32\SHParseDisplayName", WStr,vDir, Ptr,0, PtrP,vPIDL, UInt,0, Ptr,0)
for oWin in ComObjCreate("Shell.Application").Windows
if (oWin.HWND = hWnd)
{
if !InStr(vDir, "#")
oWin.Navigate(vDir)
else
{
VarSetCapacity(SAFEARRAY, A_PtrSize=8?32:24, 0)
NumPut(1, SAFEARRAY, 0, "UShort")
NumPut(1, SAFEARRAY, 4, "UShort")
NumPut(vPIDL, SAFEARRAY, A_PtrSize=8?16:12, "Ptr")
NumPut(DllCall("shell32\ILGetSize", Ptr,vPIDL, UInt), SAFEARRAY, A_PtrSize=8?24:16, "Int")
oWin.Navigate2(ComObject(0x2011,&SAFEARRAY))
DllCall("shell32\ILFree", Ptr,vPIDL)
}
break
}
return
If you want to open a new window, there's no need for COM or unreliable workarounds: just run the folder.
Run C:\delete#me
If you want to open the path in an existing window which is already active, the simplest and most effective workaround is this:
SendInput {F4}{Esc}{Raw}C:\delete#me`n
So in the context of your script, you could use the following function to work around the # when it is present:
Navigate(pExp, myPath2)
;...
Navigate(Exp, Path)
{
if RegExMatch(Path, "#.*\\")
SendInput {F4}{Esc}{Raw}%Path%`n
else
Exp.Navigate(Path)
}
Unfortunately, there does not seem to be a solution to this. Shell.Application Navigate command fails if the path includes a hash (# as in C:\C#Projects).
Using AutoHotkey, the workaround would be to rely on the "second best" approach as identified by the tests in this thread: http://ahkscript.org/boards/viewtopic.php?f=5&t=526.
run, Explorer.exe
Sleep, 500
strFolder := A_ScriptDir
Send, {F4}{Esc}
Sleep, 500
ControlSetText, Edit1, C:\delete#me, A
ControlSend, Edit1, {Enter}, A
When I saw that Navigate couldn't handle hash, I was shocked,
but sure enough I replicated the error.
I thought I'd try the short form path just in case. It works!
if vDir contains #
Loop, %vDir%, 2, 0 ;(0/1/2=files/both/folders, 0/1=recurse no/yes)
vDir := A_LoopFileShortPath
The following approach doesn't require a visible address bar, or SendInput,
also the previous navigation history is maintained.
In the worst-case scenario of a hash in the short-form path of the dir above the target dir,
a go-between folder is used which is navigated to.
A link is created there, invoked, and deleted.
Below, the workaround code is indented, to separate it from the standard code.
A hotkey of ctrl+q, when an Explorer window is active, launches the script.
-
^q:: ;explorer - navigate to directory (use go-between dir if short-form path of dir above target contains #)
WinGet, hWnd, ID, A
WinGetClass, vWinClass, ahk_id %hWnd%
if vWinClass not in CabinetWClass,ExploreWClass
Return
vDir2 = %A_Desktop%\Go-Between ;go-between dir
vDir3 = C:\delete#me ;target dir
if (SubStr(vDir3, 1-1) = "\")
vDir3 := SubStr(vDir3, 1, -1)
if !InStr(FileExist(vDir3), "D")
Return
vPathLnk := ""
if vDir3 contains #
Loop, %vDir3%, 2, 0 ;(0/1/2=files/both/folders, 0/1=recurse no/yes)
vDir3 := A_LoopFileShortPath
;vDir4 is the short-form path of the dir above the target
;paths of problem target dirs are of the form: *#*\*
;where there is at least one hash with a backslash to its right
SplitPath, vDir3, , vDir4
if vDir4 contains #
{
if !InStr(FileExist(vDir2), "D")
FileCreateDir, %vDir2%
if !InStr(FileExist(vDir2), "D")
{
MsgBox error`, go-between dir not found:`r`n%vDir2%
Return
}
vNameLnk = Go-Between.lnk
vPathLnk = %vDir2%\%vNameLnk%
FileCreateShortcut, %vDir3%, %vPathLnk%
}
for oWin in ComObjCreate("Shell.Application").Windows
if (hWnd = oWin.Hwnd)
{
vDir1 := oWin.Document.Folder.Self.Path
if (vDir1 = vDir3)
break
if vDir3 contains #
{
if !(vDir1 = vDir2)
oWin.Navigate(vDir2)
while !(oWin.ReadyState = 4)
Sleep 10
oItem := oWin.Document.Folder.Items.Item(vNameLnk)
oItem.InvokeVerbEx("open")
break
}
oWin.Navigate(vDir3)
break
}
oWin := ""
if !(vPathLnk = "")
FileRecycle, %vPathLnk% ;send to recycle bin
;if !(vPathLnk = "")
;FileDelete, %vPathLnk% ;delete
Return
I had something like the following in my notebook.
test1[g_] := (g == 5);
test2[g_] := (g == 6);
tests={"test1", "test2"}
ToExpression[#][5] & /# tests
When I put this code in a package it doesn't work because test1 is now called MyPackage'Private'test1. How can I modify the last line to make this code run both inside package and inside notebook?
Update
Here's why I was doing doing ToExpression as opposed to using Symbols. In retrospect, maybe it's easier to use Symbols instead
I had a function which I call like getGraphs["LeafFree","Planar",!"Tree",...] to get all graphs that are leaf free, planar and not trees. Some of those strings are classes in GraphData, while others were my own classes. For each of my own classes I had a function with identical name, like LeafFree that tested the property. In the notebook, using ToExpression code like above was the quickest way to implement this.
getGraphs[n_Integer, cl__] := getGraphs[{n, n}, cl];
getGraphs[{nmin_Integer, nmax_Integer}, cl__] :=
Module[{maxgraphnum = 100},
customClasses = {"isLeafFree", ! "isLeafFree"};
classes = {cl}\[Backslash]customClasses;
builtinClasses =
GraphData["Classes"] \[Tilde] (Not /# GraphData["Classes"]);
Assert[classes \[Subset] builtinClasses];
isLeafFree[gname_] :=
FreeQ[GraphData[gname, "DegreeSequence"], 0 | 1];
posClasses = Cases[classes\[Backslash]customClasses, _String];
posGroup =
If[posClasses == {}, GraphData[nmin ;; nmax],
GraphData[posClasses, nmin ;; nmax]];
negClasses = classes\[Backslash]posClasses;
negGroups = GraphData[#[[1]], nmin ;; nmax] & /# negClasses;
result = Complement[posGroup, Sequence ## negGroups];
customTest[g_] :=
And ## (ToExpression[#][g] & /# ({cl} \[Intersection]
customClasses));
(*result=Take[result,Min[Length[result],100]];*)
result = Select[result, customTest]
]
I agree with the comments above that you should perhaps have a compelling reason to do this, but here goes. Here is a code I use in such cases, which allows your symbol to be parsed in whatever context you like, at run-time:
SetAttributes[ParseTimeNameSpaceWrapper,HoldFirst];
Options[ParseTimeNameSpaceWrapper] = {
LocalizingContext->"MyLocalizingContext`",
DefaultImportedContexts:>{"Imported1`", "Imported2`"},
ExtraImportedContexts:> {}
};
ParseTimeNameSpaceWrapper[code_,opts:OptionsPattern[]]:=
Module[{result,
context = OptionValue[LocalizingContext],
defcontexts = OptionValue[DefaultImportedContexts],
extraContexts = OptionValue[ExtraImportedContexts],
allContexts},
allContexts = {Sequence##defcontexts,Sequence##extraContexts};
BeginPackage[context,If[allContexts==={},Sequence##{},allContexts]];
result = code;
EndPackage[];
result
];
You can use options to specify some contexts where these symbols exist, that you want to import during the parse stage. You can call this from any package or notebook, and the symbol will be parsed according to whatever context you specify.
HTH
Edit:
Responding to a comment (since it made the question more specific): There is no question that at run-time Context[] will display whatever is the current context from where the function was called (Global in that case). I meant something else: Context has a syntax Context[symbol], to give a context of any symbol if it is on the $ContextPath. For example, Context[getGraphs] returns Bulatov'showGraphs'. Therefore, if you need to determine the context of some exported function automatically, you call Context[function]. You can use this to construct full names of other (private) functions of that package. Here is a self - contained example:
In[1]:=
BeginPackage["MyTest`"];
f[x_, y_, context_: Context[f]] :=
Module[{f1str = "function1", f2str = "function2", f1, f2},
{f1, f2} = ToExpression[context <> "Private`" <> #] & /# {f1str, f2str};
f1[x, y];
f2[x, y];];
Begin["`Private`"];
function1[x_, y_] := Print["In function1: arguments are ", x, " , ", y];
function2[x_, y_] := Print["In function2: arguments are ", x, " , ", y];
End[]
EndPackage[];
Out[6]= "MyTest`Private`"
In[8]:= f[1, 2]
During evaluation of In[8]:= In function1: arguments are 1 , 2
During evaluation of In[8]:= In function2: arguments are 1 , 2
where x,y are just some sample arguments. Then, you never actually supply the last argument, but you can use the context variable inside your function, to construct long names for your other functions, as in the sample code above. Or you could just plain use Context[f] inside body of the function, and not add any arguments to it.
ToExpression uses the current binding of $Context when creating symbols, so you can force your expression to be interpreted within a particular context thus:
Block[{$Context="MyPackage`Private`"}, ToExpression[#][5]] & /# tests
I'm not sure I understand the circumstances of the original question. You can get the current context using $Context or Context[]... but ToExpression will automatically use the current context without intervention.
If I run the exhibited code in a notebook, it works fine. If I run it like this:
Begin["MyPackage`Private`"]
test1[g_] := (g == 5);
test2[g_] := (g == 6);
tests = {"test1", "test2"}
ToExpression[#][5] & /# tests
End[]
... it also works fine. I can get it to fail if I run it like this:
(* in the package file *)
Begin["MyPackage`Private`"]
test1[g_] := (g == 5);
test2[g_] := (g == 6);
End[]
(* in the notebook *)
tests = {"test1", "test2"}
ToExpression[#][5] & /# tests
... which not only fails but also creates spurious symbols in the notebook's context. You can work around this problem using the Block recipe from above.
If you want to capture the context that was in effect at the moment the package code was loaded, you can do something like this:
(* in the package *)
Begin["MyPackage`Private`"]
test1[g_] := (g == 5);
test2[g_] := (g == 6);
tests = {"test1", "test2"};
With[{context = $Context},
runTests[] := Block[{$Context = context}, ToExpression[#][5]] & /# tests
]
End[]
(* in the notebook *)
MyPackage`Private`runTests[]
runTests uses With to inject the private package context into its definition.
As Janus' noted, it is better to use symbols than strings since they automatically manage the whole context issue -- but this assumes your actual use case will permit the use of symbols.