Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Mailing Lists -> Oracle-L -> RE: Are There any way of calling NT OS Commands like print, del e

RE: Are There any way of calling NT OS Commands like print, del e

From: Jeff Herrick <jherrick_at_igs.net>
Date: Thu, 05 Dec 2002 13:54:17 -0800
Message-ID: <F001.00513E15.20021205135417@fatcity.com>

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

	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: jherrick_at_igs.net

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: ListGuru_at_fatcity.com (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).
Received on Thu Dec 05 2002 - 15:54:17 CST

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US