On Thu, 5 Dec 2002, Bishop Lewis wrote:
> Shiva,
>
> Attached is an email from Ankur Shah from another posting - have not tried
> it myself but this may help.
>
> Lewis Bishop
> ---
The email was instructional but it's only good for Unix. There is
no equivalent for 'system()' in the Win32 world unless you write
your own. The code below has been tested and it works. ;)
WARNING ******* WARNING *****
The code below will work....but it is not secure in that it only
does what it is told to do. If somebody sends the proc a disk
'format' command it will run it...you have been warned. Make
sure the PL/SQL wrapper procedure that calls the external is
SECURE. Also think about running the external procedure
listener under a different user id that can't do any
damage.
The following code can be placed in a DLL
------- begin code ------
ORACMD_API void RunCommand(char *cmd)
{
STARTUPINFO lpStartupInfo;
PROCESS_INFORMATION lpProcessInfo;
DWORD Derr;
BOOL pid;
DWORD Stat;
LPDWORD lpStat = &Stat;
char script[1024];
char str[1024];
char msg[1024];
char buf[1024];
char cwd[256];
strcpy(script,cmd);
getcwd(cwd,255);
cwd[255] = '\0';
//
// run the script
// Set up the STARTUPINFO Structure...this structure
// determines what the window is going to look like
lpProcessInfo.dwProcessId = -1;
lpProcessInfo.dwProcessId = -1;
lpStartupInfo.cb = sizeof(STARTUPINFO); // struct size
lpStartupInfo.lpReserved = NULL; // Reserved for Bill
lpStartupInfo.lpDesktop = NULL; // WinNT Desktop
lpStartupInfo.lpTitle = NULL; // for GUI processes
lpStartupInfo.dwX = 0;
lpStartupInfo.dwY = 0;
lpStartupInfo.dwXSize = 800;
lpStartupInfo.dwYSize = 600;
lpStartupInfo.wShowWindow = SW_SHOW;
lpStartupInfo.cb = 0; // Reserved must be zero
lpStartupInfo.lpReserved2 = NULL; // Reserved must be NULL
// Call ::CreateProcess to create a new thread....Info about
// the new thread will be returned in the PROCESS_INFORMATION
// structure
lpStartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USEPOSITION
| STARTF_USESIZE;
//MessageBox(NULL,script,NULL,MB_OK);
if((pid = ::CreateProcess(NULL, // Application Name (executable
or bat file)
(char *) script, // command Line
NULL, // Process Security Attributes
NULL, // Thread Security Attributes
TRUE, // Handle Inheritance Flag
CREATE_SUSPENDED, // Creation Flags
NULL, // Process Environment (use Parent's)
cwd, // Current directory (use DLL's dir)
&lpStartupInfo, // Start up information
&lpProcessInfo)) == 0)
{
Derr = GetLastError();
sprintf(buf," Unable to start process <%s> Error
Code = %d",
str,Derr);
//MessageBox(NULL,buf,"ERROR",MB_OK);
}
else
{
sprintf(msg,"Created Pid
%08x",lpProcessInfo.dwProcessId);
//MessageBox(NULL,msg,NULL,MB_OK);
//
// The Thread was created suspended...now we
// activiate it.
::ResumeThread(lpProcessInfo.hThread);
}
}
------ end code -----
Notes.......
1) The external procedure listener must be configured and
running...you should be able to 'tnsping EXTPROC_CONNECTION_DATA'
and get a reply. See Metalink or the manuals for setup
2) Create a Visual C++ project named 'oracmd' and then the type
entered above will work. Use the Win32 DLL template with the
option that exports functions
3) disable name-mangling (name decoration) for the exported
function by putting
extern "C" ORACMD_API void RunCommand(char *);
in the exported function declarion section of the oracmd.h
Also make sure you include direct.h (for getcwd()) and good
old stdio.h for the strcpy()/sprintf() calls
4) Compile/build the .dll and copy it to a location that is in
the server's PATH (%SYSTEMROOT%\System32 or %ORACLE_HOME%\bin)
5) Issue the CREATE LIBRARY command pointing at the DLL location
and issue the CREATE PROCEDURE AS EXTERNAL command using the
name from the code above i.e. RunCommand
6) Test execution of the procedure.
The process runs in the current directory of the DLL The only
way to make sure that it is working is to create a test '.bat'
file which will do something fairly harmless and that also
logs information to disk. Then you can look for the logfile. Do not
put a 'pause' statement in the .bat file or you will be left
with orphaned CMD.EXE processes...I know this from experience =8-0
Also....don't try to redirect the stdout/stderr of the batfile
through the DLL invocation. It won't work :( I fooled around
for a while with command line parsing and opening/inheriting
file handles from the CreateProcess API but I could not get
it working. Anything that tries to use a GUI will also cause
it to crash since there's no Desktop window handle.
Oh....and whatever you do, don't pass a command buffer larger than
1K (1024 bytes)...you'll notice the hard-coded values. It will
crash for sure.
Via con Dios/Caveat Emptor
Jeff Herrick
ps....if you want the .DLL binary (ie you don't have a Visual C++
compiler) then email me off-list for a copy.
--
Please see the official ORACLE-L FAQ: http://www.orafaq.com
--
Author: Jeff Herrick
INET: [EMAIL PROTECTED]
Fat City Network Services -- 858-538-5051 http://www.fatcity.com
San Diego, California -- Mailing list and web hosting services
---------------------------------------------------------------------
To REMOVE yourself from this mailing list, send an E-Mail message
to: [EMAIL PROTECTED] (note EXACT spelling of 'ListGuru') and in
the message BODY, include a line containing: UNSUB ORACLE-L
(or the name of mailing list you want to be removed from). You may
also send the HELP command for other information (like subscribing).