Avatar billede snowball Novice
20. december 2004 - 10:39 Der er 8 kommentarer og
1 løsning

Tilføj / fjern ODBC (DSN) til SQL Server

Hej.

Jeg har brug for at kunne tilføje/fjerne ODBC data kilder via et lille program. Jeg har fundet nedenstående eksempel som næsten gør det jeg ønsker.

<--Kode start-->
unit main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

const
  ODBC_ADD_DSN = 1; // Add data source
  ODBC_CONFIG_DSN = 2; // Configure (edit) data
  ODBC_REMOVE_DSN = 3; // Remove data source
  ODBC_ADD_SYS_DSN = 4; // add a system DSN
  ODBC_CONFIG_SYS_DSN = 5; // Configure a system DSN
  ODBC_REMOVE_SYS_DSN = 6; // remove a system DSN
  ODBC_REMOVE_DEFAULT_DSN = 7; // remove the default DSN
  SQL_MAX_MESSAGE_LENGTH = 512;

  function SQLConfigDataSource(hwndParent: HWND; fRequest: WORD;
  const lpszDriver, lpszAttributes: PChar): BOOL; stdcall;

  function  SQLInstallerError(iError: WORD; pfErrorCode: PDWORD;
  lpszErrorMsg: PChar; cbErrorMsgMax: WORD;
  pcbErrorMsg: PWORD): Smallint; stdcall;

  type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation


{$R *.DFM}

function SQLConfigDataSource; external 'ODBCCP32.DLL';
function SQLInstallerError; external 'ODBCCP32.DLL';

procedure TForm1.Button1Click(Sender: TObject);
var
  attr: string;
  pfErrorCode: DWORD;
  errMsg: PChar;
begin
  //Tilføj DSN
  attr := 'DSN=TEST'#0 + 'Description=Test database'#0 + 'SERVER=DBSERVER'#0 +
          'DATABASE=Test'#0;
  If not SQLConfigDataSource(0, ODBC_ADD_DSN, 'SQL Server', PChar(attr)) Then begin
    errMsg := AllocMem(SQL_MAX_MESSAGE_LENGTH);
    SQLInstallerError(1, @pfErrorCode, errMsg, SQL_MAX_MESSAGE_LENGTH, nil);
    MessageBox(0, errMsg, PChar('Create System DSN Error #' + IntToStr(pfErrorCode)), 0);
    FreeMem(errMsg);
  end
  Else
    Showmessage('Done');
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  attr: string;
  pfErrorCode: DWORD;
  errMsg: PChar;
begin
  //Slet DSN
  attr := 'DSN=TEST'#0;
  If not SQLConfigDataSource(0, ODBC_REMOVE_DSN, 'SQL Server', PChar(attr)) Then begin
    errMsg := AllocMem(SQL_MAX_MESSAGE_LENGTH);
    SQLInstallerError(1, @pfErrorCode, errMsg, SQL_MAX_MESSAGE_LENGTH, nil);
    MessageBox(0, errMsg, PChar('Delete System DSN Error #' + IntToStr(pfErrorCode)), 0);
    FreeMem(errMsg);
  end
  Else
    Showmessage('Done');
end;

end.
<--Kode slut-->

Mit eneste problem er at jeg ikke kan få angivet et brugernavn og password som jeg vil bruge til min ODBC forbindelse. Man skulle tro det bare var at tilføje en UID og PWD parameter, men ud fra Microsoft'es specifikation (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbcsql/od_odbc_c_99yd.asp) så understøttes de parametre netop ikke, og det virker da heller ikke hvis man prøver ;) Bemærk at det er en SQL Server jeg skal lave en ODBC forbindelse til - ved brug af Access kan man nemlig vist godt bruge UID og PWD parametrene.

Jeg har fundet masser af eksempler, men ikke nogen som virker med ovenstående. Det må da kunne lade sig gøre på én eller anden måde (evt. via andre funktioner/metoder) at angive et brugernavn og password!?

På forhånd tak.
Avatar billede stoney Nybegynder
20. december 2004 - 12:44 #1
gammel kodestump jeg har på lager.
Ikke testet

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
  SQLRETURN = SMALLINT;

  const
    ODBCVER=$0351; // Assume ODBC 3.51 DENNE LINIE ER OVERFLØDIG
  const
    ODBC_ADD_DSN = 1; // Add data source
    ODBC_CONFIG_DSN = 2; // Configure (edit) data source
    ODBC_REMOVE_DSN = 3; // Remove data source
    ODBC_ADD_SYS_DSN = 4; // add a system DSN
    ODBC_CONFIG_SYS_DSN = 5; // Configure a system DSN
    ODBC_REMOVE_SYS_DSN = 6; // remove a system DSN
    ODBC_REMOVE_DEFAULT_DSN = 7; // remove the default DSN
  function SQLConfigDataSource (hwndParent : HWND;
                                  fRequest : WORD;
                                  lpszDriver : LPCSTR;
                                lpszAttributes :
LPCSTR):SQLRETURN;stdcall;
  const
    ODBCCP32='ODBCCP32.DLL';

var
  Form1: TForm1;

implementation
{$R *.DFM}
function SQLConfigDataSource ; external ODBCCP32 name 'SQLConfigDataSource';

procedure TForm1.Button1Click(Sender: TObject);
var
  szDriver : LPCSTR;
  szAttributes : LPCSTR;
begin
  szDriver:= 'SQL Server';
  szAttributes
:='DSN=xxx'#0'Trusted_Connection=No'#0'DESCRIPTION=xxx'#0'SERVER=xxx'#0'uid=
xxxx'#0'pwd=xxxx'#0'NETWORK=DBNMPNTW'#0'DATABASE=xxx'+#0#0;
  {
    DSN=xxx : xxx is dsn name.
    Trusted_Connection=No uses SQL Server authentication.
    SERVER=xxx xxx is SQL Server name .
    uid=xxx : xxx is user name.
    pwd=xxx : xxx is user password.
    NETWORK=DBNMPNTW use named pipes to connect to SQL Server.
    DATABASE=xxx: xxx is database name.
  }
  SQLConfigDataSource(0,ODBC_ADD_SYS_DSN,szDriver,szAttributes);
end;

Stoney
Avatar billede snowball Novice
20. december 2004 - 12:50 #2
stoney: Det virker desværre ikke.
Avatar billede nop Nybegynder
21. december 2004 - 13:02 #3
Du skal ikke opgive user/password når du laver en ODBC. Bare opret den og når du så åbner en connection så angiv uid og password i selve åben metode.
Jeg gør det sådan:

function SQLConfigDataSource (hwndParent: hwnd;
                              fRequest: integer;
                              lpszDriver: String;
                              lpszAttributes: String): integer;
    stdcall;
    external 'ODBCCP32.DLL' name 'SQLConfigDataSource';

function makeSysDsn(name: string; driver: string; attr: string): boolean;
// laver en dsn med opsæt driver/parm
// returnerer true hvis ok
var
    driverP,attrP:    string;
    s:              string;
    i,j:            integer;
    ret:            integer;

    procedure replaceChar(var s: string; const c,cr: char);
    var
        i:    integer;
    begin
        for i:=1 to length(s) do
            if s[i]=c then s[i]:=cr;
    end; // replace Char

begin //make sys dsn
    driverP:=driver+#0;
    attrP:='DSN='+name+#0+attr+#0#0;
    replaceChar(attrP,';',#0);
    ret:=SQLconfigDataSource(0,odbc_add_sys_dsn,driverP,attrP);
    result:=ret=1;
end; // ODBC make sys dsn

fx makeSysDSN('myOdbc','sql','trusted_connection=yes;delphi=1'); //eksempler bare

og brug:

s:='Data source=myOdbc';
connection:=TadoConnection.create;
connection.ConnectionString:=s;
connection.Open('nop','hejhej'); //
connected:=true;

Det er taget ud af en helhed så der kan være småting, men jeg ved det virker!

--nop
Avatar billede nop Nybegynder
21. december 2004 - 13:12 #4
Det skal selvfølgelig være 'sql server':
makeSysDNS('myODBC','sql server','x=222');

Man kan også lave en ODBC ved direkte at skrive i registry har jeg læst, men ikke selv prøvet, men jeg læser i registry for at læse en ODBC op, men for at bruge den på en anden workstation i nettet er det nødvendigt at klippe lidt i parameterene.

Læs:
procedure getODBCinfoString(const dsn: string;
                            var driverName: string;
                            var str: string);
var
    reg:    Tregistry;
    nl:    TStringList;
    i:      integer;
begin
    driverName:='';
    str:='';
    reg:= TRegistry.Create;
    reg.RootKey:= HKEY_LOCAL_MACHINE;
    if reg.OpenKeyReadOnly('SOFTWARE\ODBC\ODBC.INI\'+dsn) then begin
        nl:=TStringList.Create;
        reg.GetValueNames(nl);
        for i:=0 to nl.Count-1 do begin
            case reg.GetDataType(nl[i]) of
                rdUnknown:  ;//'<unknown type>';
                rdString:  str:=str+nl[i]+'='+reg.ReadString(nl[i])+';';
                rdInteger:  str:=str+nl[i]+'='+IntToStr(reg.ReadInteger(nl[i]))+';';
                rdExpandString: ;//'<expand string>';
                rdBinary:  ;//'<binary>';
            end;
        end;
        nl.Free;
        if copy(str,length(str),1)=';' then
            Delete(str,length(str),1);
        reg.CloseKey;
        if reg.OpenKeyReadOnly('SOFTWARE\ODBC\ODBC.INI\ODBC Data Sources')
        then begin
            driverName:=reg.ReadString(dsn);
            reg.CloseKey;
        end;
    end;
    reg.Free;
end; //get odbc info string

makeSysDSN (som den rigtig var):

function makeSysDsn(name: string; driver: string; attr: string): boolean;
// laver en dsn med opsæt driver/parm
// returnerer true hvis ok
var
    driverP,attrP:    string;
    s:              string;
    i,j:            integer;
    ret:            integer;

    procedure replaceChar(var s: string; const c,cr: char);
    var
        i:    integer;
    begin
        for i:=1 to length(s) do
            if s[i]=c then s[i]:=cr;
    end; // replace Char

    function inString(const subStr: string; const str: string; start: integer): integer;
    begin
        if start <= length(str) then begin
            result:=pos(subStr,copy(str,start,length(str)-start+1));
            if result<>0 then result:=result+start-1;
        end else
            result:=0;
    end; //inString

begin //make sys dsn
    driverP:=driver+#0;
    s:=lowercase(attr);
    i:=pos('driver=',s);
    if i<>0 then begin
        j:=inString(';',s,i);
        if j=0 then j:=length(s);
        delete(attr,i,j-i+1);
        delete(s,i,j-i+1);
    end;
    i:=pos('lastuser=',s);
    if i<>0 then begin
        j:=inString(';',s,i);
        if j=0 then j:=length(s);
        delete(attr,i,j-i+1);
    end;
    attrP:='DSN='+name+#0+attr+#0#0;
    replaceChar(attrP,';',#0);
    ret:=SQLconfigDataSource(0,odbc_add_sys_dsn,driverP,attrP);
    result:=ret=1;
end; // ODBC make sys dsn

Det hele vil fungerer i forbindelse med MSSQL. Og vil nemt kunne laves om til hvad som helst.
Avatar billede snowball Novice
21. december 2004 - 13:22 #5
nop: Mit program skal kun håndtere ODBC data kilderne - ikke bruge dem som sådan.

Problemet er at jeg på flere hundrede PC'er har et program installeret (som jeg ikke har nogen kontrol over!) som benytter sig af en ODBC data kilde. Nu har vi så fået en ny SQL server og den har et andet navn. Jeg skal derfor have rettet server navnet i ODBC'en på de mange PC'ere. I stedet for at gøre det manuelt, så ville jeg lave et lille program som gør arbejdet for mig.

Det er bare slet ikke så let som jeg håbede på det ville være, for brugernavn og password informationer gemmes i dette tilfælde åbenbart ikke så det er sådan lige til at rette i. Jeg har prøvet bare at ændre selve server navnet både via reg.DB'en og SQLConfigDataSource, men lige så snart man laver noget med data kilden, så bliver password feltet af en eller anden årsag nulstillet så data kilden bliver ubrugelig.
Avatar billede nop Nybegynder
21. december 2004 - 13:54 #6
Det her kode er osse fra et program der selv opretter odbc'en udfra info givet fra et server program der læser en odbc op. Jeg tog kun det med brugen med for det er normalt her at bruger/password sættes.
Men hvis user/password ligger i ODBC'en som et parameter så kan du osse læse det bare vha. regedit. Men der kan jo både være checksum og kryptering som behandles i den driver dine pc'ere bruger. Så kræver det at du ved præcis hvordan man bygger den ODBC.
Kan du ikke prøve at rette ODBC'en vha. regedit? Hvis password stadig nulstilles (efter programmet bliver kørt!) så er det checksum på.
Avatar billede snowball Novice
22. december 2004 - 08:34 #7
I anden omgang virkede det ved at redigere server navnet direkte i regedit. Det havde jeg ellers prøvet tidligere, som jeg også skrev, uden at det virkede, så jeg ved ikke lige hvad der gik galt først gang ;)

Lav et svar, så deles pointene.
Avatar billede snowball Novice
06. januar 2005 - 10:08 #8
Ingen der vil have point!? ;)
Avatar billede snowball Novice
11. januar 2005 - 13:36 #9
Åbenbart ikke!
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester